Hurricane VLSI Database


Classes
JSON Support

JSON Import/Export of the DataBase. More...

Classes

class  Hurricane::JsonObject
 Support for JSON export. More...
 
class  Hurricane::JsonStack
 JSON Parser Stack. More...
 

Detailed Description

JSON Import/Export of the DataBase.

Introduction

One key feature of the Hurricane DataBase is it's hierarchical managment. But unfortunatly the simple approach of saving a design Cell by Cell, hierarchical level by hierarchical level makes it very difficult to save the trans-hierarchical informations (mainly is the occurrences)

One solution is to save the design and all it's levels, down and including the standard cells. With all the levels saved, we then can add the occurrences and all the attached trans-hierarchical informations. We call that comprehensive saving of a design, a design blob.

Instead of creating one more ad-hoc format, we just dump the DataBase objects in a mirror like way in JSON format.

As it is a textual format, the generated files are larges. So the files are compressed through gzip.

JSON Additional Semantic

To ease the work of the parser, some semantic has been added to the JSON objects representing a Hurricane DataBase.

  1. The first key/value pair must have the key "@typename" and give the kind of JsonObject associated. The value is the string returned by JsonObject::getTypeName().
  2. Attributes keys must start by a '_' character. (yes, I know, the C++ convention has changed and it should be put at the end).
  3. Collections or containers must be put after all the scalar attributes and their keys must start by a '+' character.
{
"@typename": "Cell",
"_id": 3,
"_library": "RootLibrary.AllianceFramework.sxlib",
"_name": "o3_x2",
"_abutmentBox": {
"@typename": "Box",
"_xMin": 0,
"_yMin": 0,
"_xMax": 72000,
"_yMax": 120000
},
"+instanceMap": [],
"+netMap": [
],
}

JSON Driver Support

The driver is implemented through overloads (template and non-template) of the jsonWriter() function. For the template overload to work, even for non-Hurricane classes, it is defined outside the Hurricane namespace.

For POD types, four overloads of jsonWriter() are defined:

void jsonWrite ( JsonWriter* w, const int* v );
void jsonWrite ( JsonWriter* w, int v );
void jsonWrite ( JsonWriter* w, const std::string& key, const int* value )
void jsonWrite ( JsonWriter* w, const std::string& key, int value )

The first two writes the object (here: int) "as is" while the two later writes a pair key/object.

For other class/object that needs to be writen in the JSON file, they must provide a toJson() function. It doesn't even need to be virtual. For Point:

void Point::toJson ( JsonWriter* w ) const
{
w->startObject();
jsonWrite( w, "@typename", "Point" );
jsonWrite( w, "_x", getX() );
jsonWrite( w, "_y", getY() );
w->endObject();
}

This function allows three templates of jsonWrite() to be used with an object of class Point:

template<typename C>
void jsonWrite ( JsonWriter* w, const C* object );
template<typename C>
void jsonWrite ( JsonWriter* w, const std::string& key, C* object );
template<typename C>
void jsonWrite ( JsonWriter* w, const std::string& key, const C* object );

Note that through those three overloads we only provides support for pointers to object. The driving mechanism is designed in such a way that passing arguments by value is not supported for non-POD types. Trying to do so will result in an unsupported message inside the generated JSON file.

DBos Special Case

For DBo objects, a complete parallel hierarchy of JsonObjects mimicking the one of DBos has been implemented. The toJson() function is implemented in the DBo base object, and the derived classes must implement the following virtual functions:

