2019-04-01 22:46:33 +02:00
/*
KLayout Layout Viewer
2025-01-04 19:28:56 +01:00
Copyright (C) 2006-2025 Matthias Koefferlein
2019-04-01 22:46:33 +02:00
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, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "dbNetlistSpiceReader.h"
2023-02-22 09:48:08 +01:00
#include "dbNetlistSpiceReaderDelegate.h"
2023-02-22 13:11:30 +01:00
#include "dbNetlistSpiceReaderExpressionParser.h"
2019-04-01 22:46:33 +02:00
#include "dbNetlist.h"
#include "dbNetlistDeviceClasses.h"
#include "tlUnitTest.h"
#include "tlStream.h"
#include "tlFileUtils.h"
TEST ( 1 _BasicReader )
{
db :: Netlist nl ;
2021-05-01 21:36:52 +02:00
std :: string path = tl :: combine_path ( tl :: combine_path ( tl :: testdata (), "algo" ), "nreader1.cir" );
2019-04-01 22:46:33 +02:00
db :: NetlistSpiceReader reader ;
tl :: InputStream is ( path );
reader . read ( is , nl );
EXPECT_EQ ( nl . to_string (),
2019-07-12 19:00:27 +02:00
"circuit TOP ('1'='1','2'='2','4'='4','7'='7'); \n "
2019-06-15 18:22:04 +02:00
" device RES $1 (A='6',B='1') (R=7650,L=0,W=0,A=0,P=0); \n "
" device RES $2 (A='3',B='1') (R=7650,L=0,W=0,A=0,P=0); \n "
" device RES $3 (A='3',B='2') (R=2670,L=0,W=0,A=0,P=0); \n "
2019-04-07 11:09:08 +02:00
" device MHVPMOS $4 (S='6',G='4',D='7',B='7') (L=0.25,W=1.5,AS=0.63,AD=0.63,PS=3.84,PD=3.84); \n "
2019-04-01 22:46:33 +02:00
"end; \n "
);
}
2020-04-01 23:19:13 +02:00
TEST ( 1 b_BasicReader_ResistorModels )
{
db :: Netlist nl ;
2021-05-01 21:36:52 +02:00
std :: string path = tl :: combine_path ( tl :: combine_path ( tl :: testdata (), "algo" ), "nreader1b.cir" );
2020-04-01 23:19:13 +02:00
db :: NetlistSpiceReader reader ;
tl :: InputStream is ( path );
reader . read ( is , nl );
EXPECT_EQ ( nl . to_string (),
"circuit TOP ('1'='1','2'='2','4'='4','7'='7'); \n "
" device M1 $1 (A='6',B='1') (R=7650,L=0,W=0,A=0,P=0); \n "
" device M2 $2 (A='3',B='1') (R=7650,L=0,W=0,A=0,P=0); \n "
" device M3 $3 (A='3',B='2') (R=2670,L=0,W=0,A=0,P=0); \n "
" device MHVPMOS $4 (S='6',G='4',D='7',B='7') (L=0.25,W=1.5,AS=0.63,AD=0.63,PS=3.84,PD=3.84); \n "
"end; \n "
);
}
2019-04-01 22:46:33 +02:00
TEST ( 2 _ReaderWithSubcircuits )
{
db :: Netlist nl ;
2021-05-01 21:36:52 +02:00
std :: string path = tl :: combine_path ( tl :: combine_path ( tl :: testdata (), "algo" ), "nreader2.cir" );
2019-04-01 22:46:33 +02:00
db :: NetlistSpiceReader reader ;
tl :: InputStream is ( path );
reader . read ( is , nl );
EXPECT_EQ ( nl . to_string (),
2019-07-12 19:00:27 +02:00
"circuit RINGO ('11'='11','12'='12','13'='13','14'='14','15'='15'); \n "
" subcircuit ND2X1 $1 ('1'='12','2'='1','3'='15','4'='12','5'='11','6'='14','7'='15'); \n "
" subcircuit INVX1 $2 ('1'='12','2'='2','3'='15','4'='12','5'='1','6'='15'); \n "
" subcircuit INVX1 $3 ('1'='12','2'='3','3'='15','4'='12','5'='2','6'='15'); \n "
" subcircuit INVX1 $4 ('1'='12','2'='4','3'='15','4'='12','5'='3','6'='15'); \n "
" subcircuit INVX1 $5 ('1'='12','2'='5','3'='15','4'='12','5'='4','6'='15'); \n "
" subcircuit INVX1 $6 ('1'='12','2'='6','3'='15','4'='12','5'='5','6'='15'); \n "
" subcircuit INVX1 $7 ('1'='12','2'='7','3'='15','4'='12','5'='6','6'='15'); \n "
" subcircuit INVX1 $8 ('1'='12','2'='8','3'='15','4'='12','5'='7','6'='15'); \n "
" subcircuit INVX1 $9 ('1'='12','2'='9','3'='15','4'='12','5'='8','6'='15'); \n "
" subcircuit INVX1 $10 ('1'='12','2'='10','3'='15','4'='12','5'='9','6'='15'); \n "
" subcircuit INVX1 $11 ('1'='12','2'='11','3'='15','4'='12','5'='10','6'='15'); \n "
" subcircuit INVX1 $12 ('1'='12','2'='13','3'='15','4'='12','5'='11','6'='15'); \n "
2019-04-01 22:46:33 +02:00
"end; \n "
2019-07-12 19:00:27 +02:00
"circuit ND2X1 ('1'='1','2'='2','3'='3','4'='4','5'='5','6'='6','7'='7'); \n "
2019-04-07 11:09:08 +02:00
" device MLVPMOS $1 (S='2',G='6',D='1',B='4') (L=0.25,W=1.5,AS=0.6375,AD=0.3375,PS=3.85,PD=1.95); \n "
" device MLVPMOS $2 (S='1',G='5',D='2',B='4') (L=0.25,W=1.5,AS=0.3375,AD=0.6375,PS=1.95,PD=3.85); \n "
" device MLVNMOS $3 (S='3',G='6',D='8',B='7') (L=0.25,W=0.95,AS=0.40375,AD=0.21375,PS=2.75,PD=1.4); \n "
" device MLVNMOS $4 (S='8',G='5',D='2',B='7') (L=0.25,W=0.95,AS=0.21375,AD=0.40375,PS=1.4,PD=2.75); \n "
2019-04-01 22:46:33 +02:00
"end; \n "
2019-07-12 19:00:27 +02:00
"circuit INVX1 ('1'='1','2'='2','3'='3','4'='4','5'='5','6'='6'); \n "
2019-04-07 11:09:08 +02:00
" device MLVPMOS $1 (S='1',G='5',D='2',B='4') (L=0.25,W=1.5,AS=0.6375,AD=0.6375,PS=3.85,PD=3.85); \n "
" device MLVNMOS $2 (S='3',G='5',D='2',B='6') (L=0.25,W=0.95,AS=0.40375,AD=0.40375,PS=2.75,PD=2.75); \n "
2019-04-01 22:46:33 +02:00
"end; \n "
);
}
TEST ( 3 _ReaderWithSubcircuitsAltOrder )
{
db :: Netlist nl ;
2021-05-01 21:36:52 +02:00
std :: string path = tl :: combine_path ( tl :: combine_path ( tl :: testdata (), "algo" ), "nreader3.cir" );
2019-04-01 22:46:33 +02:00
db :: NetlistSpiceReader reader ;
tl :: InputStream is ( path );
reader . read ( is , nl );
EXPECT_EQ ( nl . to_string (),
2019-07-12 19:00:27 +02:00
"circuit INVX1 ('1'='1','2'='2','3'='3','4'='4','5'='5','6'='6'); \n "
2019-04-07 11:09:08 +02:00
" device MLVPMOS $1 (S='1',G='5',D='2',B='4') (L=0.25,W=1.5,AS=0,AD=0,PS=0,PD=0); \n "
" device MLVNMOS $2 (S='3',G='5',D='2',B='6') (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0); \n "
2019-04-01 22:46:33 +02:00
"end; \n "
2019-07-12 19:00:27 +02:00
"circuit ND2X1 ('1'='1','2'='2','3'='3','4'='4','5'='5','6'='6','7'='7'); \n "
2019-04-07 11:09:08 +02:00
" device MLVPMOS $1 (S='2',G='6',D='1',B='4') (L=0.25,W=1.5,AS=0,AD=0,PS=0,PD=0); \n "
" device MLVPMOS $2 (S='1',G='5',D='2',B='4') (L=0.25,W=1.5,AS=0,AD=0,PS=0,PD=0); \n "
" device MLVNMOS $3 (S='3',G='6',D='8',B='7') (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0); \n "
" device MLVNMOS $4 (S='8',G='5',D='2',B='7') (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0); \n "
2019-04-01 22:46:33 +02:00
"end; \n "
2019-07-12 19:00:27 +02:00
"circuit RINGO ('11'='11','12'='12','13'='13','14'='14','15'='15'); \n "
" subcircuit ND2X1 $1 ('1'='12','2'='1','3'='15','4'='12','5'='11','6'='14','7'='15'); \n "
" subcircuit INVX1 $2 ('1'='12','2'='2','3'='15','4'='12','5'='1','6'='15'); \n "
" subcircuit INVX1 $3 ('1'='12','2'='3','3'='15','4'='12','5'='2','6'='15'); \n "
" subcircuit INVX1 $4 ('1'='12','2'='4','3'='15','4'='12','5'='3','6'='15'); \n "
" subcircuit INVX1 $5 ('1'='12','2'='5','3'='15','4'='12','5'='4','6'='15'); \n "
" subcircuit INVX1 $6 ('1'='12','2'='6','3'='15','4'='12','5'='5','6'='15'); \n "
" subcircuit INVX1 $7 ('1'='12','2'='7','3'='15','4'='12','5'='6','6'='15'); \n "
" subcircuit INVX1 $8 ('1'='12','2'='8','3'='15','4'='12','5'='7','6'='15'); \n "
" subcircuit INVX1 $9 ('1'='12','2'='9','3'='15','4'='12','5'='8','6'='15'); \n "
" subcircuit INVX1 $10 ('1'='12','2'='10','3'='15','4'='12','5'='9','6'='15'); \n "
" subcircuit INVX1 $11 ('1'='12','2'='11','3'='15','4'='12','5'='10','6'='15'); \n "
" subcircuit INVX1 $12 ('1'='12','2'='13','3'='15','4'='12','5'='11','6'='15'); \n "
2019-04-01 22:46:33 +02:00
"end; \n "
);
}
2019-05-19 22:55:03 +02:00
TEST ( 4 _ReaderWithUnconnectedPins )
{
db :: Netlist nl ;
2021-05-01 21:36:52 +02:00
std :: string path = tl :: combine_path ( tl :: combine_path ( tl :: testdata (), "algo" ), "nreader4.cir" );
2019-05-19 22:55:03 +02:00
db :: NetlistSpiceReader reader ;
tl :: InputStream is ( path );
reader . read ( is , nl );
EXPECT_EQ ( nl . to_string (),
2019-07-12 19:00:27 +02:00
"circuit RINGO ('1'='1','2'='2','3'='3','4'='4'); \n "
" subcircuit INV2PAIR $1 ('1'='4','2'='3','3'='4','4'='1','5'='6','6'='2','7'='3'); \n "
2019-08-29 23:26:03 +02:00
" subcircuit INV2PAIR $2 ('1'='4','2'='3','3'='4','4'='100','5'='1','6'='5','7'='3'); \n "
" subcircuit INV2PAIR $3 ('1'='4','2'='3','3'='4','4'='101','5'='5','6'='8','7'='3'); \n "
" subcircuit INV2PAIR $4 ('1'='4','2'='3','3'='4','4'='102','5'='8','6'='7','7'='3'); \n "
" subcircuit INV2PAIR $5 ('1'='4','2'='3','3'='4','4'='103','5'='7','6'='6','7'='3'); \n "
2019-05-19 22:55:03 +02:00
"end; \n "
2019-07-12 19:00:27 +02:00
"circuit INV2PAIR ('1'='1','2'='2','3'='3','4'='4','5'='5','6'='6','7'='7'); \n "
" subcircuit INV2 $1 ('1'='7','2'='5','3'='4','4'='3','5'='2','6'='1'); \n "
" subcircuit INV2 $2 ('1'='7','2'='4','3'='6','4'='3','5'='2','6'='1'); \n "
2019-05-19 22:55:03 +02:00
"end; \n "
2019-07-12 19:00:27 +02:00
"circuit INV2 ('1'='1','2'='2','3'='3','4'='4','5'='5','6'='6'); \n "
2023-02-27 00:19:14 +01:00
" device PMOS $1 (S='5',G='2',D='3',B='1') (L=0.25,W=3.5,AS=1.4,AD=1.4,PS=6.85,PD=6.85); \n "
" device NMOS $3 (S='4',G='2',D='3',B='6') (L=0.25,W=3.5,AS=1.4,AD=1.4,PS=6.85,PD=6.85); \n "
2019-05-19 22:55:03 +02:00
"end; \n "
);
}
2019-05-31 22:55:09 +02:00
TEST ( 5 _CircuitParameters )
{
2021-05-01 21:36:52 +02:00
std :: string path = tl :: combine_path ( tl :: combine_path ( tl :: testdata (), "algo" ), "nreader5.cir" );
2019-05-31 22:55:09 +02:00
db :: NetlistSpiceReader reader ;
2023-02-22 13:11:30 +01:00
reader . set_strict ( true );
try {
db :: Netlist nl ;
tl :: InputStream is ( path );
reader . read ( is , nl );
// strict mode makes this sample fail
EXPECT_EQ ( true , false );
} catch (...) {
// ..
}
db :: Netlist nl ;
reader . set_strict ( false );
2019-05-31 22:55:09 +02:00
tl :: InputStream is ( path );
reader . read ( is , nl );
EXPECT_EQ ( nl . to_string (),
2019-07-13 08:50:13 +02:00
"circuit SUBCKT ($1=$1,'A[5]<1>'='A[5]<1>','V42(%)'='V42(%)',Z=Z,GND=GND,GND$1=GND$1); \n "
2024-04-15 00:01:49 +02:00
" subcircuit 'HVPMOS(AD=0.18,AS=0.18,L=0.2,PD=2.16,PS=2.16,W=1)' D_$1 ('1'='V42(%)','2'=$3,'3'=Z,'4'=$1); \n "
" subcircuit 'HVPMOS(AD=0.18,AS=0.18,L=0.2,PD=2.16,PS=2.16,W=1)' D_$2 ('1'='V42(%)','2'='A[5]<1>','3'=$3,'4'=$1); \n "
" subcircuit 'HVNMOS(AD=0,AS=0,L=1.13,PD=6,PS=6,W=2.12)' D_$3 ('1'=GND,'2'=$3,'3'=GND,'4'=GND$1); \n "
" subcircuit 'HVNMOS(AD=0.19,AS=0.19,L=0.4,PD=1.16,PS=1.16,W=0.4)' D_$4 ('1'=GND,'2'=$3,'3'=Z,'4'=GND$1); \n "
" subcircuit 'HVNMOS(AD=0.19,AS=0.19,L=0.4,PD=1.76,PS=1.76,W=0.4)' D_$5 ('1'=GND,'2'='A[5]<1>','3'=$3,'4'=GND$1); \n "
2019-05-31 22:55:09 +02:00
"end; \n "
2024-04-15 00:01:49 +02:00
"circuit 'HVPMOS(AD=0.18,AS=0.18,L=0.2,PD=2.16,PS=2.16,W=1)' ('1'='1','2'='2','3'='3','4'='4'); \n "
2019-05-31 22:55:09 +02:00
"end; \n "
2024-04-15 00:01:49 +02:00
"circuit 'HVNMOS(AD=0,AS=0,L=1.13,PD=6,PS=6,W=2.12)' ('1'='1','2'='2','3'='3','4'='4'); \n "
2019-05-31 22:55:09 +02:00
"end; \n "
2024-04-15 00:01:49 +02:00
"circuit 'HVNMOS(AD=0.19,AS=0.19,L=0.4,PD=1.16,PS=1.16,W=0.4)' ('1'='1','2'='2','3'='3','4'='4'); \n "
2023-02-21 00:49:23 +01:00
"end; \n "
2024-04-15 00:01:49 +02:00
"circuit 'HVNMOS(AD=0.19,AS=0.19,L=0.4,PD=1.76,PS=1.76,W=0.4)' ('1'='1','2'='2','3'='3','4'='4'); \n "
2019-05-31 22:55:09 +02:00
"end; \n "
);
}
2019-06-22 19:44:33 +02:00
class MyNetlistReaderDelegate
: public db :: NetlistSpiceReaderDelegate
{
public :
MyNetlistReaderDelegate () : db :: NetlistSpiceReaderDelegate () { }
bool wants_subcircuit ( const std :: string & circuit_name )
{
return circuit_name == "HVNMOS" || circuit_name == "HVPMOS" ;
}
2023-02-22 10:15:05 +01:00
bool element ( db :: Circuit * circuit , const std :: string & element , const std :: string & name , const std :: string & model , double value , const std :: vector < db :: Net *> & nets , const std :: map < std :: string , tl :: Variant > & params )
2019-06-22 19:44:33 +02:00
{
if ( element == "X" ) {
if ( nets . size () != 4 ) {
error ( tl :: sprintf ( "Device subcircuit '%s' requires four nets" , model ));
}
db :: DeviceClass * cls = circuit -> netlist () -> device_class_by_name ( model );
if ( ! cls ) {
cls = new db :: DeviceClassMOS4Transistor ();
cls -> set_name ( model );
circuit -> netlist () -> add_device_class ( cls );
}
db :: Device * device = new db :: Device ( cls );
device -> set_name ( name );
circuit -> add_device ( device );
device -> connect_terminal ( db :: DeviceClassMOS4Transistor :: terminal_id_S , nets [ 0 ]);
device -> connect_terminal ( db :: DeviceClassMOS4Transistor :: terminal_id_G , nets [ 1 ]);
device -> connect_terminal ( db :: DeviceClassMOS4Transistor :: terminal_id_D , nets [ 2 ]);
device -> connect_terminal ( db :: DeviceClassMOS4Transistor :: terminal_id_B , nets [ 3 ]);
const std :: vector < db :: DeviceParameterDefinition > & td = cls -> parameter_definitions ();
for ( std :: vector < db :: DeviceParameterDefinition >:: const_iterator i = td . begin (); i != td . end (); ++ i ) {
2023-02-22 10:15:05 +01:00
auto pi = params . find ( i -> name ());
2019-06-22 19:44:33 +02:00
if ( pi != params . end ()) {
2023-02-22 10:15:05 +01:00
device -> set_parameter_value ( i -> id (), pi -> second . to_double () * 1.5 );
2019-06-22 19:44:33 +02:00
}
}
return true ;
} else {
return db :: NetlistSpiceReaderDelegate :: element ( circuit , element , name , model , value , nets , params );
}
}
};
TEST ( 6 _ReaderWithDelegate )
{
db :: Netlist nl ;
2021-05-01 21:36:52 +02:00
std :: string path = tl :: combine_path ( tl :: combine_path ( tl :: testdata (), "algo" ), "nreader6.cir" );
2019-06-22 19:44:33 +02:00
MyNetlistReaderDelegate delegate ;
db :: NetlistSpiceReader reader ( & delegate );
tl :: InputStream is ( path );
reader . read ( is , nl );
EXPECT_EQ ( nl . to_string (),
2023-02-21 00:49:23 +01:00
"circuit .TOP (); \n "
" subcircuit SUBCKT SUBCKT ($1=IN,A=OUT,VDD=VDD,Z=Z,GND=VSS,GND$1=VSS); \n "
"end; \n "
2019-07-12 19:00:27 +02:00
"circuit SUBCKT ($1=$1,A=A,VDD=VDD,Z=Z,GND=GND,GND$1=GND$1); \n "
2019-06-22 19:44:33 +02:00
" device HVPMOS $1 (S=VDD,G=$3,D=Z,B=$1) (L=0.3,W=1.5,AS=0.27,AD=0.27,PS=3.24,PD=3.24); \n "
" device HVPMOS $2 (S=VDD,G=A,D=$3,B=$1) (L=0.3,W=1.5,AS=0.27,AD=0.27,PS=3.24,PD=3.24); \n "
2019-06-28 17:08:04 +02:00
" device HVNMOS $3 (S=GND,G=$3,D=GND,B=GND$1) (L=1.695,W=3.18,AS=0,AD=0,PS=9,PD=9); \n "
" device HVNMOS $4 (S=GND,G=$3,D=Z,B=GND$1) (L=0.6,W=0.6,AS=0.285,AD=0.285,PS=1.74,PD=1.74); \n "
" device HVNMOS $5 (S=GND,G=A,D=$3,B=GND$1) (L=0.6,W=0.6,AS=0.285,AD=0.285,PS=2.64,PD=2.64); \n "
2019-06-22 22:03:32 +02:00
" device RES $1 (A=A,B=Z) (R=100000,L=0,W=0,A=0,P=0); \n "
2019-06-22 19:44:33 +02:00
"end; \n "
);
}
2019-07-22 23:02:31 +02:00
TEST ( 7 _GlobalNets )
{
db :: Netlist nl ;
2021-05-01 21:36:52 +02:00
std :: string path = tl :: combine_path ( tl :: combine_path ( tl :: testdata (), "algo" ), "nreader7.cir" );
2019-07-22 23:02:31 +02:00
MyNetlistReaderDelegate delegate ;
db :: NetlistSpiceReader reader ( & delegate );
tl :: InputStream is ( path );
reader . read ( is , nl );
EXPECT_EQ ( nl . to_string (),
"circuit RINGO (FB=FB,OUT=OUT,ENABLE=ENABLE,VDD=VDD,VSS=VSS); \n "
" subcircuit ND2X1 $1 (OUT='1',B=FB,A=ENABLE,VDD=VDD,VSS=VSS); \n "
" subcircuit INVX1 $2 (OUT='2',IN='1',VDD=VDD,VSS=VSS); \n "
" subcircuit INVX1 $3 (OUT='3',IN='2',VDD=VDD,VSS=VSS); \n "
" subcircuit INVX1 $4 (OUT='4',IN='3',VDD=VDD,VSS=VSS); \n "
" subcircuit INVX1 $5 (OUT='5',IN='4',VDD=VDD,VSS=VSS); \n "
" subcircuit INVX1 $6 (OUT='6',IN='5',VDD=VDD,VSS=VSS); \n "
" subcircuit INVX1 $7 (OUT='7',IN='6',VDD=VDD,VSS=VSS); \n "
" subcircuit INVX1 $8 (OUT='8',IN='7',VDD=VDD,VSS=VSS); \n "
" subcircuit INVX1 $9 (OUT='9',IN='8',VDD=VDD,VSS=VSS); \n "
" subcircuit INVX1 $10 (OUT='10',IN='9',VDD=VDD,VSS=VSS); \n "
" subcircuit INVX1 $11 (OUT=FB,IN='10',VDD=VDD,VSS=VSS); \n "
" subcircuit INVX1 $12 (OUT=OUT,IN=FB,VDD=VDD,VSS=VSS); \n "
"end; \n "
"circuit ND2X1 (OUT=OUT,B=B,A=A,VDD=VDD,VSS=VSS); \n "
" device MLVPMOS $1 (S=OUT,G=A,D=VDD,B=VDD) (L=0.25,W=1.5,AS=0.6375,AD=0.3375,PS=3.85,PD=1.95); \n "
" device MLVPMOS $2 (S=VDD,G=B,D=OUT,B=VDD) (L=0.25,W=1.5,AS=0.3375,AD=0.6375,PS=1.95,PD=3.85); \n "
" device MLVNMOS $3 (S=VSS,G=A,D=INT,B=VSS) (L=0.25,W=0.95,AS=0.40375,AD=0.21375,PS=2.75,PD=1.4); \n "
" device MLVNMOS $4 (S=INT,G=B,D=OUT,B=VSS) (L=0.25,W=0.95,AS=0.21375,AD=0.40375,PS=1.4,PD=2.75); \n "
"end; \n "
"circuit INVX1 (OUT=OUT,IN=IN,VDD=VDD,VSS=VSS); \n "
" device MLVPMOS $1 (S=VDD,G=IN,D=OUT,B=VDD) (L=0.25,W=1.5,AS=0.6375,AD=0.6375,PS=3.85,PD=3.85); \n "
" device MLVNMOS $2 (S=VSS,G=IN,D=OUT,B=VSS) (L=0.25,W=0.95,AS=0.40375,AD=0.40375,PS=2.75,PD=2.75); \n "
"end; \n "
);
}
2019-08-19 21:45:40 +02:00
TEST ( 8 _Include )
{
db :: Netlist nl ;
2021-05-01 21:36:52 +02:00
std :: string path = tl :: combine_path ( tl :: combine_path ( tl :: testdata (), "algo" ), "nreader8.cir" );
2019-08-19 21:45:40 +02:00
db :: NetlistSpiceReader reader ;
tl :: InputStream is ( path );
reader . read ( is , nl );
EXPECT_EQ ( nl . to_string (),
"circuit INVX1 ('1'='1','2'='2','3'='3','4'='4','5'='5','6'='6'); \n "
" device MLVPMOS $1 (S='1',G='5',D='2',B='4') (L=0.25,W=1.5,AS=0,AD=0,PS=0,PD=0); \n "
" device MLVNMOS $2 (S='3',G='5',D='2',B='6') (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0); \n "
"end; \n "
"circuit ND2X1 ('1'='1','2'='2','3'='3','4'='4','5'='5','6'='6','7'='7'); \n "
" device MLVPMOS $1 (S='2',G='6',D='1',B='4') (L=0.25,W=1.5,AS=0,AD=0,PS=0,PD=0); \n "
" device MLVPMOS $2 (S='1',G='5',D='2',B='4') (L=0.25,W=1.5,AS=0,AD=0,PS=0,PD=0); \n "
" device MLVNMOS $3 (S='3',G='6',D='8',B='7') (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0); \n "
" device MLVNMOS $4 (S='8',G='5',D='2',B='7') (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0); \n "
"end; \n "
"circuit RINGO ('11'='11','12'='12','13'='13','14'='14','15'='15'); \n "
" subcircuit ND2X1 $1 ('1'='12','2'='1','3'='15','4'='12','5'='11','6'='14','7'='15'); \n "
" subcircuit INVX1 $2 ('1'='12','2'='2','3'='15','4'='12','5'='1','6'='15'); \n "
" subcircuit INVX1 $3 ('1'='12','2'='3','3'='15','4'='12','5'='2','6'='15'); \n "
" subcircuit INVX1 $4 ('1'='12','2'='4','3'='15','4'='12','5'='3','6'='15'); \n "
" subcircuit INVX1 $5 ('1'='12','2'='5','3'='15','4'='12','5'='4','6'='15'); \n "
" subcircuit INVX1 $6 ('1'='12','2'='6','3'='15','4'='12','5'='5','6'='15'); \n "
" subcircuit INVX1 $7 ('1'='12','2'='7','3'='15','4'='12','5'='6','6'='15'); \n "
" subcircuit INVX1 $8 ('1'='12','2'='8','3'='15','4'='12','5'='7','6'='15'); \n "
" subcircuit INVX1 $9 ('1'='12','2'='9','3'='15','4'='12','5'='8','6'='15'); \n "
" subcircuit INVX1 $10 ('1'='12','2'='10','3'='15','4'='12','5'='9','6'='15'); \n "
" subcircuit INVX1 $11 ('1'='12','2'='11','3'='15','4'='12','5'='10','6'='15'); \n "
" subcircuit INVX1 $12 ('1'='12','2'='13','3'='15','4'='12','5'='11','6'='15'); \n "
"end; \n "
);
}
2019-08-19 22:51:22 +02:00
TEST ( 9 _DeviceMultipliers )
{
db :: Netlist nl ;
2021-05-01 21:36:52 +02:00
std :: string path = tl :: combine_path ( tl :: combine_path ( tl :: testdata (), "algo" ), "nreader9.cir" );
2019-08-19 22:51:22 +02:00
2020-10-10 23:16:02 +02:00
{
db :: NetlistSpiceReader reader ;
tl :: InputStream is ( path );
reader . read ( is , nl );
std :: string nl_string = nl . to_string ();
// normalization of exponential representation:
nl_string = tl :: replaced ( nl_string , "e-009" , "e-09" );
EXPECT_EQ ( nl_string ,
"circuit .TOP (); \n "
" device RES $1 (A='1',B='2') (R=850,L=0,W=0,A=0,P=0); \n "
" device RES $2 (A='3',B='4') (R=1700,L=0,W=0,A=0,P=0); \n "
" device RMODEL $3 (A='1',B='2') (R=850,L=0,W=0,A=0,P=0); \n "
" device RMODEL $4 (A='3',B='4') (R=1700,L=0,W=0,A=0,P=0); \n "
2021-05-13 21:13:41 +02:00
" device RMODEL $5 (A='3',B='4') (R=1700,L=0,W=0,A=0,P=0); \n "
" device RMODEL2 $6 (A='3',B='4',W='5') (R=1700,L=0,W=0,A=0,P=0); \n "
" device RMODEL2 $7 (A='3',B='4',W='5') (R=1700,L=0,W=0,A=0,P=0); \n "
" device RES3 $8 (A='3',B='4',W='5') (R=1700,L=0,W=0,A=0,P=0); \n "
2023-02-27 00:19:14 +01:00
" device NMOS $1 (S='3',G='2',D='1',B='4') (L=7,W=4,AS=0,AD=0,PS=0,PD=0); \n "
" device PMOS $2 (S='3',G='2',D='1',B='4') (L=7,W=2,AS=0,AD=0,PS=0,PD=0); \n "
2020-10-10 23:16:02 +02:00
" device CAP $1 (A='1',B='2') (C=2e-09,A=0,P=0); \n "
" device CAP $2 (A='3',B='4') (C=1e-09,A=0,P=0); \n "
" device CMODEL $3 (A='1',B='2') (C=2e-09,A=0,P=0); \n "
" device CMODEL $4 (A='3',B='4') (C=1e-09,A=0,P=0); \n "
2021-05-13 21:13:41 +02:00
" device CMODEL $5 (A='3',B='4') (C=1e-09,A=0,P=0); \n "
" device CMODEL2 $6 (A='3',B='4',W='5') (C=1e-09,A=0,P=0); \n "
" device CAP3 $7 (A='3',B='4',W='5') (C=1e-09,A=0,P=0); \n "
" device CMODEL2 $8 (A='3',B='4',W='5') (C=1e-09,A=0,P=0); \n "
2020-10-10 23:16:02 +02:00
" device IND $1 (A='1',B='2') (L=5e-10); \n "
" device IND $2 (A='3',B='4') (L=1e-09); \n "
" device LMODEL $3 (A='1',B='2') (L=5e-10); \n "
" device LMODEL $4 (A='3',B='4') (L=1e-09); \n "
" device DIODE $1 (A='1',C='2') (A=20,P=0); \n "
" device DIODE $2 (A='3',C='4') (A=10,P=0); \n "
" device BIP $1 (C='1',B='2',E='3',S='4') (AE=20,PE=0,AB=0,PB=0,AC=0,PC=0,NE=1); \n "
" device BIP $2 (C='1',B='2',E='3',S='4') (AE=10,PE=0,AB=0,PB=0,AC=0,PC=0,NE=1); \n "
"end; \n "
);
}
2019-08-19 22:51:22 +02:00
2020-10-10 23:16:02 +02:00
db :: Circuit * top = nl . circuit_by_name ( ".TOP" );
nl . remove_circuit ( top );
2019-08-21 23:03:24 +02:00
2020-10-10 23:16:02 +02:00
// read once again, this time with known classes (must not trigger issue-652)
{
db :: NetlistSpiceReader reader ;
tl :: InputStream is ( path );
reader . read ( is , nl );
std :: string nl_string = nl . to_string ();
// normalization of exponential representation:
nl_string = tl :: replaced ( nl_string , "e-009" , "e-09" );
EXPECT_EQ ( nl_string ,
"circuit .TOP (); \n "
" device RES $1 (A='1',B='2') (R=850,L=0,W=0,A=0,P=0); \n "
" device RES $2 (A='3',B='4') (R=1700,L=0,W=0,A=0,P=0); \n "
" device RMODEL $3 (A='1',B='2') (R=850,L=0,W=0,A=0,P=0); \n "
" device RMODEL $4 (A='3',B='4') (R=1700,L=0,W=0,A=0,P=0); \n "
2021-05-13 21:13:41 +02:00
" device RMODEL $5 (A='3',B='4') (R=1700,L=0,W=0,A=0,P=0); \n "
" device RMODEL2 $6 (A='3',B='4',W='5') (R=1700,L=0,W=0,A=0,P=0); \n "
" device RMODEL2 $7 (A='3',B='4',W='5') (R=1700,L=0,W=0,A=0,P=0); \n "
" device RES3 $8 (A='3',B='4',W='5') (R=1700,L=0,W=0,A=0,P=0); \n "
2023-02-27 00:19:14 +01:00
" device NMOS $1 (S='3',G='2',D='1',B='4') (L=7,W=4,AS=0,AD=0,PS=0,PD=0); \n "
" device PMOS $2 (S='3',G='2',D='1',B='4') (L=7,W=2,AS=0,AD=0,PS=0,PD=0); \n "
2020-10-10 23:16:02 +02:00
" device CAP $1 (A='1',B='2') (C=2e-09,A=0,P=0); \n "
" device CAP $2 (A='3',B='4') (C=1e-09,A=0,P=0); \n "
" device CMODEL $3 (A='1',B='2') (C=2e-09,A=0,P=0); \n "
" device CMODEL $4 (A='3',B='4') (C=1e-09,A=0,P=0); \n "
2021-05-13 21:13:41 +02:00
" device CMODEL $5 (A='3',B='4') (C=1e-09,A=0,P=0); \n "
" device CMODEL2 $6 (A='3',B='4',W='5') (C=1e-09,A=0,P=0); \n "
" device CAP3 $7 (A='3',B='4',W='5') (C=1e-09,A=0,P=0); \n "
" device CMODEL2 $8 (A='3',B='4',W='5') (C=1e-09,A=0,P=0); \n "
2020-10-10 23:16:02 +02:00
" device IND $1 (A='1',B='2') (L=5e-10); \n "
" device IND $2 (A='3',B='4') (L=1e-09); \n "
" device LMODEL $3 (A='1',B='2') (L=5e-10); \n "
" device LMODEL $4 (A='3',B='4') (L=1e-09); \n "
" device DIODE $1 (A='1',C='2') (A=20,P=0); \n "
" device DIODE $2 (A='3',C='4') (A=10,P=0); \n "
" device BIP $1 (C='1',B='2',E='3',S='4') (AE=20,PE=0,AB=0,PB=0,AC=0,PC=0,NE=1); \n "
" device BIP $2 (C='1',B='2',E='3',S='4') (AE=10,PE=0,AB=0,PB=0,AC=0,PC=0,NE=1); \n "
"end; \n "
);
}
2019-08-19 22:51:22 +02:00
}
2019-08-19 23:00:24 +02:00
TEST ( 10 _SubcircuitsNoPins )
{
db :: Netlist nl ;
2021-05-01 21:36:52 +02:00
std :: string path = tl :: combine_path ( tl :: combine_path ( tl :: testdata (), "algo" ), "nreader10.cir" );
2019-08-19 23:00:24 +02:00
db :: NetlistSpiceReader reader ;
tl :: InputStream is ( path );
reader . read ( is , nl );
EXPECT_EQ ( nl . to_string (),
"circuit .TOP (); \n "
" device RES $1 (A=VDD,B=GND) (R=1000,L=0,W=0,A=0,P=0); \n "
" subcircuit FILLER_CAP '0' (VDD=VDD,GND=GND); \n "
"end; \n "
"circuit FILLER_CAP (VDD=VDD,GND=GND); \n "
" device NMOS '0' (S=GND,G=VDD,D=GND,B=GND) (L=10,W=10,AS=0,AD=0,PS=0,PD=0); \n "
"end; \n "
);
}
2019-12-07 23:39:39 +01:00
TEST ( 11 _ErrorOnCircuitRedefinition )
{
db :: Netlist nl ;
2021-05-01 21:36:52 +02:00
std :: string path = tl :: combine_path ( tl :: combine_path ( tl :: testdata (), "algo" ), "nreader11.cir" );
2019-12-07 23:39:39 +01:00
std :: string msg ;
try {
db :: NetlistSpiceReader reader ;
tl :: InputStream is ( path );
reader . read ( is , nl );
} catch ( tl :: Exception & ex ) {
msg = ex . msg ();
}
2023-04-07 00:19:10 +02:00
EXPECT_EQ ( tl :: replaced ( msg , tl :: absolute_file_path ( path ), "?" ), "Redefinition of circuit SUBCKT in ?, line 20" );
2019-12-07 23:39:39 +01:00
}
2020-04-26 16:54:13 +02:00
TEST ( 12 _IgnoreDuplicateGlobals )
{
db :: Netlist nl ;
2021-05-01 21:36:52 +02:00
std :: string path = tl :: combine_path ( tl :: combine_path ( tl :: testdata (), "algo" ), "nreader12.cir" );
2020-04-26 16:54:13 +02:00
db :: NetlistSpiceReader reader ;
tl :: InputStream is ( path );
reader . read ( is , nl );
EXPECT_EQ ( nl . to_string (),
"circuit .TOP (); \n "
" device RES $1 (A=VDD,B=GND) (R=1000,L=0,W=0,A=0,P=0); \n "
" subcircuit FILLER_CAP '0' (VDD=VDD,GND=GND); \n "
"end; \n "
"circuit FILLER_CAP (VDD=VDD,GND=GND); \n "
" device NMOS '0' (S=GND,G=VDD,D=GND,B=GND) (L=10,W=10,AS=0,AD=0,PS=0,PD=0); \n "
"end; \n "
);
}
2020-05-26 23:47:59 +02:00
TEST ( 13 _NoGlobalNetsIfNotUsed )
{
db :: Netlist nl ;
2021-05-01 21:36:52 +02:00
std :: string path = tl :: combine_path ( tl :: combine_path ( tl :: testdata (), "algo" ), "nreader13.cir" );
2020-05-26 23:47:59 +02:00
db :: NetlistSpiceReader reader ;
tl :: InputStream is ( path );
reader . read ( is , nl );
EXPECT_EQ ( nl . to_string (),
"circuit .TOP (); \n "
" device RES $1 (A=VDD,B=NC) (R=1000,L=0,W=0,A=0,P=0); \n "
" subcircuit C10 '1' (VDD=VDD,GND=GND); \n "
"end; \n "
"circuit C10 (VDD=VDD,GND=GND); \n "
" subcircuit C1 '1' (VDD=VDD,GND=GND); \n "
" subcircuit C2 '2' (); \n "
" subcircuit C3 '3' (VDD=VDD,GND=GND); \n "
" subcircuit C4 '4' (VDD=VDD,GND=GND); \n "
"end; \n "
2023-02-21 00:49:23 +01:00
"circuit C1 (VDD=VDD,GND=GND); \n "
" subcircuit FILLER_CAP '1' (VDD=VDD,GND=GND); \n "
" subcircuit DUMMY '2' (); \n "
"end; \n "
2020-05-26 23:47:59 +02:00
"circuit FILLER_CAP (VDD=VDD,GND=GND); \n "
" device NMOS '1' (S=GND,G=VDD,D=GND,B=GND) (L=10,W=10,AS=0,AD=0,PS=0,PD=0); \n "
"end; \n "
"circuit DUMMY (); \n "
" device NMOS '1' (S=A,G=A,D=A,B=B) (L=1,W=1,AS=0,AD=0,PS=0,PD=0); \n "
"end; \n "
"circuit C2 (); \n "
" subcircuit DUMMY '1' (); \n "
"end; \n "
"circuit C3 (VDD=VDD,GND=GND); \n "
" device NMOS '1' (S=GND,G=VDD,D=GND,B=GND) (L=10,W=10,AS=0,AD=0,PS=0,PD=0); \n "
" subcircuit FILLER_CAP '1' (VDD=VDD,GND=GND); \n "
"end; \n "
"circuit C4 (VDD=VDD,GND=GND); \n "
" subcircuit C1 '3' (VDD=VDD,GND=GND); \n "
"end; \n "
);
}
2021-07-02 23:31:54 +02:00
TEST ( 14 _IncludeWithError )
{
db :: Netlist nl ;
std :: string path = tl :: combine_path ( tl :: combine_path ( tl :: testdata (), "algo" ), "nreader14.cir" );
try {
db :: NetlistSpiceReader reader ;
tl :: InputStream is ( path );
reader . read ( is , nl );
EXPECT_EQ ( true , false ); // must not happen
} catch ( tl :: Exception & ex ) {
2023-04-07 00:19:10 +02:00
EXPECT_EQ ( ex . msg (), "'M' element must have four nodes in " + std :: string ( tl :: absolute_file_path ( tl :: combine_path ( tl :: combine_path ( tl :: testdata (), "algo" ), "nreader14x.cir" ))) + ", line 3" );
2021-07-02 23:31:54 +02:00
}
}
TEST ( 15 _ContinuationWithBlanks )
{
db :: Netlist nl ;
std :: string path = tl :: combine_path ( tl :: combine_path ( tl :: testdata (), "algo" ), "nreader15.cir" );
db :: NetlistSpiceReader reader ;
tl :: InputStream is ( path );
reader . read ( is , nl );
EXPECT_EQ ( nl . to_string (),
"circuit SUBCKT ($1=$1,'A[5]<1>'='A[5]<1>','V42(%)'='V42(%)',Z=Z,GND=GND,GND$1=GND$1); \n "
2024-04-15 00:01:49 +02:00
" subcircuit 'HVPMOS(AD=0.18,AS=0.18,L=0.2,PD=2.16,PS=2.16,W=1)' D_$1 ('1'='V42(%)','2'=$3,'3'=Z,'4'=$1); \n "
" subcircuit 'HVPMOS(AD=0.18,AS=0.18,L=0.2,PD=2.16,PS=2.16,W=1)' D_$2 ('1'='V42(%)','2'='A[5]<1>','3'=$3,'4'=$1); \n "
" subcircuit 'HVNMOS(AD=0,AS=0,L=1.13,PD=6,PS=6,W=2.12)' D_$3 ('1'=GND,'2'=$3,'3'=GND,'4'=GND$1); \n "
" subcircuit 'HVNMOS(AD=0.19,AS=0.19,L=0.4,PD=1.16,PS=1.16,W=0.4)' D_$4 ('1'=GND,'2'=$3,'3'=Z,'4'=GND$1); \n "
" subcircuit 'HVNMOS(AD=0.19,AS=0.19,L=0.4,PD=1.76,PS=1.76,W=0.4)' D_$5 ('1'=GND,'2'='A[5]<1>','3'=$3,'4'=GND$1); \n "
2023-02-21 00:49:23 +01:00
"end; \n "
2024-04-15 00:01:49 +02:00
"circuit 'HVPMOS(AD=0.18,AS=0.18,L=0.2,PD=2.16,PS=2.16,W=1)' ('1'='1','2'='2','3'='3','4'='4'); \n "
2023-02-21 00:49:23 +01:00
"end; \n "
2024-04-15 00:01:49 +02:00
"circuit 'HVNMOS(AD=0,AS=0,L=1.13,PD=6,PS=6,W=2.12)' ('1'='1','2'='2','3'='3','4'='4'); \n "
2021-07-02 23:31:54 +02:00
"end; \n "
2024-04-15 00:01:49 +02:00
"circuit 'HVNMOS(AD=0.19,AS=0.19,L=0.4,PD=1.16,PS=1.16,W=0.4)' ('1'='1','2'='2','3'='3','4'='4'); \n "
2021-07-02 23:31:54 +02:00
"end; \n "
2024-04-15 00:01:49 +02:00
"circuit 'HVNMOS(AD=0.19,AS=0.19,L=0.4,PD=1.76,PS=1.76,W=0.4)' ('1'='1','2'='2','3'='3','4'='4'); \n "
2021-07-02 23:31:54 +02:00
"end; \n "
);
}
2021-08-29 21:12:04 +02:00
TEST ( 16 _issue898 )
{
db :: Netlist nl ;
std :: string path = tl :: combine_path ( tl :: combine_path ( tl :: testdata (), "algo" ), "issue-898.cir" );
db :: NetlistSpiceReader reader ;
tl :: InputStream is ( path );
reader . read ( is , nl );
EXPECT_EQ ( nl . to_string (),
"circuit .TOP (); \n "
" device RES $1 (A=VDD,B=GND) (R=1000,L=0,W=0,A=0,P=0); \n "
" subcircuit FILLER_CAP '0' (VDD=VDD,GND=GND); \n "
"end; \n "
"circuit FILLER_CAP (VDD=VDD,GND=GND); \n "
" device NMOS '0' (S=GND,G=VDD,D=GND,B=GND) (L=10,W=10,AS=0,AD=0,PS=0,PD=0); \n "
"end; \n "
);
}
2023-02-22 13:11:30 +01:00
TEST ( 17 _RecursiveExpansion )
{
2023-02-26 21:31:34 +01:00
db :: Netlist nl , nl2 ;
2023-02-22 13:11:30 +01:00
2023-02-26 21:31:34 +01:00
{
std :: string path = tl :: combine_path ( tl :: combine_path ( tl :: testdata (), "algo" ), "nreader17.cir" );
2023-02-22 13:11:30 +01:00
2023-02-26 21:31:34 +01:00
db :: NetlistSpiceReader reader ;
tl :: InputStream is ( path );
reader . read ( is , nl );
}
2023-02-22 13:11:30 +01:00
EXPECT_EQ ( nl . to_string (),
"circuit .TOP (); \n "
" subcircuit 'SUB1(L=0.15,W=1.5)' SUB1A (N1=A,N2=B,N3=C); \n "
" subcircuit 'SUB1(L=0.25,W=3)' SUB1B (N1=A,N2=B,N3=C); \n "
"end; \n "
"circuit 'SUB1(L=0.15,W=1.5)' (N1=N1,N2=N2,N3=N3); \n "
" subcircuit 'SUB2(L=0.15,M=1,W=1.5)' SUB2A (N1=N1,N2=N2,N3=N3); \n "
" subcircuit 'SUB2(L=0.15,M=2,W=1.5)' SUB2B (N1=N1,N2=N2,N3=N3); \n "
"end; \n "
"circuit 'SUB2(L=0.15,M=1,W=1.5)' (N1=N1,N2=N2,N3=N3); \n "
2023-02-27 21:27:19 +01:00
" device NMOS NMOS (S=N3,G=N2,D=N1,B=N1) (L=150000,W=1500000,AS=0,AD=0,PS=0,PD=0); \n "
2023-02-22 13:11:30 +01:00
"end; \n "
"circuit 'SUB2(L=0.15,M=2,W=1.5)' (N1=N1,N2=N2,N3=N3); \n "
2023-02-27 21:27:19 +01:00
" device NMOS NMOS (S=N3,G=N2,D=N1,B=N1) (L=150000,W=3000000,AS=0,AD=0,PS=0,PD=0); \n "
2023-02-22 13:11:30 +01:00
"end; \n "
"circuit 'SUB1(L=0.25,W=3)' (N1=N1,N2=N2,N3=N3); \n "
" subcircuit 'SUB2(L=0.25,M=1,W=3)' SUB2A (N1=N1,N2=N2,N3=N3); \n "
" subcircuit 'SUB2(L=0.25,M=2,W=3)' SUB2B (N1=N1,N2=N2,N3=N3); \n "
"end; \n "
"circuit 'SUB2(L=0.25,M=1,W=3)' (N1=N1,N2=N2,N3=N3); \n "
2023-02-27 21:27:19 +01:00
" device NMOS NMOS (S=N3,G=N2,D=N1,B=N1) (L=250000,W=3000000,AS=0,AD=0,PS=0,PD=0); \n "
2023-02-22 13:11:30 +01:00
"end; \n "
"circuit 'SUB2(L=0.25,M=2,W=3)' (N1=N1,N2=N2,N3=N3); \n "
2023-02-27 21:27:19 +01:00
" device NMOS NMOS (S=N3,G=N2,D=N1,B=N1) (L=250000,W=6000000,AS=0,AD=0,PS=0,PD=0); \n "
2023-02-22 13:11:30 +01:00
"end; \n "
);
2023-02-26 21:31:34 +01:00
{
std :: string path = tl :: combine_path ( tl :: combine_path ( tl :: testdata (), "algo" ), "nreader17b.cir" );
db :: NetlistSpiceReader reader ;
tl :: InputStream is ( path );
reader . read ( is , nl2 );
}
EXPECT_EQ ( nl2 . to_string (), nl . to_string ());
2023-02-22 13:11:30 +01:00
}
TEST ( 18 _XSchemOutput )
{
db :: Netlist nl ;
std :: string path = tl :: combine_path ( tl :: combine_path ( tl :: testdata (), "algo" ), "nreader18.cir" );
db :: NetlistSpiceReader reader ;
tl :: InputStream is ( path );
reader . read ( is , nl );
EXPECT_EQ ( nl . to_string (),
"circuit .TOP (); \n "
" subcircuit 'PMOS4_STANDARD(L=0.15U,NF=4,W=1.5U)' XPMOS (D=Q,G=I,S=VDD,B=VDD); \n "
" subcircuit 'NMOS4_STANDARD(L=0.15U,NF=4,W=1.5U)' XNMOS (D=Q,G=I,S=VSS,B=VSS); \n "
" subcircuit 'NMOS4_STANDARD(L=0.15U,NF=2,W=1.5U)' XDUMMY0 (D=VSS,G=VSS,S=VSS,B=VSS); \n "
" subcircuit 'NMOS4_STANDARD(L=0.15U,NF=2,W=1.5U)' XDUMMY1 (D=VSS,G=VSS,S=VSS,B=VSS); \n "
" subcircuit 'PMOS4_STANDARD(L=0.15U,NF=2,W=1.5U)' XDUMMY2 (D=VDD,G=VDD,S=VDD,B=VDD); \n "
" subcircuit 'PMOS4_STANDARD(L=0.15U,NF=2,W=1.5U)' XDUMMY3 (D=VDD,G=VDD,S=VDD,B=VDD); \n "
"end; \n "
"circuit 'PMOS4_STANDARD(L=0.15U,NF=4,W=1.5U)' (D=D,G=G,S=S,B=B); \n "
2023-03-12 15:36:50 +01:00
" device SKY130_FD_PR__PFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=6,AS=1.305,AD=0.87,PS=10.74,PD=7.16); \n "
2023-02-22 13:11:30 +01:00
"end; \n "
"circuit 'NMOS4_STANDARD(L=0.15U,NF=4,W=1.5U)' (D=D,G=G,S=S,B=B); \n "
2023-03-12 15:36:50 +01:00
" device SKY130_FD_PR__NFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=6,AS=1.305,AD=0.87,PS=10.74,PD=7.16); \n "
2023-02-22 13:11:30 +01:00
"end; \n "
"circuit 'NMOS4_STANDARD(L=0.15U,NF=2,W=1.5U)' (D=D,G=G,S=S,B=B); \n "
2023-03-12 15:36:50 +01:00
" device SKY130_FD_PR__NFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=3,AS=0.87,AD=0.435,PS=7.16,PD=3.58); \n "
2023-02-22 13:11:30 +01:00
"end; \n "
"circuit 'PMOS4_STANDARD(L=0.15U,NF=2,W=1.5U)' (D=D,G=G,S=S,B=B); \n "
2023-03-12 15:36:50 +01:00
" device SKY130_FD_PR__PFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=3,AS=0.87,AD=0.435,PS=7.16,PD=3.58); \n "
"end; \n "
);
}
TEST ( 19 _ngspice_ref )
{
db :: Netlist nl ;
std :: string path = tl :: combine_path ( tl :: combine_path ( tl :: testdata (), "algo" ), "nreader19.cir" );
db :: NetlistSpiceReader reader ;
tl :: InputStream is ( path );
reader . read ( is , nl );
EXPECT_EQ ( nl . to_string (),
"circuit .TOP (); \n "
" subcircuit 'PMOS4_STANDARD(L=0.15,NF=4,W=1.5)' XPMOS (D=Q,G=I,S=VDD,B=VDD); \n "
" subcircuit 'NMOS4_STANDARD(L=0.15,NF=4,W=1.5)' XNMOS (D=Q,G=I,S=VSS,B=VSS); \n "
" subcircuit 'NMOS4_STANDARD(L=0.15,NF=2,W=1.5)' XDUMMY0 (D=VSS,G=VSS,S=VSS,B=VSS); \n "
" subcircuit 'NMOS4_STANDARD(L=0.15,NF=2,W=1.5)' XDUMMY1 (D=VSS,G=VSS,S=VSS,B=VSS); \n "
" subcircuit 'PMOS4_STANDARD(L=0.15,NF=2,W=1.5)' XDUMMY2 (D=VDD,G=VDD,S=VDD,B=VDD); \n "
" subcircuit 'PMOS4_STANDARD(L=0.15,NF=2,W=1.5)' XDUMMY3 (D=VDD,G=VDD,S=VDD,B=VDD); \n "
"end; \n "
"circuit 'PMOS4_STANDARD(L=0.15,NF=4,W=1.5)' (D=D,G=G,S=S,B=B); \n "
" device SKY130_FD_PR__PFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=6,AS=0.32625,AD=0.2175,PS=3.99,PD=2.66); \n "
"end; \n "
"circuit 'NMOS4_STANDARD(L=0.15,NF=4,W=1.5)' (D=D,G=G,S=S,B=B); \n "
" device SKY130_FD_PR__NFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=6,AS=0.32625,AD=0.2175,PS=3.99,PD=2.66); \n "
"end; \n "
"circuit 'NMOS4_STANDARD(L=0.15,NF=2,W=1.5)' (D=D,G=G,S=S,B=B); \n "
" device SKY130_FD_PR__NFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=3,AS=0.435,AD=0.2175,PS=4.16,PD=2.08); \n "
"end; \n "
"circuit 'PMOS4_STANDARD(L=0.15,NF=2,W=1.5)' (D=D,G=G,S=S,B=B); \n "
" device SKY130_FD_PR__PFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=3,AS=0.435,AD=0.2175,PS=4.16,PD=2.08); \n "
2023-02-22 13:11:30 +01:00
"end; \n "
2023-03-24 13:29:14 +01:00
);
}
// using parameters evaluated before inside formulas
TEST ( 19 b_ngspice_ref )
{
db :: Netlist nl ;
std :: string path = tl :: combine_path ( tl :: combine_path ( tl :: testdata (), "algo" ), "nreader19b.cir" );
db :: NetlistSpiceReader reader ;
tl :: InputStream is ( path );
reader . read ( is , nl );
EXPECT_EQ ( nl . to_string (),
"circuit .TOP (); \n "
" subcircuit 'PMOS4_STANDARD(L=0.15,NF=4,V=1.5)' XPMOS (D=Q,G=I,S=VDD,B=VDD); \n "
" subcircuit 'NMOS4_STANDARD(L=0.15,NF=4,V=1.5)' XNMOS (D=Q,G=I,S=VSS,B=VSS); \n "
" subcircuit 'NMOS4_STANDARD(L=0.15,NF=2,V=1.5)' XDUMMY0 (D=VSS,G=VSS,S=VSS,B=VSS); \n "
" subcircuit 'NMOS4_STANDARD(L=0.15,NF=2,V=1.5)' XDUMMY1 (D=VSS,G=VSS,S=VSS,B=VSS); \n "
" subcircuit 'PMOS4_STANDARD(L=0.15,NF=2,V=1.5)' XDUMMY2 (D=VDD,G=VDD,S=VDD,B=VDD); \n "
" subcircuit 'PMOS4_STANDARD(L=0.15,NF=2,V=1.5)' XDUMMY3 (D=VDD,G=VDD,S=VDD,B=VDD); \n "
"end; \n "
"circuit 'PMOS4_STANDARD(L=0.15,NF=4,V=1.5)' (D=D,G=G,S=S,B=B); \n "
" device SKY130_FD_PR__PFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=6,AS=0.32625,AD=0.2175,PS=3.99,PD=2.66); \n "
"end; \n "
"circuit 'NMOS4_STANDARD(L=0.15,NF=4,V=1.5)' (D=D,G=G,S=S,B=B); \n "
" device SKY130_FD_PR__NFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=6,AS=0.32625,AD=0.2175,PS=3.99,PD=2.66); \n "
"end; \n "
"circuit 'NMOS4_STANDARD(L=0.15,NF=2,V=1.5)' (D=D,G=G,S=S,B=B); \n "
" device SKY130_FD_PR__NFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=3,AS=0.435,AD=0.2175,PS=4.16,PD=2.08); \n "
"end; \n "
"circuit 'PMOS4_STANDARD(L=0.15,NF=2,V=1.5)' (D=D,G=G,S=S,B=B); \n "
" device SKY130_FD_PR__PFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=3,AS=0.435,AD=0.2175,PS=4.16,PD=2.08); \n "
"end; \n "
);
}
// issue #1319, clarification
TEST ( 20 _precendence )
{
db :: Netlist nl ;
std :: string path = tl :: combine_path ( tl :: combine_path ( tl :: testdata (), "algo" ), "nreader20.cir" );
db :: NetlistSpiceReader reader ;
tl :: InputStream is ( path );
reader . read ( is , nl );
EXPECT_EQ ( nl . to_string (),
"circuit TEST (); \n "
" device CAP '1' (A=A,B=B) (C=5e-12,A=0,P=0); \n "
" device CAP '2A' (A=A,B=B) (C=2.5e-12,A=0,P=0); \n "
" device CAP '2B' (A=A,B=B) (C=2.5e-12,A=0,P=0); \n "
" device CAP_MODEL1 '3' (A=A,B=B) (C=5e-12,A=0,P=0); \n "
" device CAP3 '4' (A=A,B=B,W=CAP_MODEL1) (C=2.5e-12,A=0,P=0); \n "
" device CAP_MODEL2 '5' (A=A,B=B,W=C) (C=5e-12,A=0,P=0); \n "
" device CAP_MODEL1 '6' (A=A,B=B) (C=2.5e-12,A=0,P=0); \n "
" device CAP_MODEL2 '7A' (A=A,B=B,W=C) (C=2.5e-12,A=0,P=0); \n "
" device CAP_MODEL2 '7B' (A=A,B=B,W=C) (C=2.5e-12,A=0,P=0); \n "
" device CAP_MODEL2 '8' (A=A,B=B,W=C) (C=2.5e-12,A=0,P=0); \n "
"end; \n "
2023-03-24 14:31:49 +01:00
);
}
// issue #1320, .lib support
TEST ( 21 _lib )
{
db :: Netlist nl ;
std :: string path = tl :: combine_path ( tl :: combine_path ( tl :: testdata (), "algo" ), "nreader21.cir" );
db :: NetlistSpiceReader reader ;
tl :: InputStream is ( path );
reader . read ( is , nl );
2024-04-14 19:43:50 +02:00
EXPECT_EQ ( nl . to_string (),
"circuit .TOP (); \n "
" device CAP '10' (A='1',B='2') (C=1e-12,A=0,P=0); \n "
" device CAP '1' (A='1',B='2') (C=1e-10,A=0,P=0); \n "
" device CAP '2A' (A='1',B='2') (C=1.01e-10,A=0,P=0); \n "
" device CAP '2B' (A='1',B='2') (C=1.02e-10,A=0,P=0); \n "
" device CAP '100' (A='1',B='2') (C=1.5e-11,A=0,P=0); \n "
"end; \n "
);
}
// issue #1681, .endl with lib name
TEST ( 22 _endl )
{
db :: Netlist nl ;
std :: string path = tl :: combine_path ( tl :: combine_path ( tl :: testdata (), "algo" ), "nreader22.cir" );
db :: NetlistSpiceReader reader ;
tl :: InputStream is ( path );
reader . read ( is , nl );
2023-03-24 14:31:49 +01:00
EXPECT_EQ ( nl . to_string (),
"circuit .TOP (); \n "
" device CAP '10' (A='1',B='2') (C=1e-12,A=0,P=0); \n "
" device CAP '1' (A='1',B='2') (C=1e-10,A=0,P=0); \n "
" device CAP '2A' (A='1',B='2') (C=1.01e-10,A=0,P=0); \n "
" device CAP '2B' (A='1',B='2') (C=1.02e-10,A=0,P=0); \n "
" device CAP '100' (A='1',B='2') (C=1.5e-11,A=0,P=0); \n "
"end; \n "
2024-04-14 21:04:02 +02:00
);
}
// issue #1683
TEST ( 23 _endl )
{
db :: Netlist nl ;
std :: string path = tl :: combine_path ( tl :: combine_path ( tl :: testdata (), "algo" ), "nreader23.cir" );
db :: NetlistSpiceReader reader ;
tl :: InputStream is ( path );
reader . read ( is , nl );
EXPECT_EQ ( nl . to_string (),
"circuit .TOP (); \n "
" device PFET M1 (S=VDD,G=I,D=O,B=VDD) (L=100,W=100,AS=0,AD=0,PS=0,PD=0); \n "
" device NFET M2 (S=VSS,G=I,D=O,B=VSS) (L=100,W=100,AS=0,AD=0,PS=0,PD=0); \n "
" subcircuit DOESNOTEXIST DUMMY ('1'=O,'2'=I); \n "
"end; \n "
"circuit DOESNOTEXIST ('1'='1','2'='2'); \n "
"end; \n "
2024-04-18 21:27:09 +02:00
);
}
TEST ( 24 _recursive_calls )
{
db :: Netlist nl ;
std :: string path = tl :: combine_path ( tl :: combine_path ( tl :: testdata (), "algo" ), "nreader24.cir" );
db :: NetlistSpiceReader reader ;
tl :: InputStream is ( path );
try {
reader . read ( is , nl );
EXPECT_EQ ( false , true );
} catch ( tl :: Exception & ex ) {
2024-04-20 23:35:38 +02:00
EXPECT_EQ ( ex . msg (). find ( "Subcircuit 'C1' called recursively in" ), size_t ( 0 ));
2024-04-18 21:27:09 +02:00
}
}
TEST ( 25 _dismiss_top_level )
{
db :: Netlist nl ;
std :: string path = tl :: combine_path ( tl :: combine_path ( tl :: testdata (), "algo" ), "nreader25.cir" );
db :: NetlistSpiceReader reader ;
tl :: InputStream is ( path );
reader . read ( is , nl );
EXPECT_EQ ( nl . to_string (),
"circuit TOP (A=A,B=B); \n "
" device NMOS '1' (S=A,G=B,D=A,B=B) (L=100,W=100,AS=0,AD=0,PS=0,PD=0); \n "
"end; \n "
2024-07-28 22:24:15 +02:00
);
}
TEST ( 26 _comments )
{
db :: Netlist nl ;
std :: string path = tl :: combine_path ( tl :: combine_path ( tl :: testdata (), "algo" ), "nreader26.cir" );
db :: NetlistSpiceReader reader ;
tl :: InputStream is ( path );
reader . read ( is , nl );
EXPECT_EQ ( nl . to_string (),
"circuit TOP (A=A,B=B); \n "
" device NMOS '1' (S=A,G=B,D=A,B=B) (L=100,W=100,AS=0,AD=0,PS=0,PD=0); \n "
" device NMOS '2' (S=' \\\\ A',G='NET \" Q \" ',D=A,B='NET[0]') (L=100,W=100,AS=0,AD=0,PS=0,PD=0); \n "
" device NMOS 'FET[1]' (S=' \\\\ A',G='NET \" Q \" ',D=AAA,B='NET[0]') (L=100,W=1.7,AS=0,AD=0,PS=0,PD=0); \n "
"end; \n "
2023-02-22 13:11:30 +01:00
);
}
TEST ( 100 _ExpressionParser )
{
std :: map < std :: string , tl :: Variant > vars ;
vars [ "A" ] = 17.5 ;
vars [ "B" ] = 42 ;
vars [ "S" ] = "string" ;
tl :: Variant v ;
db :: NetlistSpiceReaderExpressionParser parser ( & vars );
EXPECT_EQ ( parser . read ( "1.75" ). to_string (), "1.75" );
EXPECT_EQ ( parser . read ( "-1.75" ). to_string (), "-1.75" );
EXPECT_EQ ( parser . read ( "-a*0.1" ). to_string (), "-1.75" );
EXPECT_EQ ( parser . read ( "-A*0.1" ). to_string (), "-1.75" );
EXPECT_EQ ( parser . read ( "b/6" ). to_string (), "7" );
EXPECT_EQ ( parser . read ( "B/6" ). to_string (), "7" );
EXPECT_EQ ( parser . read ( "s" ). to_string (), "string" );
EXPECT_EQ ( parser . read ( "S" ). to_string (), "string" );
EXPECT_EQ ( parser . read ( "!0" ). to_string (), "true" );
EXPECT_EQ ( parser . read ( "!1" ). to_string (), "false" );
EXPECT_EQ ( parser . read ( "4*2+1" ). to_string (), "9" );
EXPECT_EQ ( parser . read ( "4*2-1" ). to_string (), "7" );
EXPECT_EQ ( parser . read ( "4/2-1" ). to_string (), "1" );
EXPECT_EQ ( parser . read ( "4%2-1" ). to_string (), "-1" );
EXPECT_EQ ( parser . read ( "5%2-1" ). to_string (), "0" );
EXPECT_EQ ( parser . read ( "2**2*2+1" ). to_string (), "9" );
EXPECT_EQ ( parser . read ( "2**2*(2+1)" ). to_string (), "12" );
EXPECT_EQ ( parser . read ( "pow(2,2)*(2+1)" ). to_string (), "12" );
EXPECT_EQ ( parser . read ( "POW(2,2)*(2+1)" ). to_string (), "12" );
EXPECT_EQ ( parser . read ( "pwr(2,2)*(2+1)" ). to_string (), "12" );
EXPECT_EQ ( parser . read ( "PWR(2,2)*(2+1)" ). to_string (), "12" );
EXPECT_EQ ( parser . read ( "3==2+1" ). to_string (), "true" );
EXPECT_EQ ( parser . read ( "4==2+1" ). to_string (), "false" );
EXPECT_EQ ( parser . read ( "3!=2+1" ). to_string (), "false" );
EXPECT_EQ ( parser . read ( "4!=2+1" ). to_string (), "true" );
EXPECT_EQ ( parser . read ( "2<2+1" ). to_string (), "true" );
EXPECT_EQ ( parser . read ( "3<2+1" ). to_string (), "false" );
EXPECT_EQ ( parser . read ( "4<2+1" ). to_string (), "false" );
EXPECT_EQ ( parser . read ( "2<=2+1" ). to_string (), "true" );
EXPECT_EQ ( parser . read ( "3<=2+1" ). to_string (), "true" );
EXPECT_EQ ( parser . read ( "4<=2+1" ). to_string (), "false" );
EXPECT_EQ ( parser . read ( "2>2+1" ). to_string (), "false" );
EXPECT_EQ ( parser . read ( "3>2+1" ). to_string (), "false" );
EXPECT_EQ ( parser . read ( "4>2+1" ). to_string (), "true" );
EXPECT_EQ ( parser . read ( "2>=2+1" ). to_string (), "false" );
EXPECT_EQ ( parser . read ( "3>=2+1" ). to_string (), "true" );
EXPECT_EQ ( parser . read ( "4>=2+1" ). to_string (), "true" );
EXPECT_EQ ( parser . read ( "1==2||2==2" ). to_string (), "true" );
EXPECT_EQ ( parser . read ( "1==2||3==2" ). to_string (), "false" );
EXPECT_EQ ( parser . read ( "1==2&&2==2" ). to_string (), "false" );
EXPECT_EQ ( parser . read ( "1==1&&2==2" ). to_string (), "true" );
EXPECT_EQ ( parser . read ( "1==2?2:3" ). to_string (), "3" );
EXPECT_EQ ( parser . read ( "ternery_fcn(1==2,2,3)" ). to_string (), "3" );
EXPECT_EQ ( parser . read ( "1==1?2:3" ). to_string (), "2" );
EXPECT_EQ ( parser . read ( "ternery_fcn(1==1,2,3)" ). to_string (), "2" );
EXPECT_EQ ( parser . read ( "sin(0)" ). to_string (), "0" );
EXPECT_EQ ( parser . read ( "sin(atan(1.0)*2)" ). to_string (), "1" );
EXPECT_EQ ( parser . read ( "cos(0)" ). to_string (), "1" );
EXPECT_EQ ( parser . read ( "cos(atan(1.0)*2)" ). to_string (), "0" );
EXPECT_EQ ( parser . read ( "tan(0)" ). to_string (), "0" );
EXPECT_EQ ( parser . read ( "tan(atan(1.0))" ). to_string (), "1" );
EXPECT_EQ ( parser . read ( "sin(asin(0.5))" ). to_string (), "0.5" );
EXPECT_EQ ( parser . read ( "cos(acos(0.5))" ). to_string (), "0.5" );
EXPECT_EQ ( parser . read ( "ln(exp(0.5))" ). to_string (), "0.5" );
EXPECT_EQ ( parser . read ( "exp(0.0)" ). to_string (), "1" );
EXPECT_EQ ( parser . read ( "log(10**0.5)" ). to_string (), "0.5" );
EXPECT_EQ ( parser . read ( "int(-0.5)" ). to_string (), "0" );
EXPECT_EQ ( parser . read ( "int(-1.5)" ). to_string (), "-1" );
EXPECT_EQ ( parser . read ( "int(0.5)" ). to_string (), "0" );
EXPECT_EQ ( parser . read ( "int(1.5)" ). to_string (), "1" );
EXPECT_EQ ( parser . read ( "floor(-0.5)" ). to_string (), "-1" );
EXPECT_EQ ( parser . read ( "floor(-1.5)" ). to_string (), "-2" );
EXPECT_EQ ( parser . read ( "floor(0.5)" ). to_string (), "0" );
EXPECT_EQ ( parser . read ( "floor(1.5)" ). to_string (), "1" );
EXPECT_EQ ( parser . read ( "ceil(-0.5)" ). to_string (), "0" );
EXPECT_EQ ( parser . read ( "ceil(-1.5)" ). to_string (), "-1" );
EXPECT_EQ ( parser . read ( "ceil(0.5)" ). to_string (), "1" );
EXPECT_EQ ( parser . read ( "ceil(1.5)" ). to_string (), "2" );
EXPECT_EQ ( parser . read ( "nint(-0.5)" ). to_string (), "0" );
EXPECT_EQ ( parser . read ( "nint(-1.5)" ). to_string (), "-2" );
EXPECT_EQ ( parser . read ( "nint(0.5)" ). to_string (), "0" );
EXPECT_EQ ( parser . read ( "nint(1.5)" ). to_string (), "2" );
EXPECT_EQ ( parser . read ( "min(4,1,3)" ). to_string (), "1" );
EXPECT_EQ ( parser . read ( "min(4,3)" ). to_string (), "3" );
EXPECT_EQ ( parser . read ( "min(4)" ). to_string (), "4" );
EXPECT_EQ ( parser . read ( "max(1,4,3)" ). to_string (), "4" );
EXPECT_EQ ( parser . read ( "max(4,3)" ). to_string (), "4" );
EXPECT_EQ ( parser . read ( "max(4)" ). to_string (), "4" );
EXPECT_EQ ( parser . read ( "max(a,b)" ). to_string (), "42" );
EXPECT_EQ ( parser . try_read ( "a syntax error" , v ), false );
v = tl :: Variant ();
EXPECT_EQ ( parser . try_read ( "1+2*(2+1)-1" , v ), true );
EXPECT_EQ ( v . to_string (), "6" );
EXPECT_EQ ( parser . try_read ( "{1+2*(2+1)-1)" , v ), false );
EXPECT_EQ ( parser . try_read ( "'1+2*(2+1)-1)" , v ), false );
EXPECT_EQ ( parser . try_read ( " \" 1+2*(2+1)-1)" , v ), false );
EXPECT_EQ ( parser . try_read ( " \" 1+2*(2+1)-1'" , v ), false );
v = tl :: Variant ();
EXPECT_EQ ( parser . try_read ( "{1+2*(2+1)-1}" , v ), true );
EXPECT_EQ ( v . to_string (), "6" );
v = tl :: Variant ();
EXPECT_EQ ( parser . try_read ( "'1+2*(2+1)-1'" , v ), true );
EXPECT_EQ ( v . to_string (), "6" );
v = tl :: Variant ();
EXPECT_EQ ( parser . try_read ( " \" 1+2*(2+1)-1 \" " , v ), true );
EXPECT_EQ ( v . to_string (), "6" );
}
2023-03-12 15:36:50 +01:00
TEST ( 101 _ExpressionParserWithDefScale )
{
std :: map < std :: string , tl :: Variant > vars ;
vars [ "A" ] = 17.5 ;
tl :: Variant v ;
db :: NetlistSpiceReaderExpressionParser parser ( & vars , 1e-3 );
EXPECT_EQ ( parser . read ( "1.75" ). to_string (), "0.00175" );
EXPECT_EQ ( parser . read ( "-1.75u" ). to_string (), "-1.75e-06" );
EXPECT_EQ ( parser . read ( "1.75k" ). to_string (), "1750" );
EXPECT_EQ ( parser . read ( "2*A" ). to_string (), "0.035" );
}