// In order to define the design rules for the router, one
// should specify a RuleSet object. This object has a name,
// an identifier string, a list of attibutes, a list of hard
// rules and a list of soft rules.
// In our case, we define the drc13 RuleSet as follows:
RulesSet drc13 ("drc13",
{
mask1,
mask2,
},
{
metal1_is_hor,
metal2_is_ver,
m1_minimal_length_hor_2,
m2_minimal_length_ver_2,
contacts_imply_m1,
vias_imply_m1,
vias_imply_m2,
contacts_and_vias,
separation_ver_m2,
t_hor,
t_ver,
non_closeness_hor_m1,
non_closeness_ver_m2,
top_is_for_vdd,
bottom_is_for_gnd,
double_pattern_lythography,
},
{
// no soft rules (will simply optimize wire-length)
}
);
// The mask1 and mask2 attributes are used to enforce the
// double pattern lythography properties in the metal 1
// layer. mask1 corresponds to the binary attribute for wires
// in the first mask and mask2 corresponds to the binary
// attribute for wires in the second mask.
Attribute mask1("mask1");
Attribute mask2("mask2");
// Some identifiers are defined for each layer.
#define PolyDiff 0
#define Metal1 1
#define Metal2 2
// Some identifiers are defined for particular signals.
#define GND 0
#define VDD 1
// In order to specify the design rules, we make use of the
// 3d geometric model described in the paper, where each vertex
// is identified with a position (i, j, k) and edges link vertices
// whose distance is exactly one.
//
// i ranges from 0 to ni-1
// j ranges from 0 to nj-1
// k ranges from 0 to nk-1
//
// so that
//
// ni corresponds to the number of rows in the grid,
// nj corresponds to the number of columns in the grid,
// nk corresponds to the number of layers in the grid.
//
// In order to specify edges, the notation (i, j, k, d)
// is used, where i,j,k is a vertex position and d
// is +di, -di, +dj, -dj, +dk or -dk and specifies the
// direction of the edge. For instace (3,2,1,+dk) specifies
// the via between vertex (3,2,1) and vertex (3,2,2).
//
// Rules are written using logical operators (and, or, not, >>)
// on the default binary attributes (signal and wire) and the
// user defined attributes. The >> symbol corresponds to the implication.
// Intermediate expressions can be declared as Contraint variables.
//
// Each hard rule is defined with a HardRule function.
// Rules do not have explicity parameters, but are defined
// for all possible i, j, k variables in the geometry of the grid.
//
// Attributes whose edge do not lie inside the grid are
// conveniently deemed false.
//
// The signal attribute is particular, in the case that it needs
// accepts an extra attribute corresponding to the particular identifier
// of the signal.
/** Horizontal disposition of metal 1. */
HardRule metal1_is_hor () {
if (k == Metal1) {
def(not wire(i, j, k, +di));
} }
/** Vertical disposition of metal 2. */
HardRule metal2_is_ver () {
if (k == Metal2) {
def(not wire(i, j, k, +dj));
} }
/** The top row is just for the vdd signal. */
HardRule top_is_for_vdd () {
if (i == 0) {
def(wire(i, j, k, +di) >> signal(i, j, k, +di, VDD));
def(wire(i, j, k, +dj) >> signal(i, j, k, +dj, VDD));
def(wire(i, j, k, +dk) >> signal(i, j, k, +dk, VDD));
} }
/** The bottow row is just for the gnd signal. */
HardRule bottom_is_for_gnd () {
if (i == ni - 1) {
def(wire(i, j, k, -di) >> signal(i, j, k, -di, GND));
def(wire(i, j, k, +dj) >> signal(i, j, k, +dj, GND));
def(wire(i, j, k, +dk) >> signal(i, j, k, +dk, GND));
} }
/** Rule (d): Horizontal segments in layer 1 must have length >= 2. */
HardRule m1_minimal_length_hor_2 () {
if (k == Metal1) {
def(
wire(i, j, k, +dj) >> (wire(i, j-1, k, +dj) or wire(i, j+1, k, +dj))
);
} }
/** Rule (e): Vertical segments in layer 2 must have length >= 3. */
HardRule m2_minimal_length_ver_3 () {
if (k == Metal2) {
def(
wire(i, j, k, +di)
>> (
(wire(i+1, j, k, +dj) and wire(i+2, j, k, +dj))
or (wire(i-1, j, k, +dj) and wire(i+1, j, k, +dj))
or (wire(i-2, j, k, +dj) and wire(i-1, j, k, +dj))
)
);
} }
/** Rule (c): Contacts and vias. */
HardRule contacts_and_vias () {
if (k == PolyDiff or k == Metal1) {
def(
wire(i, j, k, +dk)
>> ( not wire(i + 1, j, k, +dk)
and not wire(i, j + 1, k, +dk)
and not wire(i + 1, j - 1, k, +dk)
and not wire(i + 1, j + 1, k, +dk)
)
);
} }
/** Contacts imply metal 1 wires. */
HardRule contacts_imply_m1 () {
if (k == PolyDiff) {
def(
wire(i, j, k, +dk)
>>
( wire(i, j, k+1, +di)
or wire(i, j, k+1, -di)
or wire(i, j, k+1, +dj)
or wire(i, j, k+1, -dj)
)
);
} }
/** Vias imply metal 1 wires. */
HardRule vias_imply_m1 () {
if (k == Metal1) {
def(
wire(i, j, k, +dk)
>>
( wire(i, j, k, +di)
or wire(i, j, k, -di)
or wire(i, j, k, +dj)
or wire(i, j, k, -dj)
)
);
} }
/** Vias imply metal 2 wires. */
HardRule vias_imply_m2 () {
if (k == Metal1) {
def(
wire(i, j, k, +dk)
>>
( wire(i, j, k+1, +di)
or wire(i, j, k+1, -di)
or wire(i, j, k+1, +dj)
or wire(i, j, k+1, -dj)
)
);
} }
/** Rule (f): Non-closeness in metal 1. */
HardRule non_closeness_hor_m1 () {
if (k == Metal1) {
def(
(wire(i, j, k, +dj) and wire(i, j+2, k, +dj)) >> wire(i, j+1, k, +dj)
);
} }
/** Non-closeness in metal 2. */
HardRule non_closeness_ver_m2 () {
if (k == Metal1) {
def(
(wire(i, j, k, +di) and wire(i+2, j, k, +di)) >> wire(i+1, j, k, +di)
);
} }
/** Rule (g): Vertical separation in metal 2. */
HardRule separation_ver_m2 () {
if (k == Metal2) {
def(
wire(i, j, k, +di) >>
(not wire(i, j+1, k, +di) and not wire(i-1, j+1, k, +di) and not wire(i+1, j+1, k, +di))
);
} }
/** Rule (b): T-rule about horizontal metals in layer 1. */
HardRule t_hor () {
if (k == Metal1) {
Constraint e1 = wire(i, j + 0, 1, +dj);
Constraint e2 = wire(i, j + 1, 1, +dj);
Constraint e3 = wire(i, j + 2, 1, +dj);
Constraint e4 = wire(i, j + 3, 1, +dj);
Constraint f1 = wire(i - 1, j + 0, 1, +dj);
Constraint f2 = wire(i - 1, j + 1, 1, +dj);
Constraint f3 = wire(i - 1, j + 2, 1, +dj);
Constraint f4 = wire(i - 1, j + 3, 1, +dj);
Constraint g1 = wire(i + 1, j + 0, 1, +dj);
Constraint g2 = wire(i + 1, j + 1, 1, +dj);
Constraint g3 = wire(i + 1, j + 2, 1, +dj);
Constraint g4 = wire(i + 1, j + 3, 1, +dj);
Constraint v1 = wire(i, j + 1, 1, +dk);
Constraint v3 = wire(i, j + 3, 1, +dk);
def(
(e1 and not e2 and not e3 and e4 and (v1 or v3))
>> not (f1 or f2 or f3 or f4 or g1 or g2 or g3 or g4)
);
} }
/** Rule (a): T-rule about vertical metals in layer 2. */
HardRule t_ver () {
if (k == Metal2) {
Constraint m = wire(i, j, 2, +i);
Constraint e1 = wire(i - 2, j - 1, 2, +i);
Constraint e2 = wire(i - 1, j - 1, 2, +i);
Constraint e3 = wire(i - 0, j - 1, 2, +i);
Constraint e4 = wire(i + 1, j - 1, 2, +i);
Constraint e5 = wire(i + 2, j - 1, 2, +i);
Constraint d1 = wire(i - 2, j + 1, 2, +i);
Constraint d2 = wire(i - 1, j + 1, 2, +i);
Constraint d3 = wire(i - 0, j + 1, 2, +i);
Constraint d4 = wire(i + 1, j + 1, 2, +i);
Constraint d5 = wire(i + 2, j + 1, 2, +i);
def(
m >> not (e1 or e2 or e3 or e4 or e5 or d1 or d2 or d3 or d4 or d5 )
);
} }
/** Rule (h): Double pattern lythography. */
HardRule double_pattern_lythography () {
if (k == Metal1) {
def(
(wire(i, j, k, +dj) >> (mask1(i, j, k, +dj) or mask2(i, j, k, +dj)))
and
not (mask1(i, j, k, +dj) and not mask1(i, j+1, k, +dj) and mask1(i, j+2, k, +dj))
and
not (mask2(i, j, k, +dj) and not mask2(i, j+1, k, +dj) and mask2(i, j+2, k, +dj))
and
(mask1(i, j, k, +dj) >> not mask1(i+1, j, k, +dj))
and
(mask1(i, j, k, +dj) >> not mask1(i+1, j+1, k, +dj))
and
(mask1(i, j, k, +dj) >> not mask1(i+1, j-1, k, +dj))
and
(mask2(i, j, k, +dj) >> not mask2(i+1, j, k, +dj))
and
(mask2(i, j, k, +dj) >> not mask2(i+1, j+1, k, +dj))
and
(mask2(i, j, k, +dj) >> not mask2(i+1, j-1, k, +dj))
);
} else {
def(
not mask1(i, j, k, +di)
and not mask1(i, j, k, +dj)
and not mask1(i, j, k, +dk)
and not mask2(i, j, k, +di)
and not mask2(i, j, k, +dj)
and not mask2(i, j, k, +dk)
);
} }