class DBo {
public:
virtual void _toJson ( JsonWriter* ) const;
virtual void _toJsonCollections ( JsonWriter* ) const;
virtual void _toJsonSignature ( JsonWriter* ) const;
void toJson ( JsonWriter* ) const;
void toJsonSignature ( JsonWriter* ) const;

The JSON driver functions is splitted in two parts:

The additionnal toJsonSignature() method provide the signature for an Entity which is used by an occurrence. The signature of an occurrence is needed when we create a JSON for a Cell only. In that case we cannot directly save the transhierarchical informations, so we need a way to characterize the deep Entity (which is not part of the saved Cell). Most of the time, the signature is the scalar attributes of the occurrenced object, it is far from foolproof, but it will do for now.

JSON Parser Support

To enable JSON parsing support for an object, say Point, an associated JsonPoint class must be created. This class must be derived (directly or not) from JsonObject. It must implement one static functions and four methods, as shown below.

class JsonPoint : public JsonObject {
public:
static void initialize ();
JsonPoint (unsigned long flags);
virtual string getTypeName() const;
virtual JsonPoint* clone (unsigned long flags) const;
virtual void toData (JsonStack&);
};

The initialize() static function must be present in concrete class only. It is used to register the Json object into the parser during the static initialization of the program.

#include "hurricane/Initializer.h"
#include "hurricane/Point.h"
Initializer<JsonPoint> jsonPointInit ( 0 );
void JsonPoint::initialize ()
{ JsonTypes::registerType( new JsonPoint (JsonWriter::RegisterMode) ); }

The constructor has to declare requirements, attributes, and collections needed to build the DataBase object. Note the the requirements are not part of the objects but only needed to build it.

JsonPoint::JsonPoint ( unsigned long flags )
: JsonObject(flags)
{
add( "_x", typeid(int64_t) );
add( "_y", typeid(int64_t) );
}

The getTypeName() virtual function must return the typename used for the "@typename" key in the JSON file. Most of the time it's the same name as the object itself, but not always.

string JsonPoint::getTypeName () const
{ return "Point"; }

The clone() virtual function must return a brand new Json object of the same type. The datas of the orignal object must not be copied. The cloning is about the class type, not the contents.

JsonPoint* JsonPoint::clone ( unsigned long flags ) const
{ return new JsonPoint ( flags ); }

The toData() virtual function actually gather the attributes to recreate the DataBase object. It needs the parser stack to pull the attributes and to push the created object.

void JsonPoint::toData ( JsonStack& stack )
{
check( stack, "JsonPoint::toData" );
Point point ( DbU::fromDb(get<int64_t>(stack,"_x"))
, DbU::fromDb(get<int64_t>(stack,"_y")) );
update( stack, point );
}
static Unit fromDb(Unit value)
Definition: DbU.h:163

JSON Array

JSON array are not translated into containers of any kind. They are simply ignored (from the stack point of view). Objects in array comes from a great variety of containers including Hurricane::Collection, in almost all cases, their very constructors are responsibles for inserting the object in the relevant container/collection. So there is no need to build a mechanism to keep track of all the objects in an array through a temporary container.

The corollary is that an object in an array must be able to extract the relevant context information from the stack. Say, if we are in an array of components, they must belong to a Net, which must be present in the stack with a key ".Net".

Parser Stack

While performing the parsing, the parser maintain a stack (JsonStack) containing:

JsonObject Life Cycle

{ # JsonDummy() (1).
"_typename": "Net", # JsonNet() CTOR (2).
"_id": 14622,
"_name": "saccu(0)",
"_isGlobal": false,
"_isExternal": false,
"_isAutomatic": false,
"_type": "LOGICAL",
"_direction": "---- (UNDEFINED)",
"+aliases": [], # JsonNet::toData() (3).
"+componentSet": [
{
"@typename": "RoutingPad",
"_id": 27410,
"_bodyHook": "Contact::AnchorHook.46566",
"_occurrence": {
"@typename": "Occurrence",
"_path": "14720.14976",
"_entity": 3888
},
"+propertySet": []
},
{
"@typename": "RoutingPad",
"_id": 27409,
"_bodyHook": "Contact::AnchorHook.46574",
"_occurrence": {
"@typename": "Occurrence",
"_path": "14654.18564",
"_entity": 4529
},
"+propertySet": []
}
}
} # ~JsonNet() DTOR (4).

At (1) , before _typename is encountered, we know that a new object is about to be created, but do not know what is type will be. So we push on top of the stack a JsonDummy.

At (2) , the _typename allows us to create the right kind of JsonObject, which will replace the JsonDummy on top of the stack.

At (3) , a first non-POD attribute of JsonNet is encountered. This triggers the call to JsonObject::toData(), which creates the Hurricane object Net, and put it back on the attribute stack with the key ".Net" (because it is not an attribute).

At (4) , the Json parser knows that the current JsonObject is finished, so it removes JsonNet from the stack and destroy it.

So, if you need to perform specific post-processing that can only take place after the object and all it's sub-objects has been fully parsed, you may do it in the destructor of the JsonObject. For example, this technique is used to rebuild the rings of a Net.



Generated by doxygen 1.9.1 on Thu Aug 11 2022 Return to top of page
Hurricane VLSI Database Copyright © 2000-2020 Bull S.A. All rights reserved