Design rules

// 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)
        );

}   }