Limbo 3.5.4
Loading...
Searching...
No Matches
Limbo.Parsers.GdsiiParser

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);
}
virtual void begin_end_cbk(const char* ascii_record_type)
{
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;
}
virtual void bit_array_cbk(GdsParser::GdsRecords::EnumType record_type, GdsParser::GdsData::EnumType data_type, vector<int> const& vBitArray)
{
cout << __func__ << endl;
this->general_cbk(record_type, data_type, vBitArray);
}
virtual void integer_2_cbk(GdsParser::GdsRecords::EnumType record_type, GdsParser::GdsData::EnumType data_type, vector<int> const& vInteger)
{
cout << __func__ << endl;
this->general_cbk(record_type, data_type, vInteger);
}
virtual void integer_4_cbk(GdsParser::GdsRecords::EnumType record_type, GdsParser::GdsData::EnumType data_type, vector<int> const& vInteger)
{
cout << __func__ << endl;
this->general_cbk(record_type, data_type, vInteger);
}
virtual void real_4_cbk(GdsParser::GdsRecords::EnumType record_type, GdsParser::GdsData::EnumType data_type, vector<double> const& vFloat)
{
cout << __func__ << endl;
this->general_cbk(record_type, data_type, vFloat);
}
virtual void real_8_cbk(GdsParser::GdsRecords::EnumType record_type, GdsParser::GdsData::EnumType data_type, vector<double> const& vFloat)
{
cout << __func__ << endl;
this->general_cbk(record_type, data_type, vFloat);
}
virtual void string_cbk(GdsParser::GdsRecords::EnumType record_type, GdsParser::GdsData::EnumType data_type, string const& str)
{
cout << __func__ << endl;
this->general_cbk(record_type, data_type, str);
}
{
cout << __func__ << endl;
this->general_cbk(record_type, GdsParser::GdsData::NO_DATA, vector<int>(0));
}
template <typename ContainerType>
void general_cbk(GdsParser::GdsRecords::EnumType record_type, GdsParser::GdsData::EnumType data_type, ContainerType const& data)
{
cout << "ascii_record_type: " << GdsParser::gds_record_ascii(record_type) << endl
<< "ascii_data_type: " << GdsParser::gds_data_ascii(data_type) << endl
<< "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;
}
}
};
/* ===========================================
example to read .gds.gz
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/filtering_stream.hpp>
EnumDataBase edb;
boost::iostreams::filtering_istream in;
in.push(boost::iostreams::gzip_decompressor());
in.push(boost::iostreams::file_source(argv[1]));
cout << "test enum api\n" << GdsParser::read(edb, in) << endl;
=========================================== */
int main(int argc, char** argv)
{
if (argc > 1)
{
cout << "test ascii api\n" << GdsParser::read(adb, argv[1]) << endl;
cout << "test enum api\n" << GdsParser::read(edb, argv[1]) << endl;
}
else cout << "at least 1 argument is required" << endl;
return 0;
}
read GDSII file
GdsDataBase redirects callbacks of GdsDataBaseKernel to ascii callbacks.
Definition GdsReader.h:82
Kernel callbacks for GdsReader. These callbacks use enum for record_type and data_type,...
Definition GdsReader.h:40
bool read(GdsDriverDataBase &db, string const &filename)
API function for GdsDriver.
const char * gds_record_ascii(int record_type)
Definition GdsRecords.h:329
const char * gds_data_ascii(int data_type)
Definition GdsRecords.h:347
test ascii callbacks
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
test enum callbacks
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
Definition GdsRecords.h:222
EnumType
enum type of GDSII records
Definition GdsRecords.h:23
int main()

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;
}
// start the gds library with HEADER, BGNLIB, LIBNAME, and UNITS
GdsParser::GdsWriter gw (argv[1]);
// two different wrappers
//gw.gds_create_lib( "dogs", 0.001 /* um per bit */ );
gw.create_lib("dogs", 0.001, 1.0e-9);
// create a cell called "hotdogs"
gw.gds_write_bgnstr( );
gw.gds_write_strname( "hotdogs" );
//-----------------------------------------------------------------------------
// create a polygon 1
gw.gds_write_boundary( ); // write just the token
gw.gds_write_layer( 10001 ); // layer 0, for example
gw.gds_write_datatype( 0 ); // datatype 1, for example
x[0] = 0; y[0] = 0; // signed four-byte integers
x[1] = 0; y[1] = 500;
x[2] = 1000; y[2] = 500; // in this example 1 integer unit = 1 nm
x[3] = 1000; y[3] = 0;
x[4] = 0; y[4] = 0; // required repetition of first point (yup, that's stupid)
gw.gds_write_xy( x, y, 5 ); // polygon, four vertices, first vertex repeated => 5 points
gw.gds_write_endel( ); // end of element
//-----------------------------------------------------------------------------
// create a polygon 2
// use high-level interfaces
std::vector<int> vx(4);
std::vector<int> vy(4);
vx[0] = 0; vy[0] = 0; // signed four-byte integers
vx[1] = 0; vy[1] = 500;
vx[2] = 1000; vy[2] = 500; // in this example 1 integer unit = 1 nm
vx[3] = 1000; vy[3] = 0;
gw.write_boundary(10002, 0, vx, vy, false);
//-----------------------------------------------------------------------------
// create a polygon 3
// for rectangles
// use high-level interfaces
for (int i = 0; i < 1; ++i)
gw.write_box(10003, 0, 10, 10, 20, 20);
//-----------------------------------------------------------------------------
// create some text, reflected about the x axis
gw.gds_write_text( );
gw.gds_write_layer( 1 );
gw.gds_write_texttype( 0 );
gw.gds_write_presentation( 0, 1, 1 ); // font, hp, vp
gw.gds_write_width( 500 );
gw.gds_write_strans( 1, 0, 0 ); // reflect, abs_angle, abs_mag
x[0] = 2000;
y[0] = 2000;
gw.gds_write_xy( x, y, 1 );
gw.gds_write_string( "reflected" );
gw.gds_write_endel( );
//-----------------------------------------------------------------------------
// create some text, using the helper function instead.
// arguments: file-descriptor, string, x, y, layer, size
// where x, y, and size are in database units (nanometers, usually)
gw.gds_create_text( "not reflected", 2000, 1500, 2, 500 );
//-----------------------------------------------------------------------------
// create a path
gw.gds_write_path( );
gw.gds_write_layer( 3 ); // layer 3
gw.gds_write_datatype( 4 ); // datatype 4
gw.gds_write_pathtype( 2 ); // extended square ends
gw.gds_write_width( 200 ); // 200 nm wide
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( );
//-----------------------------------------------------------------------------
// create a box, which is stupid
gw.gds_write_box( ); // write just the token
gw.gds_write_layer( 6 ); // layer 6, for example
gw.gds_write_boxtype( 12 ); // boxtype 12, for example same as datatype
x[0] = 3000; y[0] = 0; // signed four-byte integers
x[1] = 3000; y[1] = 500;
x[2] = 4000; y[2] = 500; // in this example 1 integer unit = 1 nm
x[3] = 4000; y[3] = 0;
x[4] = 3000; y[4] = 0; // required repetition of first point (yup, that's stupid)
gw.gds_write_xy( x, y, 5 ); // polygon, four vertices, first vertex repeated => 5 points
gw.gds_write_endel( ); // end of element
// end the structure (the cell hotdogs)
gw.gds_write_endstr( );
//-----------------------------------------------------------------------------
// Create a new cell, which will contain an instance of the previous cell
gw.gds_write_bgnstr( ); // new cell (structure)
gw.gds_write_strname( "sausage" ); // called "sausage"
gw.gds_write_sref( ); // contains an instance of...
gw.gds_write_sname( "hotdogs" ); // the cell hotdogs
gw.gds_write_mag( 5.0 ); // which will be 5 times larger
gw.gds_write_angle( 15.4 ); // and tilted at some weird angle
x[0] = 2000;
y[0] = -2000;
gw.gds_write_xy( x, y, 1 ); // at these coordinates (database units)
gw.gds_write_endel( ); // end of element
gw.gds_write_endstr( ); // end of structure (cell)
//-----------------------------------------------------------------------------
// Create a new cell "meatball" containing an array of the cell "sausage"
gw.gds_write_bgnstr( ); // new cell
gw.gds_write_strname( "meatball" ); // called "meatball"
gw.gds_write_aref( ); // containing an array of...
gw.gds_write_sname( "sausage" ); // the cell "sausage"
gw.gds_write_colrow( 2, 5 ); // 2 columns, 5 rows
x[0] = 5000; y[0] = 5000; // array anchor point
x[1] = 85000; y[1] = 5000; // displacement from anchor plus ncols*pitch
// which makes the column pitch 40 um
x[2] = 5000; y[2] = 205000; // displacement from anchor plus nrows*pitch
// which makes the row pitch 40 um
gw.gds_write_xy( x, y, 3 ); // See how you could have a diagonal matrix?
// That would be so goofy!
gw.gds_write_endel( ); // end of element
gw.gds_write_endstr( ); // end of structure (cell) "meatball"
// end of library
gw.gds_write_endlib( );
printf( "\nDone. Look at %s\n\n", argv[1] );
return 0;
}
write GDSII file

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)
{
// test simple read and write
limboAssert(reader(argv[1]));
for (std::vector<GdsParser::GdsDB::GdsCell>::const_iterator it = db.cells().begin(); it != db.cells().end(); ++it)
std::cout << "cell: " << it->name() << std::endl;
// write
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)
{
// test simple read and write
limboAssert(reader(argv[1]));
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
// try removing all text records except for the top cell
// iterate through all cells
for (std::vector<GdsParser::GdsDB::GdsCell>::iterator it = db.cells().begin(); it != db.cells().end(); ++it)
{
if (cell.name() != argv[4]) // check the non-top cell
{
// iterate through all objects
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) // find TEXT records
{
std::vector<GdsParser::GdsDB::GdsCell::object_entry_type>::iterator itclast = itce - 1;
if (itc != itclast) // swap current object with the last object
{
std::swap(*itc, *itclast);
}
// delete the last object
GdsParser::GdsDB::GdsObjectHelpers()(itclast->first, itclast->second, GdsParser::GdsDB::DeleteCellObjectAction(*itclast));
// update the object array in the cell
cell.objects().pop_back();
// update end iterator
itce = cell.objects().end();
}
else
{
++itc;
}
}
}
}
#endif
// test flatten
GdsParser::GdsDB::GdsCell flatCell = db.extractCell(argv[4]);
flatDB.setLibname(db.libname());
flatDB.setUnit(db.unit());
flatDB.setPrecision(db.precision());
flatDB.addCell(flatCell);
// write flatten cell
GdsParser::GdsDB::GdsWriter flatGw (flatDB);
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
Definition AssertMsg.h:36
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
Definition GdsObjects.h:632
std::string const & name() const
Definition GdsObjects.h:627
GdsCell & addCell(std::string const &name="")
add a cell and return the reference to the new cell
void setUnit(double u)
Definition GdsObjects.h:700
std::string const & libname() const
Definition GdsObjects.h:693
double unit() const
Definition GdsObjects.h:698
GdsCell extractCell(std::string const &cellName) const
extract a cell into a new cell with flatten hierarchies
double precision() const
Definition GdsObjects.h:703
void setPrecision(double p)
Definition GdsObjects.h:705
void setLibname(std::string const &n)
Definition GdsObjects.h:695
std::vector< GdsCell > const & cells() const
Definition GdsObjects.h:708
read GDSII file with GDSII database GdsParser::GdsDB::GdsDB
Definition GdsIO.h:27
write GDSII file with GDSII database GdsParser::GdsDB::GdsDB
Definition GdsIO.h:121
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