Introduction
GDSII is an industry standard for data exchange of integrated circuits (IC) layout artwork. It is a binary file format representing planar geometric shapes, text labels, and other information about the layout in hierarchical form. The manual can be found in here. The parser consists of three parts, reader, writer and database for full chip parsing. GdsParser::GdsReader provides API to read GDSII files (.gds or .gds.gz with Boost and Zlib support). GdsParser::GdsWriter provides API to write GDSII files (.gds or .gds.gz with Boost and Zlib support). These two parts are basic functionalities for read and write in GDSII format. GdsParser::GdsDB is a database to store layout elements and provides easy API to read, write and flatten full layouts.
Examples
Stream Reader
See documented version: test/parsers/gdsii/test_reader.cpp
#include <iostream>
using std::cout;
using std::endl;
{
{
cout << "constructing AsciiDataBase" << endl;
}
virtual void bit_array_cbk(
const char* ascii_record_type,
const char* ascii_data_type, vector<int>
const& vBitArray)
{
cout << __func__ << endl;
this->
general_cbk(ascii_record_type, ascii_data_type, vBitArray);
}
virtual void integer_2_cbk(
const char* ascii_record_type,
const char* ascii_data_type, vector<int>
const& vInteger)
{
cout << __func__ << endl;
this->
general_cbk(ascii_record_type, ascii_data_type, vInteger);
}
virtual void integer_4_cbk(
const char* ascii_record_type,
const char* ascii_data_type, vector<int>
const& vInteger)
{
cout << __func__ << endl;
this->
general_cbk(ascii_record_type, ascii_data_type, vInteger);
}
virtual void real_4_cbk(
const char* ascii_record_type,
const char* ascii_data_type, vector<double>
const& vFloat)
{
cout << __func__ << endl;
this->
general_cbk(ascii_record_type, ascii_data_type, vFloat);
}
virtual void real_8_cbk(
const char* ascii_record_type,
const char* ascii_data_type, vector<double>
const& vFloat)
{
cout << __func__ << endl;
this->
general_cbk(ascii_record_type, ascii_data_type, vFloat);
}
virtual void string_cbk(
const char* ascii_record_type,
const char* ascii_data_type,
string const& str)
{
cout << __func__ << endl;
this->
general_cbk(ascii_record_type, ascii_data_type, str);
}
{
cout << __func__ << endl;
this->
general_cbk(ascii_record_type,
"", vector<int>(0));
}
template <typename ContainerType>
void general_cbk(
string const& ascii_record_type,
string const& ascii_data_type, ContainerType
const& data)
{
cout << "ascii_record_type: " << ascii_record_type << endl
<< "ascii_data_type: " << ascii_data_type << endl
<< "data size: " << data.size() << endl;
if (ascii_record_type == "UNITS")
{
}
else if (ascii_record_type == "BOUNDARY")
{
}
else if (ascii_record_type == "LAYER")
{
}
else if (ascii_record_type == "XY")
{
cout << data.size() << endl;
}
else if (ascii_record_type == "ENDEL")
{
}
}
};
{
{
cout << "constructing EnumDataBase" << endl;
}
{
cout << __func__ << endl;
}
{
cout << __func__ << endl;
}
{
cout << __func__ << endl;
}
{
cout << __func__ << endl;
}
{
cout << __func__ << endl;
}
{
cout << __func__ << endl;
}
{
cout << __func__ << endl;
this->
general_cbk(record_type, GdsParser::GdsData::NO_DATA, vector<int>(0));
}
template <typename ContainerType>
{
<< "data size: " << data.size() << endl;
switch (record_type)
{
case GdsParser::GdsRecords::UNITS:
break;
case GdsParser::GdsRecords::BOUNDARY:
break;
case GdsParser::GdsRecords::LAYER:
cout << "LAYER = " << data[0] << endl;
break;
case GdsParser::GdsRecords::XY:
for (typename ContainerType::const_iterator it = data.begin(); it != data.end(); ++it)
cout << *it << " ";
cout << endl;
cout << data.size() << endl;
break;
case GdsParser::GdsRecords::ENDEL:
break;
default:
break;
}
}
};
int main(
int argc,
char** argv)
{
if (argc > 1)
{
}
else cout << "at least 1 argument is required" << endl;
return 0;
}
GdsDataBase redirects callbacks of GdsDataBaseKernel to ascii callbacks.
Kernel callbacks for GdsReader. These callbacks use enum for record_type and data_type,...
bool read(GdsDriverDataBase &db, string const &filename)
API function for GdsDriver.
const char * gds_record_ascii(int record_type)
const char * gds_data_ascii(int data_type)
virtual void begin_end_cbk(const char *ascii_record_type)
begin or end indicator of a block
virtual void real_4_cbk(const char *ascii_record_type, const char *ascii_data_type, vector< double > const &vFloat)
4-byte floating point number callback
virtual void bit_array_cbk(const char *ascii_record_type, const char *ascii_data_type, vector< int > const &vBitArray)
bit array callback
virtual void string_cbk(const char *ascii_record_type, const char *ascii_data_type, string const &str)
string callback
virtual void real_8_cbk(const char *ascii_record_type, const char *ascii_data_type, vector< double > const &vFloat)
8-byte floating point number callback
virtual void integer_2_cbk(const char *ascii_record_type, const char *ascii_data_type, vector< int > const &vInteger)
2-byte integer callback
void general_cbk(string const &ascii_record_type, string const &ascii_data_type, ContainerType const &data)
A generic callback function handles all other callback functions. It is not efficient but concise as ...
AsciiDataBase()
constructor
virtual void integer_4_cbk(const char *ascii_record_type, const char *ascii_data_type, vector< int > const &vInteger)
4-byte integer callback
virtual void integer_4_cbk(GdsParser::GdsRecords::EnumType record_type, GdsParser::GdsData::EnumType data_type, vector< int > const &vInteger)
4-byte integer callback
virtual void real_8_cbk(GdsParser::GdsRecords::EnumType record_type, GdsParser::GdsData::EnumType data_type, vector< double > const &vFloat)
8-byte floating point number callback
virtual void begin_end_cbk(GdsParser::GdsRecords::EnumType record_type)
begin or end indicator of a block
virtual void string_cbk(GdsParser::GdsRecords::EnumType record_type, GdsParser::GdsData::EnumType data_type, string const &str)
string callback
virtual void real_4_cbk(GdsParser::GdsRecords::EnumType record_type, GdsParser::GdsData::EnumType data_type, vector< double > const &vFloat)
4-byte floating point number callback
void general_cbk(GdsParser::GdsRecords::EnumType record_type, GdsParser::GdsData::EnumType data_type, ContainerType const &data)
A generic callback function handles all other callback functions. It is not efficient but concise as ...
virtual void integer_2_cbk(GdsParser::GdsRecords::EnumType record_type, GdsParser::GdsData::EnumType data_type, vector< int > const &vInteger)
2-byte integer callback
virtual void bit_array_cbk(GdsParser::GdsRecords::EnumType record_type, GdsParser::GdsData::EnumType data_type, vector< int > const &vBitArray)
bit array callback
EnumDataBase()
constructor
EnumType
enum type of data type
EnumType
enum type of GDSII records
Compiling and running commands (assuming LIMBO_DIR is exported as the environment variable to the path where limbo library is installed)
g++ -o test_reader test_reader.cpp -I $LIMBO_DIR/include -L $LIMBO_DIR/lib -lgdsparser
# read a file
./test_reader benchmarks/test_reader.gds
If BOOST_DIR and ZLIB_DIR have been defined as environment variables when building Limbo library, one can compile with support to compression files.
g++ -o test_reader test_reader.cpp -I $LIMBO_DIR/include -L $LIMBO_DIR/lib -lgdsparser -L $BOOST_DIR/lib -lboost_iostreams -L $ZLIB_DIR -lz
# read a compressed file
./test_reader benchmarks/test_reader_gz.gds.gz
Stream Writer
See documented version: test/parsers/gdsii/test_writer.cpp
#include <vector>
int main(
int argc,
char *argv[] )
{
int
x[5],
y[5];
if (argc < 2)
{
printf("need a output file name\n");
return 1;
}
gw.create_lib("dogs", 0.001, 1.0e-9);
gw.gds_write_bgnstr( );
gw.gds_write_strname( "hotdogs" );
gw.gds_write_boundary( );
gw.gds_write_layer( 10001 );
gw.gds_write_datatype( 0 );
x[0] = 0; y[0] = 0;
x[1] = 0; y[1] = 500;
x[2] = 1000; y[2] = 500;
x[3] = 1000; y[3] = 0;
x[4] = 0; y[4] = 0;
gw.gds_write_xy( x, y, 5 );
gw.gds_write_endel( );
std::vector<int> vx(4);
std::vector<int> vy(4);
vx[0] = 0; vy[0] = 0;
vx[1] = 0; vy[1] = 500;
vx[2] = 1000; vy[2] = 500;
vx[3] = 1000; vy[3] = 0;
gw.write_boundary(10002, 0, vx, vy, false);
for (int i = 0; i < 1; ++i)
gw.write_box(10003, 0, 10, 10, 20, 20);
gw.gds_write_text( );
gw.gds_write_layer( 1 );
gw.gds_write_texttype( 0 );
gw.gds_write_presentation( 0, 1, 1 );
gw.gds_write_width( 500 );
gw.gds_write_strans( 1, 0, 0 );
x[0] = 2000;
y[0] = 2000;
gw.gds_write_xy( x, y, 1 );
gw.gds_write_string( "reflected" );
gw.gds_write_endel( );
gw.gds_create_text( "not reflected", 2000, 1500, 2, 500 );
gw.gds_write_path( );
gw.gds_write_layer( 3 );
gw.gds_write_datatype( 4 );
gw.gds_write_pathtype( 2 );
gw.gds_write_width( 200 );
x[0] = 2000; y[0] = 3000;
x[1] = 2000; y[1] = 4000;
x[2] = 2500; y[2] = 3500;
gw.gds_write_xy( x, y, 3 );
gw.gds_write_endel( );
gw.gds_write_box( );
gw.gds_write_layer( 6 );
gw.gds_write_boxtype( 12 );
x[0] = 3000; y[0] = 0;
x[1] = 3000; y[1] = 500;
x[2] = 4000; y[2] = 500;
x[3] = 4000; y[3] = 0;
x[4] = 3000; y[4] = 0;
gw.gds_write_xy( x, y, 5 );
gw.gds_write_endel( );
gw.gds_write_endstr( );
gw.gds_write_bgnstr( );
gw.gds_write_strname( "sausage" );
gw.gds_write_sref( );
gw.gds_write_sname( "hotdogs" );
gw.gds_write_mag( 5.0 );
gw.gds_write_angle( 15.4 );
x[0] = 2000;
y[0] = -2000;
gw.gds_write_xy( x, y, 1 );
gw.gds_write_endel( );
gw.gds_write_endstr( );
gw.gds_write_bgnstr( );
gw.gds_write_strname( "meatball" );
gw.gds_write_aref( );
gw.gds_write_sname( "sausage" );
gw.gds_write_colrow( 2, 5 );
x[0] = 5000; y[0] = 5000;
x[1] = 85000; y[1] = 5000;
x[2] = 5000; y[2] = 205000;
gw.gds_write_xy( x, y, 3 );
gw.gds_write_endel( );
gw.gds_write_endstr( );
gw.gds_write_endlib( );
printf( "\nDone. Look at %s\n\n", argv[1] );
return 0;
}
Compiling and running commands (assuming LIMBO_DIR is exported as the environment variable to the path where limbo library is installed)
g++ -o test_writer test_writer.cpp -I $LIMBO_DIR/include -L $LIMBO_DIR/lib -lgdsparser
# write to a file
./test_writer test_writer.gds
If BOOST_DIR and ZLIB_DIR have been defined as environment variables when building Limbo library, one can compile with support to compression files.
g++ -o test_writer test_writer.cpp -I $LIMBO_DIR/include -L $LIMBO_DIR/lib -lgdsparser -L $BOOST_DIR/lib -lboost_iostreams -L $ZLIB_DIR -lz
# write to a compressed file
./test_writer test_writer_gz.gds.gz
Stream GDSII Database
See documented version: test/parsers/gdsii/test_gdsdb.cpp
#include <iostream>
int main(
int argc,
char** argv)
{
if (argc > 2 && argc <= 4)
{
for (std::vector<GdsParser::GdsDB::GdsCell>::const_iterator it = db.
cells().begin(); it != db.
cells().end(); ++it)
std::cout << "cell: " << it->name() << std::endl;
gw(argv[2]);
std::cout << "4 arguments to test flatten: input gds, output gds, flat output gds, flat cell name" << std::endl;
}
else if (argc > 4)
{
for (std::vector<GdsParser::GdsDB::GdsCell>::const_iterator it = db.
cells().begin(); it != db.
cells().end(); ++it)
std::cout << "cell: " << it->name() << std::endl;
#if 0
for (std::vector<GdsParser::GdsDB::GdsCell>::iterator it = db.
cells().begin(); it != db.
cells().end(); ++it)
{
if (cell.
name() != argv[4])
{
for (std::vector<GdsParser::GdsDB::GdsCell::object_entry_type>::iterator itc = cell.
objects().begin(), itce = cell.
objects().end(); itc != itce; )
{
if (itc->first == ::GdsParser::GdsRecords::TEXT)
{
std::vector<GdsParser::GdsDB::GdsCell::object_entry_type>::iterator itclast = itce - 1;
if (itc != itclast)
{
std::swap(*itc, *itclast);
}
}
else
{
++itc;
}
}
}
}
#endif
flatGw(argv[3]);
}
else std::cout << "at least 4 arguments are required: input gds, output gds, flat output gds, flat cell name" << std::endl;
return 0;
}
#define limboAssert(condition)
custom assertion without message
Wrapper to GDSII read and write with GDSII database GdsParser::GdsDB::GdsDB.
Various GDSII objects and a top GDSII database.
header to include PrintMsg.h and AssertMsg.h
std::vector< std::pair< ::GdsParser::GdsRecords::EnumType, GdsObject * > > const & objects() const
std::string const & name() const
GdsCell & addCell(std::string const &name="")
add a cell and return the reference to the new cell
std::string const & libname() const
GdsCell extractCell(std::string const &cellName) const
extract a cell into a new cell with flatten hierarchies
void setPrecision(double p)
void setLibname(std::string const &n)
std::vector< GdsCell > const & cells() const
read GDSII file with GDSII database GdsParser::GdsDB::GdsDB
write GDSII file with GDSII database GdsParser::GdsDB::GdsDB
an action function for delete a cell
a helper to facilitate actions on different GDSII objects.
Compiling and running commands (assuming LIMBO_DIR is exported as the environment variable to the path where limbo library is installed)
g++ -o test_gdsdb test_gdsdb.cpp -I $LIMBO_DIR/include -I $BOOST_DIR/include -L $LIMBO_DIR/lib -lgdsparser -lgdsdb
# read a file and test flatten
./test_gdsdb benchmarks/test_reader.gds test_gdsdb.gds test_gdsdb_flat.gds TOPCELL
If BOOST_DIR and ZLIB_DIR have been defined as environment variables when building Limbo library, one can compile with support to compression files.
g++ -o test_gdsdb test_gdsdb.cpp -I $LIMBO_DIR/include -I $BOOST_DIR/include -L $LIMBO_DIR/lib -lgdsparser -lgdsdb -L $BOOST_DIR/lib -lboost_iostreams -L $ZLIB_DIR -lz
# read a compressed file and test flatten
./test_gdsdb benchmarks/test_reader_gz.gds.gz test_gdsdb_gz.gds.gz test_gdsdb_gz_flat.gds.gz TOPCELL
All Examples
References