Exemplo n.º 1
0
def make_hcs_3d_scaled (a, b, c):
    """build a 3D homogeneus coordiate system from three points, and derive scale from distance between points"""
     # create orthonormal basis 
    u = normalised(b-a)
    v = normalised(c-a)
    nu = vector.norm(u)
    nv = vector.norm(v)
    if tol_eq(nu,0) and tol_eq(nv,0):
        # all points equal, no rotation
        u = vector.vector([1.0,0.0,0.0])
        v = vector.vector([0.0,1.0,0.0])
    elif tol_eq(nu, 0):
        # determine u perpendicular from v
        u,dummy = perp_3d(v)[0]
    elif tol_eq(nv, 0):
        # determine v perpendicular from u
        dummy,v = perp_3d(u)[0]
    # make the basis vectors orthogonal
    w = vector.cross(u,v)
    v = vector.cross(w,u)
    # scale again
    if not tol_eq(vector.norm(b-a),0.0):
        u = u / vector.norm(b-a)
    if not tol_eq(vector.norm(c-a),0.0):
        v = v / vector.norm(c-a)
    # note: w is not scaled
    # create matix with basis vectors + translation as columns
    hcs = Mat([ 
        [u[0],v[0], w[0], a[0]], 
        [u[1],v[1], w[1], a[1]],
        [u[2],v[2], w[2], a[2]], 
        [0.0, 0.0, 0.0, 1.0]    ])
    return hcs 
Exemplo n.º 2
0
def make_hcs_3d (a, b, c, righthanded=True):
    """build a 3D homogeneous coordiate system from three points. The origin is point a. The x-axis is
    b-a, the y axis is c-a, or as close as possible after orthogonormalisation."""
    # create orthonormal basis 
    u = normalised(b-a)
    v = normalised(c-a)
    nu = vector.norm(u)
    nv = vector.norm(v)
    if tol_eq(nu,0.0) and tol_eq(nv,0.0):
        # all points equal, no rotation
        u = vector.vector([1.0,0.0,0.0])
        v = vector.vector([0.0,1.0,0.0])
    elif tol_eq(nu, 0.0):
        # determine u perpendicular from v
        u,dummy = perp_3d(v)
    elif tol_eq(nv, 0.0):
        # determine v perpendicular from u
        dummy,v = perp_3d(u)
    # ensure that u and v are different
    if tol_eq(vector.norm(u-v),0.0):
        dummy,v = perp_3d(u)
    # make the basis vectors orthogonal
    w = vector.cross(u,v)
    v = vector.cross(w,u)
    # flip basis if lefthanded desired
    if righthanded==False:
        w = -w
    # create matix with basis vectors + translation as columns
    hcs = Mat([ 
        [u[0],v[0], w[0], a[0]], 
        [u[1],v[1], w[1], a[1]],
        [u[2],v[2], w[2], a[2]], 
        [0.0, 0.0, 0.0, 1.0]    ])
    return hcs 
Exemplo n.º 3
0
def cc_int(p1, r1, p2, r2):
    """
    Intersect circle (p1,r1) circle (p2,r2)
    where p1 and p2 are 2-vectors and r1 and r2 are scalars
    Returns a list of zero, one or two solution points.
    """
    d = vector.norm(p2-p1)
    if not tol_gt(d, 0):
        return []
    u = ((r1*r1 - r2*r2)/d + d)/2
    if tol_lt(r1*r1, u*u):
        return []
    elif r1*r1 < u*u:
        v = 0.0
    else:
        v = math.sqrt(r1*r1 - u*u)
    s = (p2-p1) * u / d
    if tol_eq(vector.norm(s),0):
        p3a = p1+vector.vector([p2[1]-p1[1],p1[0]-p2[0]])*r1/d
        if tol_eq(r1/d,0):
            return [p3a]
        else:
            p3b = p1+vector.vector([p1[1]-p2[1],p2[0]-p1[0]])*r1/d
            return [p3a,p3b]
    else:
        p3a = p1 + s + vector.vector([s[1], -s[0]]) * v / vector.norm(s) 
        if tol_eq(v / vector.norm(s),0):
            return [p3a]
        else:
            p3b = p1 + s + vector.vector([-s[1], s[0]]) * v / vector.norm(s)
            return [p3a,p3b]
Exemplo n.º 4
0
    def __getitem__(self, i):
        """This operation returns either a single value or a subview. Examples:

          >>> m = matrix(array=[[1.,2.,3.],[4.,5.,6.],[7.,8.,9.]])
          >>> m[1]         # row 1
          vector(dtype=float64, shape=(3), data=[4.,5.,6.])
          >>> m[:,1]       # column 1
          vector(dtype=float64, shape=(3), data=[2.,5.,8.])
          >>> m[0,0]       # element (0,0)
          1.0
          >>> m[0:2,0:3:2] # a submatrix
          matrix(dtype=float64, shape=(2,2)
            [[1.0, 3.0],
             [4.0, 6.0]])
        """

        if type(i) != tuple:
            # must be a row accessor
            if isinstance(i, slice):
                return matrix(block=_block.subblock(self.block, (i,slice(0,None))))
            else:
                return vector(block=self.block.row(i))
        assert len(i) == 2
        if isinstance(i[0], slice) and isinstance(i[1], slice):
            return matrix(block=_block.subblock(self.block, i))
        elif isinstance(i[0], slice):
            return vector(block=_block.subblock(self.block.col(i[1]), (i[0],)))
        elif isinstance(i[1], slice):
            return vector(block=_block.subblock(self.block.row(i[0]), (i[1],)))
        else:
            return self.block.get(i[0], i[1])
 def think(self, others):
     '''
     When the leader is user controlled the leader uses the same seek target logic as without user control.
         The target to be sought to is set in the direction desired by user.
     When the leader is not user controlled the seek target moves using self.seek_offset_speed.
         The position of seek target and self.seek_offset_speed
         is randomized at regular interval or when the leader gets too close to the seek target.
     '''
     if self.user_controlled:
         direction = vector(0, 0)
         if self.user_up: direction.y-= 100
         if self.user_down: direction.y+= 100
         if self.user_left: direction.x-= 100
         if self.user_right: direction.x+= 100
         self.current_seek_target = self.pos + direction
     else:
         distance = self.current_seek_target - self.pos
         if distance.lenght < 10.0 or random.randint(0, 300) == 0:
             self.current_seek_target = self.pos + vector(random.uniform(-50, 50), random.uniform(-50, 50))
             self.randomizeSeekOffsetSpeed()
         else:
             self.seek_offset_speed+= vector(random.uniform(-0.3, 0.3), random.uniform(-0.3, 0.3))
             self.seek_offset_speed.clamp(0, 2.5)
             self.current_seek_target+= self.seek_offset_speed
     #go, seek!
     self.seekTraget(self.current_seek_target, 1.0)
     
     
Exemplo n.º 6
0
 def __init__(self, obj, **kwargs):
     super(Physics, self).__init__(obj, **kwargs)
     self.velocity = vector(0,0)
     self.rect = pygame.Rect(0,0,30,30)
     self.corners = (vector(0,0), vector(0,30), vector(30,30), vector(30,0))
     #self.corners = (vector(16,16),)
     self.attached = None
     self.gravity = 1.0
Exemplo n.º 7
0
def test_sss_degen():
    p1 = vector.vector([0.0, 0.0, 0.0])
    p2 = vector.vector([2.0, 0.0, 0.0])
    p3 = vector.vector([1.0, 0.0, 0.0])
    r1 = 2.0
    r2 = 2.0
    r3 = math.sqrt(3)
    print sss_int(p1,r1,p2,r2,p3,r3)
Exemplo n.º 8
0
def make_hcs_2d_scaled (a, b):
    """build a 2D homogeneus coordiate system from two points, but scale with distance between input point"""
    u = b-a
    if tol_eq(vector.norm(u), 0.0):     
        u = vector.vector([1.0,0.0])
    #else:
    #    u = u / vector.norm(u)
    v = vector.vector([-u[1], u[0]])
    hcs = Mat([ [u[0],v[0],a[0]] , [u[1],v[1],a[1]] , [0.0, 0.0, 1.0] ] )
    return hcs 
Exemplo n.º 9
0
def make_hcs_2d (a, b):
    """build a 2D homogeneus coordiate system from two points"""
    u = b-a
    if tol_eq(vector.norm(u), 0.0):
        u = vector.vector([0.0,0.0])
    else:
        u = u / vector.norm(u)
    v = vector.vector([-u[1], u[0]])
    hcs = Mat([ [u[0],v[0],a[0]] , [u[1],v[1],a[1]] , [0.0, 0.0, 1.0] ] )
    return hcs 
Exemplo n.º 10
0
 def bounce(self, direction):
     if self['Physics'].velocity.dot(direction) < 0:
         #reflect
         u = direction.normal()
         v = direction
         t = vector(self['Physics'].velocity.dot(u), -self['Physics'].velocity.dot(v))
         self['Physics'].velocity = vector(t.x * u.x + t.y * v.x, t.x * u.y + t.y * v.y) 
         self['Physics'].velocity += direction * self.movement.speed_bonus
     else:
         self['Physics'].velocity += direction * self.movement.speed_bonus
Exemplo n.º 11
0
def trilaterate(u, v, r1, r2):
    P1 = vector(u)
    P2 = vector(v)
    ex = (P2 - P1) / abs(P2 - P1)
    d = abs(P2 - P1)
    x = (r1 ** 2 - r2 ** 2 + d ** 2)/(2 * d)
    y1 = math.sqrt(r1 ** 2 - x ** 2)
    y2 = -y1
    p1 = P1 + x * ex + y1
    p2 = P1 + x * ex + y2
    return [p1, p2]
Exemplo n.º 12
0
def problem102():
	count = 0
	zero = vector(0,0)
	with open('Problem102.txt','r') as data:
		for l in data.readlines():
			x0,x1,y0,y1,z0,z1 = l.split(',')
			X, Y, Z = vector(x0,x1),vector(y0,y1),vector(z0,z1)
			# Computes the area of each of the possible inner trianle and compares it to the area of the centre
			if area(X,Y,Z) == area(X,Y,zero) + area(X,zero,Z) + area(zero,Y,Z):
				count += 1
	#return all(orthogonalIntersection(v,w, vector(0,0)) for v,w in combinations([X,Y,Z],2))
	return count
Exemplo n.º 13
0
def sss_int(p1, r1, p2, r2, p3, r3):
    """Intersect three spheres, centered in p1, p2, p3 with radius r1,r2,r3 respectively. 
       Returns a list of zero, one or two solution points.
    """
    solutions = []
    # intersect circles in plane
    cp1 = vector.vector([0.0,0.0]) 
    cp2 = vector.vector([vector.norm(p2-p1), 0.0])
    cpxs = cc_int(cp1, r1, cp2, r2)
    if len(cpxs) == 0:
        return []
    # determine normal of plane though p1, p2, p3
    n = vector.cross(p2-p1, p3-p1)
    if not tol_eq(vector.norm(n),0.0):  
        n = n / vector.norm(n)
    else:
        # traingle p1, p2, p3 is degenerate
        # check for 2d solutions
        if len(cpxs) == 0:
            return []
        # project cpxs back to 3d and check radius r3 
        cp4 = cpxs[0]
        u = normalised(p2-p1)
        v,w = perp_3d(u)
        p4 = p1 + cp4[0] * u + cp4[1] * v
        if tol_eq(vector.norm(p4-p3), r3):
            return [p4]
        else:
            return []
    # px, rx, nx is circle 
    px = p1 + (p2-p1) * cpxs[0][0] / vector.norm(p2-p1)
    rx = abs(cpxs[0][1])
    nx = p2-p1
    nx = nx / vector.norm(nx)
    # py is projection of p3 on px,nx
    dy3 = vector.dot(p3-px, nx)
    py = p3 - (nx * dy3)
    if tol_gt(dy3, r3):
        return []
    # ry is radius of circle in py
    if tol_eq(r3,0.0):
        ry = 0.0 
    else:   
        ry = math.sin(math.acos(min(1.0,abs(dy3/r3))))*r3
    # determine intersection of circle px, rx and circle py, ry, projected relative to line py-px 
    cpx = vector.vector([0.0,0.0]) 
    cpy = vector.vector([vector.norm(py-px), 0.0])
    cp4s = cc_int(cpx, rx, cpy, ry)
    for cp4 in cp4s:
        p4 = px + (py-px) * cp4[0] / vector.norm(py-px) + n * cp4[1] 
        solutions.append(p4)  
    return solutions
Exemplo n.º 14
0
def eye(n, d=None):
    """ Creates an identity TT-matrix"""
    c = _matrix.matrix()
    c.tt = _vector.vector()
    if d is None:
        n0 = _np.asanyarray(n, dtype=_np.int32)
        c.tt.d = n0.size
    else:
        n0 = _np.asanyarray([n] * d, dtype=_np.int32)
        c.tt.d = d
    c.n = n0.copy()
    c.m = n0.copy()
    c.tt.n = (c.n) * (c.m)
    c.tt.r = _np.ones((c.tt.d + 1,), dtype=_np.int32)
    c.tt.get_ps()
    c.tt.alloc_core()
    for i in xrange(c.tt.d):
        c.tt.core[
            c.tt.ps[i] -
            1:c.tt.ps[
                i +
                1] -
            1] = _np.eye(
            c.n[i]).flatten()
    return c
Exemplo n.º 15
0
def mkron(a, *args):
    """Kronecker product of all the arguments"""
    if not isinstance(a, list):
        a = [a]
    a = list(a)  # copy list
    for i in args:
        if isinstance(i, list):
            a.extend(i)
        else:
            a.append(i)

    c = _vector.vector()
    c.d = 0
    c.n = _np.array([], dtype=_np.int32)
    c.r = _np.array([], dtype=_np.int32)
    c.core = []

    for t in a:
        thetensor = t.tt if isinstance(t, _matrix.matrix) else t
        c.d += thetensor.d
        c.n = _np.concatenate((c.n, thetensor.n))
        c.r = _np.concatenate((c.r[:-1], thetensor.r))
        c.core = _np.concatenate((c.core, thetensor.core))

    c.get_ps()
    return c
Exemplo n.º 16
0
def random_problem_2D(numpoints, radius=10.0, roundoff=0.0, angleratio=0.5):
    """Generate a random problem with given number of points, a roundoff
       value for the prototype points, a radius for the cloud of prototype points
       and a ratio of angle constraints over distance constraints"""
    group = {}
    problem = GeometricProblem(dimension=2)
    i = 0
    while i < numpoints:
        aname = 'p'+str(i)
        apoint = vector([
            _round(random.uniform(-radius,radius),roundoff),
            _round(random.uniform(-radius,radius),roundoff)
        ])
        unique = True
        for v in group:
            p = group[v]
            if tol_eq(apoint[0],p[0]) and tol_eq(apoint[1],p[1]):
                unique = False
                break
        if unique:
                problem.add_point(aname, apoint)
                group[aname] = apoint
                i = i + 1
    #next
    _constraint_group(problem, group, None, angleratio)
    return problem
Exemplo n.º 17
0
 def __matmul__(self, other):
     """
     Multiplication of two TT-matrices
     """
     diff = len(self.n) - len(other.m)
     L = self if diff >= 0 else _tools.kron(self, matrix(_tools.ones(1, abs(diff))))
     R = other if diff <= 0 else _tools.kron(other, matrix(_tools.ones(1, abs(diff))))
     c = matrix()
     c.n = L.n.copy()
     c.m = R.m.copy()
     res = _vector.vector()
     res.d = L.tt.d
     res.n = c.n * c.m
     if L.is_complex or R.is_complex:
         res.r = _core_f90.core.zmat_mat(
             L.n, L.m, R.m, _np.array(
                 L.tt.core, dtype=_np.complex), _np.array(
                 R.tt.core, dtype=_np.complex), L.tt.r, R.tt.r)
         res.core = _core_f90.core.zresult_core.copy()
     else:
         res.r = _core_f90.core.dmat_mat(
             L.n, L.m, R.m, _np.real(
                 L.tt.core), _np.real(
                 R.tt.core), L.tt.r, R.tt.r)
         res.core = _core_f90.core.result_core.copy()
     _core_f90.core.dealloc()
     res.get_ps()
     c.tt = res
     return c
Exemplo n.º 18
0
def intersectionOfTwoLines(p1,p2,p3,p4):
	''' The intersetion of the two lines spanned by p1,p2 and by p3,p4'''
	x1,y1,x2,y2,x3,y3,x4,y4 = p1.x,p1.y,p2.x,p2.y,p3.x,p3.y,p4.x,p4.y
	denominator = (x1 - x2)*(y3-y4) - (y1-y2)*(x3-x4)
	numeratorx = (x1*y2 - y1*x2)*(x3-x4) - (x1 - x2)*(x3*y4 - y3*x4)
	numeratory = (x1*y2 - y1*x2)*(y3-y4) - (y1 - y2)*(x3*y4 - y3*x4)
	return vector(numeratorx,numeratory)/denominator
Exemplo n.º 19
0
 def __init__(self, x, y, max_speed = -1, max_force = -1, size = -1, random_position = True):
     '''
     x and y should be the window dimensions when random_position is True.
     '''
     if random_position: self.pos = vector(random.uniform(0, x), random.uniform(0, y))
     else: self.pos = vector(x, y)
     self.speed = vector(0, 0)
     if max_speed > 0: self.max_speed = max_speed
     else: self.randomizeMaxSpeed()
     self.current_force = vector(0, 0)
     if max_force > 0: self.max_force = max_force
     else: self.randomizeMaxForce()
     if size > 0: self.size = size
     else: self.randomizeSize()
     #This is used for drawing
     self.last_seek_target = vector(0, 0)
Exemplo n.º 20
0
def improvisedTrilateration(x1, y1, d1, x2,y2,d2, x3,y3,d3):
    p1 = vector.vector()
    p1.append(x1)
    p1.append(y1)

    p2 = vector.vector()
    p2.append(x2)
    p2.append(y2)

    p3 = vector.vector()
    p3.append(x3)
    p3.append(y3)
    a = cc_int(p1, d1, p2, d2)
    b = cc_int(p2, d2, p3, d3)
    c = cc_int(p3, d3, p1, d1)
    return centerFinder(a,b,c)
Exemplo n.º 21
0
def transform_point(point, transform):
    """transform a point"""
    hpoint = Vec(point)
    hpoint.append(1.0)
    hres = transform.mmul(hpoint)
    res = vector.vector(hres[0:-1]) / hres[-1]
    return res
Exemplo n.º 22
0
 def __init__(self, obj, **kwargs):
     super(Player, self).__init__(obj)
     self.movement = movement.Momentum()
     self.size = vector(32, 32)
     self.image = pygame.transform.scale(resource.get('characters')[0][0], self.size)
     self.keys = {}
     self.new_keys = set()
     print 'instantiated player'
Exemplo n.º 23
0
def quarilaterate(u, v, w, r1, r2, r3):
    P1 = vector(u)
    P2 = vector(v)
    P3 = vector(w)
    ex = (P2 - P1) / abs(P2 - P1)
    i = ex * (P3 - P1)
    ey = (P3 - P1 - i * ex) / abs(P3 - P1 - i * ex)
    d = abs(P2 - P1)
    j = ey * (P3 - P1)
    x = (r1 ** 2 - r2 ** 2 + d ** 2)/(2 * d)
    y = (r1 ** 2 - r3 ** 2 - x ** 2 + (i + x) ** 2 + j ** 2) / 2 * j
    ez = ex ^ ey
    z1 = math.sqrt(r1 ** 2 - x ** 2 - y ** 2)
    z2 = -z1
    p1 = P1 + x * ex + y * ey + z1 * ez
    p2 = P1 + x * ex + y * ey + z2 * ez
    return [p1, p2]
Exemplo n.º 24
0
def plocket_pla(d,limit):
	w = vector(5)
	updated = True
	n = len(d.input_vectors)
	w_pocket = vector(5)
	#for i in range(limit):
	count = 0
	while count < limit:
		index = random.randint(0,n-1)
		if(not verify(d,w,index)):
			w = update(d,w,index)
			count = count + 1
			if(error_count(d,w) < error_count(d,w_pocket)):
				w_pocket  = w
		if(error_count(d,w) ==0 ):
			break
	return w_pocket
Exemplo n.º 25
0
def is_counterclockwise(p1,p2,p3):
    """ returns True iff triangle p1,p2,p3 is counterclockwise oriented"""
    assert len(p1)==2
    assert len(p1)==len(p2)
    assert len(p2)==len(p3)   
    u = p2 - p1
    v = p3 - p2;
    perp_u = vector.vector([-u[1], u[0]])
    return tol_gt(vector.dot(perp_u,v), 0)
Exemplo n.º 26
0
def concatenate(*args):
    """Concatenates given TT-vectors.

    For two tensors :math:`X(i_1,\\ldots,i_d),Y(i_1,\\ldots,i_d)` returns :math:`(d+1)`-dimensional
    tensor :math:`Z(i_0,i_1,\\ldots,i_d)`, :math:`i_0=\\overline{0,1}`, such that

    .. math::
       Z(0, i_1, \\ldots, i_d) = X(i_1, \\ldots, i_d),

       Z(1, i_1, \\ldots, i_d) = Y(i_1, \\ldots, i_d).

    """
    tmp = _np.array([[1] + [0] * (len(args) - 1)])
    result = kron(_vector.vector(tmp), args[0])
    for i in range(1, len(args)):
        result += kron(_vector.vector(_np.array([[0] * i +
                                         [1] + [0] * (len(args) - i - 1)])), args[i])
    return result
Exemplo n.º 27
0
 def __init__(self, **kwargs):
     dict.__init__(self)
     
     # Set the default attributes
     self['radius']  = 1.0
     self['axis']    = vector(1,0,0, record=False) # Don't log the creation of these vectors
     self['color']   = color.white
     self['opacity'] = 1.0
     self['pos']     = vector(0,0,0, record=False)
     self['up']      = vector(0,1,0,record=False)
     self['x']       = 0.0
     self['y']       = 0.0
     self['z']       = 0.0
     
     for key in kwargs:
         setattr(self, key, kwargs[key])
     
     log.debug("create", extra={'class':'sphere', 'object':self, 'keywords':kwargs})
Exemplo n.º 28
0
 def move(self):
     '''
     This function actually moves this thinker to a new position
         using self.current_force that should be the desired force.
     '''
     self.current_force.clamp(0, self.max_force)
     self.speed+= self.current_force
     self.speed.clamp(0, self.max_speed)
     self.pos+= self.speed
     self.current_force = vector(0, 0)
Exemplo n.º 29
0
 def __next_step(self, matr_m, matr, vect, cur_approx, t):
   """In this func: from M*(x(k+1)-x(k))/t(k+1) + Ax(k) = b
                    to x(k+1) = t(k+1)b - t(k + 1)Ax(k) + x(k)"""
   next_approx = vector(vect)
   next_approx.mult_by_number(t)
   next_approx.add(cur_approx)
   matr_a = matr.multiply(cur_approx)
   matr_a.mult_by_number(t)
   next_approx.add(matr_a)
   return next_approx
Exemplo n.º 30
0
    def __init__(self, **kwargs):
        dict.__init__(self)
        # Set default attributes
        
        self['fixedwidth'] = False
        self['headlength'] = 0.3
        self['headwidth']  = 0.2
        self['length']     = 1.0
        self['shaftwidth'] = 0.1
        self['axis']       = vector(1,0,0, record=False)
        self['color']      = color.white
        self['opacity']    = 1.0
        self['pos']        = vector(0,0,0, record=False)
        self['up']         = vector(0,1,0, record=False)

        for key in kwargs:
            setattr(self, key, kwargs[key])
            
        log.debug("create", extra={'class':'arrow', 'object':self, 'keywords':kwargs})
Exemplo n.º 31
0
    def add_modules(self):
        """ Add all of the module instances in the logical netlist """
        # This is the threshold detect inverter on the output of the RBL
        self.rbl_inv_inst = self.add_inst(name="rbl_inv",
                                          mod=self.inv,
                                          offset=self.rbl_inv_offset +
                                          vector(0, self.inv.width),
                                          rotate=270,
                                          mirror="MX")
        self.connect_inst(["bl[0]", "out", "vdd", "gnd"])

        self.tx_inst = self.add_inst(name="rbl_access_tx",
                                     mod=self.access_tx,
                                     offset=self.access_tx_offset,
                                     rotate=90)
        # D, G, S, B
        self.connect_inst(["vdd", "delayed_en", "bl[0]", "vdd"])
        # add the well and poly contact

        self.dc_inst = self.add_inst(name="delay_chain",
                                     mod=self.delay_chain,
                                     offset=self.delay_chain_offset,
                                     rotate=90)
        self.connect_inst(["en", "delayed_en", "vdd", "gnd"])

        self.rbc_inst = self.add_inst(name="bitcell",
                                      mod=self.replica_bitcell,
                                      offset=self.bitcell_offset,
                                      mirror="MX")
        self.connect_inst(["bl[0]", "br[0]", "delayed_en", "vdd", "gnd"])

        self.rbl_inst = self.add_inst(name="load",
                                      mod=self.rbl,
                                      offset=self.rbl_offset)
        self.connect_inst(["bl[0]", "br[0]"] + ["gnd"] * self.rows +
                          ["vdd", "gnd"])
Exemplo n.º 32
0
    def add_decoder_inv_array(self):
        """Add a column of INV gates for the decoder above the predecoders
        and to the right of the NAND decoders."""

        z_pin = self.inv.get_pin("Z")

        if (self.num_inputs == 4 or self.num_inputs == 5):
            x_off = self.routing_width + self.nand2.width
        else:
            x_off = self.routing_width + self.nand3.width

        self.inv_inst = []
        for row in range(self.rows):
            name = "DEC_INV_[{0}]".format(row)
            if (row % 2 == 0):
                inv_row_height = self.inv.height * row
                mirror = "R0"
                y_dir = 1
            else:
                inv_row_height = self.inv.height * (row + 1)
                mirror = "MX"
                y_dir = -1
            y_off = self.predecoder_height + inv_row_height
            offset = vector(x_off, y_off)

            self.inv_inst.append(
                self.add_inst(name=name,
                              mod=self.inv,
                              offset=offset,
                              mirror=mirror))

            # This will not check that the inst connections match.
            self.connect_inst(args=[
                "Z[{0}]".format(row), "decode[{0}]".format(row), "vdd", "gnd"
            ],
                              check=False)
Exemplo n.º 33
0
    def route_input_gate_B(self):
        """  routing for input B """
        xoffset = self.pmos2.poly_positions[0].x \
            + self.pmos_position2.x - drc["minwidth_poly"]
        yoffset = self.nmos_position1.y + self.nmos1.height \
            - drc["well_enclosure_active"] + (self.nmos1.active_contact.height \
                                                       - self.nmos1.active_height) / 2 \
                                                       + drc["metal1_to_metal1"]
        self.add_contact(layers=("poly", "contact", "metal1"),
                         offset=[xoffset,yoffset])
        self.add_via(layers=("metal1", "via1", "metal2"),
                     offset=[xoffset,yoffset])

        xoffset = self.pmos2.poly_positions[0].x + self.pmos_position2.x \
            - drc["minwidth_poly"] + self.m1m2_via.width
        length = -xoffset + self.m1m2_via.width
        self.add_rect(layer="metal2",
                      offset=[xoffset, yoffset],
                      width=length,
                      height=-drc["minwidth_metal2"])

        self.B_position = vector(0, yoffset - drc["minwidth_metal1"])
        self.add_label(text="B",
                       layer="metal1",
                       offset=self.B_position)

        xoffset = self.pmos_position1.x + self.pmos1.active_position.x \
            - drc["metal1_to_metal1"] + (self.pmos1.active_contact.width \
                                             - self.m1m2_via.second_layer_width) / 2
        self.add_via(layers=("metal1", "via1", "metal2"),
                     offset=[xoffset,yoffset - drc["minwidth_metal2"]],
                     rotate=90)
        self.add_rect(layer="metal1",
                      offset=[xoffset, yoffset],
                      width=-xoffset,
                      height=-drc["minwidth_metal1"])
Exemplo n.º 34
0
 def multiply(self, multiplier):
     error_msg = ('Number of columns in first matrix must be equal '
                  'number of rows in second multiplier(matrix/vector)')
     result = []
     if type(multiplier) == matrix:
         if self.cnt_col() != multiplier.cnt_row():
             raise Exception(error_msg)
         for row in range(self.cnt_row()):
             result.append([])
             for col in range(multiplier.cnt_col()):
                 result[row].append(0)
                 for step in range(self.cnt_col()):
                     result[row][col] += self.get(
                         row, step) * multiplier.get(step, col)
         return matrix(result)
     elif type(multiplier) == vector:
         if self.cnt_col() != multiplier.size():
             raise Exception(error_msg)
         for row in range(self.cnt_row()):
             result.append(0)
             for col in range(self.cnt_col()):
                 result[row] += self.get(row,
                                         col) * multiplier.get_elem(col)
         return vector(result)
Exemplo n.º 35
0
    def setup_layout_constants(self):
        """ Pre-compute some handy layout parameters. """

        poly_contact = contact.contact(("poly", "contact", "metal1"))
        m1m2_via = contact.contact(("metal1", "via1", "metal2"))
        m2m3_via = contact.contact(("metal2", "via2", "metal3"))

        # metal spacing to allow contacts on any layer
        self.input_spacing = max(
            self.poly_space + poly_contact.first_layer_width,
            self.m1_space + m1m2_via.first_layer_width,
            self.m2_space + m2m3_via.first_layer_width,
            self.m3_space + m2m3_via.second_layer_width)

        # Compute the other pmos2 location, but determining offset to overlap the
        # source and drain pins
        self.overlap_offset = self.pmos.get_pin("D").ll() - self.pmos.get_pin(
            "S").ll()

        # Two PMOS devices and a well contact. Separation between each.
        # Enclosure space on the sides.
        self.well_width = 2*self.pmos.active_width + self.pmos.active_contact.width \
                          + 2*drc["active_to_body_active"] + 2*drc["well_enclosure_active"]

        self.width = self.well_width
        # Height is an input parameter, so it is not recomputed.

        # This will help with the wells
        self.well_pos = vector(0, 0.4 * self.height)

        # This is the extra space needed to ensure DRC rules to the active contacts
        extra_contact_space = max(-self.nmos.get_pin("D").by(), 0)
        # This is a poly-to-poly of a flipped cell
        self.top_bottom_space = max(
            0.5 * self.m1_width + self.m1_space + extra_contact_space,
            drc["poly_extend_active"], self.poly_space)
Exemplo n.º 36
0
    def add_layout_pins(self):

        # input is A pin of first inverter
        a_pin = self.driver_inst_list[0].get_pin("A")
        self.add_via_stack_center(from_layer=a_pin.layer,
                                  to_layer="m2",
                                  offset=a_pin.center())
        self.add_layout_pin(text="in",
                            layer="m2",
                            offset=a_pin.ll().scale(1, 0),
                            height=a_pin.cy())

        # output is A pin of last load inverter
        last_driver_inst = self.driver_inst_list[-1]
        a_pin = self.load_inst_map[last_driver_inst][-1].get_pin("A")
        self.add_via_stack_center(from_layer=a_pin.layer,
                                  to_layer="m2",
                                  offset=a_pin.center())
        mid_point = vector(a_pin.cx() + 3 * self.m2_width, a_pin.cy())
        self.add_path("m2", [a_pin.center(), mid_point, mid_point.scale(1, 0)])
        self.add_layout_pin_segment_center(text="out",
                                           layer="m2",
                                           start=mid_point,
                                           end=mid_point.scale(1, 0))
Exemplo n.º 37
0
    def __init__(self,
                 layer_stack,
                 dimensions=[1, 1],
                 implant_type=None,
                 well_type=None):
        if implant_type or well_type:
            name = "{0}_{1}_{2}_{3}x{4}_{5}{6}".format(
                layer_stack[0], layer_stack[1], layer_stack[2], dimensions[0],
                dimensions[1], implant_type, well_type)
        else:
            name = "{0}_{1}_{2}_{3}x{4}".format(layer_stack[0], layer_stack[1],
                                                layer_stack[2], dimensions[0],
                                                dimensions[1])

        design.design.__init__(self, name)
        debug.info(4, "create contact object {0}".format(name))

        self.layer_stack = layer_stack
        self.dimensions = dimensions
        self.offset = vector(0, 0)
        self.implant_type = implant_type
        self.well_type = well_type
        self.pins = []  # used for matching parm lengths
        self.create_layout()
Exemplo n.º 38
0
    def add_horizontal_trunk_route(self, pins, trunk_offset, layer_stack,
                                   pitch):
        """
        Create a trunk route for all pins with  the trunk located at the given y offset. 
        """
        max_x = max([pin.center().x for pin in pins])
        min_x = min([pin.center().x for pin in pins])

        # if we are less than a pitch, just create a non-preferred layer jog
        if max_x - min_x <= pitch:

            half_layer_width = 0.5 * drc["minwidth_{0}".format(
                self.vertical_layer)]

            # Add the horizontal trunk on the vertical layer!
            self.add_path(self.vertical_layer, [
                vector(min_x - half_layer_width, trunk_offset.y),
                vector(max_x + half_layer_width, trunk_offset.y)
            ])

            # Route each pin to the trunk
            for pin in pins:
                # No bend needed here
                mid = vector(pin.center().x, trunk_offset.y)
                self.add_path(self.vertical_layer, [pin.center(), mid])
        else:
            # Add the horizontal trunk
            self.add_path(
                self.horizontal_layer,
                [vector(min_x, trunk_offset.y),
                 vector(max_x, trunk_offset.y)])
            trunk_mid = vector(0.5 * (max_x + min_x), trunk_offset.y)

            # Route each pin to the trunk
            for pin in pins:
                mid = vector(pin.center().x, trunk_offset.y)
                self.add_path(self.vertical_layer, [pin.center(), mid])
                self.add_via_center(layers=layer_stack, offset=mid)
Exemplo n.º 39
0
    def route_ctrl_en_gate(self):
        """ Routing pins to modules input and output"""

        #route the "ack" input to ctrl_latch gate
        pos1 = (self.ack_xoff + self.via_shift("co"),
                self.ctrl_en_inst.get_pin("Gn0").lc().y)
        pos2 = self.ctrl_en_inst.get_pin("Gn0").lc()
        self.add_path("poly", [pos1, pos2])

        pin = self.ctrl_en_inst.get_pin("Gp0")
        self.co_shift = vector(contact.poly.height, -contact.poly.width)
        off = vector(self.ack_xoff, pin.lc().y) + self.co_shift
        self.add_contact(self.poly_stack, off, rotate=90)

        self.shift = vector(contact.m1m2.height - self.via_shift("v1"),
                            -contact.poly.width + self.via_co_shift)
        off = vector(self.ack_xoff, pin.lc().y) + self.shift
        self.add_via(self.m1_stack, off, rotate=90)

        self.min_area_shift = 0.5 * contact.m1m2.width + self.via_co_shift
        off = (self.ack_xoff, pin.lc().y - self.min_area_shift)
        self.add_metal_minarea("metal1", off)

        #route the "clk" input to ctrl_latch gate
        pin = self.ctrl_en_inst.get_pin("Gp1")
        self.add_path("poly",
                      [(self.clk_xoff + self.via_shift("co"), pin.lc().y),
                       pin.lc()])

        off = vector(self.clk_xoff, pin.lc().y) + self.co_shift
        self.add_contact(self.poly_stack, off, rotate=90)

        off = vector(self.clk_xoff, pin.lc().y) + self.shift
        self.add_via(self.m1_stack, off, rotate=90)

        off = (self.clk_xoff, pin.lc().y - self.min_area_shift)
        self.add_metal_minarea("metal1", off)

        self.add_path("metal1", [
            self.ctrl_en_inst.get_pin("Dn0").uc(),
            self.ctrl_en_inst.get_pin("Dp1").lc()
        ])
Exemplo n.º 40
0
    def cal_modules_offset(self):
        pinv_error_offset = 0.025
        # leave some room for metal1 routing
        margin = 3 * drc["minwidth_metal1"]
        # witdth + min_spacing of M1 & M2
        m1rail_space = drc["minwidth_metal1"] + drc["metal1_to_metal1"]
        m2rail_space = drc["minwidth_metal2"] + drc["metal2_to_metal2"]
        # leave some margin as bit cell layout exceeds its own orgin
        route_margin = 8 * m2rail_space
        well_margin = 2 * drc["pwell_enclose_nwell"]
        bitcell_array_spacing = max(route_margin, well_margin)
        # now extra space for BL and WL of RBC
        gnd_route_margin = 5 * m2rail_space

        y_off = (self.inv.height * 2 + pinv_error_offset +
                 max(drc["pwell_enclose_nwell"], m1rail_space * 4))
        self.delay_chain_offset = vector(self.delay_chain.height, y_off)
        self.en_input_offset = vector(0, y_off - m2rail_space)
        self.en_nor_offset = vector(self.nor.width + margin,
                                    self.inv.height * 2)
        self.BL_inv_offset = vector(self.en_nor_offset.x - self.inv.width, 0)
        self.access_tx_offset = vector(
            self.en_nor_offset.x - self.nor.width + self.access_tx.height +
            margin, self.inv.height * 0.5)
        self.replica_bitline_offset = vector(
            self.delay_chain_offset.x + bitcell_array_spacing,
            self.bitcell_chars["height"] + gnd_route_margin)
        self.delay_inv_offset = vector(
            self.delay_chain_offset.x - self.inv.width, self.inv.height * 2)

        self.height = m1rail_space + max(
            self.delay_chain_offset.y + self.inv.height,
            self.replica_bitline_offset.y + self.bitline_load.height +
            0.5 * self.bitcell_chars["height"])
        self.width = (self.replica_bitline_offset.x +
                      self.replica_bitcell.width)
Exemplo n.º 41
0
    def add_ptx(self):
        """  transistors are added and placed inside the layout         """

        # determines the spacing between the edge and nmos (rail to active
        # metal or poly_to_poly spacing)
        edge_to_nmos = max(
            drc["metal1_to_metal1"] -
            self.nmos1.active_contact_positions[0][1],
            0.5 * (drc["poly_to_poly"] - drc["minwidth_metal1"]) -
            self.nmos1.poly_positions[0][1])

        # determine the position of the first transistor from the left
        self.nmos_position1 = vector(
            0, 0.5 * drc["minwidth_metal1"] + edge_to_nmos)
        offset = self.nmos_position1 + vector(0, self.nmos1.height)
        self.add_inst(name="nmos1", mod=self.nmos1, offset=offset, mirror="MX")
        self.connect_inst(["Z", "A", "net1", "gnd"])

        self.nmos_position2 = vector(
            self.nmos2.active_width - self.nmos2.active_contact.width,
            self.nmos_position1[1])
        offset = self.nmos_position2 + vector(0, self.nmos2.height)
        self.add_inst(name="nmos2", mod=self.nmos2, offset=offset, mirror="MX")
        self.connect_inst(["net1", "B", "gnd", "gnd"])

        # determines the spacing between the edge and pmos
        edge_to_pmos = max(drc["metal1_to_metal1"] \
                               - self.pmos1.active_contact_positions[0][1],
                           0.5 * drc["poly_to_poly"] - 0.5 * drc["minwidth_metal1"] \
                               - self.pmos1.poly_positions[0][1])

        self.pmos_position1 = vector(
            0, self.height - 0.5 * drc["minwidth_metal1"] - edge_to_pmos -
            self.pmos1.height)
        self.add_inst(name="pmos1", mod=self.pmos1, offset=self.pmos_position1)
        self.connect_inst(["vdd", "A", "Z", "vdd"])

        self.pmos_position2 = vector(self.nmos_position2.x,
                                     self.pmos_position1.y)
        self.add_inst(name="pmos2", mod=self.pmos2, offset=self.pmos_position2)
        self.connect_inst(["Z", "B", "vdd", "vdd"])
Exemplo n.º 42
0
    def calculate_module_offsets(self):
        """ Calculate all the module offsets """

        # delay chain and inv will be rotated 90
        self.rbl_inv_offset = vector(self.inv.height, self.inv.width)

        # access TX goes right on top of inverter
        self.access_tx_offset = vector(0.5*self.inv.height,self.rbl_inv_offset.y) + \
                                vector(0,0.5*self.inv.height)
        self.delay_chain_offset = self.rbl_inv_offset + vector(
            -contact.m1m2.width, self.inv.width)

        # Replica bitline is not rotated, it is placed 2 M1 pitch away from the delay chain
        self.bitcell_offset = self.rbl_inv_offset + vector(
            2 * self.m_pitch("m2"), self.bitcell.height)
        self.rbl_offset = self.bitcell_offset + vector(0, -self.rbl.y_shift)

        self.height = max(self.rbl_offset.y + self.rbl.height,
                          self.delay_chain_offset.y + self.delay_chain.width)
        self.width = self.rbl_offset.x + self.bitcell.width + 3 * self.m_pitch(
            "m1")
Exemplo n.º 43
0
    def compute_connector(self, pin, enclosure):
        """
        Compute a shape to connect the pin to the enclosure shape.
        This assumes the shape will be the dimension of the pin.
        """
        if pin.xoverlaps(enclosure):
            # Is it vertical overlap, extend pin shape to enclosure
            plc = pin.lc()
            prc = pin.rc()
            elc = enclosure.lc()
            # erc = enclosure.rc()
            ymin = min(plc.y, elc.y)
            ymax = max(plc.y, elc.y)
            ll = vector(plc.x, ymin)
            ur = vector(prc.x, ymax)
        elif pin.yoverlaps(enclosure):
            # Is it horizontal overlap, extend pin shape to enclosure
            pbc = pin.bc()
            puc = pin.uc()
            ebc = enclosure.bc()
            # euc = enclosure.uc()
            xmin = min(pbc.x, ebc.x)
            xmax = max(pbc.x, ebc.x)
            ll = vector(xmin, pbc.y)
            ur = vector(xmax, puc.y)
        else:
            # Neither, so we must do a corner-to corner
            pc = pin.center()
            ec = enclosure.center()
            xmin = min(pc.x, ec.x)
            xmax = max(pc.x, ec.x)
            ymin = min(pc.y, ec.y)
            ymax = max(pc.y, ec.y)
            ll = vector(xmin, ymin)
            ur = vector(xmax, ymax)

        if ll.x == ur.x or ll.y == ur.y:
            return None
        p = pin_layout(pin.name, [ll, ur], pin.layer)
        return p
Exemplo n.º 44
0
    def connect_stages_of_ring(self):
        """ Connect output of each stage to input of next stage in delay_chains (dc1 and dc2) """

        for i in range(self.stage - 1):
            pos1 = self.dc2_inst[i].get_pin("out").lc()
            if i % 2:
                pos2 = vector(pos1.x - 2 * self.m_pitch("m1"), pos1.y)
            else:
                pos2 = vector(pos1.x - self.m_pitch("m1"), pos1.y)
            pos4 = self.dc2_inst[i + 1].get_pin("in").lc()
            pos3 = vector(pos2.x, pos4.y)
            self.add_wire(self.m1_stack, [pos1, pos2, pos3, pos4])

        for i in range(self.stage - 1):
            pos1 = self.dc1_inst[i].get_pin("out").lc()
            if i % 2:
                pos2 = vector(pos1.x - 2 * self.m_pitch("m1"), pos1.y)
            else:
                pos2 = vector(pos1.x - self.m_pitch("m1"), pos1.y)
            pos4 = self.dc1_inst[i + 1].get_pin("in").lc()
            pos3 = vector(pos2.x, pos4.y)
            self.add_wire(self.m1_stack, [pos1, pos2, pos3, pos4])
Exemplo n.º 45
0
    def add_wells(self):
        """ Add a well and implant over the whole cell. Also, add the pwell contact (if it exists) """

        
        # find right most gnd rail
        gnd_pins = self.bitcell.get_pins("gnd")
        right_gnd = None
        for gnd_pin in gnd_pins:
            if right_gnd == None or gnd_pin.lx()>right_gnd.lx():
                right_gnd = gnd_pin
                
        # Add to the right (first) gnd rail
        m1m2_offset = right_gnd.bc() + vector(0,0.5*self.nmos.poly_height)
        self.add_via_center(layers=("metal1", "via1", "metal2"),
                            offset=m1m2_offset)
        active_offset = right_gnd.bc() + vector(0,0.5*self.nmos.poly_height)
        self.add_via_center(layers=("active", "contact", "metal1"),
                            offset=active_offset)

        # implant must surround the active area
        active_correct = vector(contact.well.width,contact.well.height).scale(0.5,0.5)
        offset_implant = active_offset - vector([drc["implant_to_contact"]]*2) - active_correct
        implant_width = 2*drc["implant_to_contact"] + contact.well.width
        implant_height = 2*drc["implant_to_contact"] + contact.well.height        
        self.add_rect(layer="pimplant",
                      offset=offset_implant,
                      width=implant_width,
                      height=implant_height)

        # Add a well around the whole cell
        if info["has_pwell"]:
            self.add_rect(layer="pwell",
                          offset=vector(0,0),
                          width=self.width + contact.well.width + drc["well_enclosure_active"],
                          height=self.height)
        self.add_rect(layer="vtg",
                      offset=vector(0,0),
                      width=self.width + contact.well.width,
                      height=self.height)
Exemplo n.º 46
0
    def add_vertical_trunk_route(self,
                                 pins,
                                 trunk_offset,
                                 layer_stack=("metal1", "via1", "metal2"),
                                 pitch=None):
        """
        Create a trunk route for all pins with the trunk located at the given x offset. 
        """
        if not pitch:
            pitch = self.m2_pitch
            
        max_y = max([pin.center().y for pin in pins])
        min_y = min([pin.center().y for pin in pins])

        # Add the vertical trunk
        half_minwidth = 0.5*drc["minwidth_{}".format(layer_stack[2])]

        # if we are less than a pitch, just create a non-preferred layer jog
        if max_y-min_y < pitch:
            # Add the horizontal trunk on the vertical layer!
            self.add_path(layer_stack[0],[vector(trunk_offset.x,min_y-half_minwidth), vector(trunk_offset.x,max_y+half_minwidth)])

            # Route each pin to the trunk
            for pin in pins:
                # No bend needed here
                mid = vector(trunk_offset.x, pin.center().y)
                self.add_path(layer_stack[0], [pin.center(), mid])
        else:
            # Add the vertical trunk
            self.add_path(layer_stack[2],[vector(trunk_offset.x,min_y), vector(trunk_offset.x,max_y)])
            trunk_mid = vector(trunk_offset.x,0.5*(max_y+min_y),)

            # Route each pin to the trunk
            for pin in pins:
                mid = vector(trunk_offset.x, pin.center().y)
                self.add_path(layer_stack[0], [pin.center(), mid])
                self.add_via_center(layers=layer_stack,
                                    offset=mid)
Exemplo n.º 47
0
    def route_instances(self):

        # bank_sel is vertical wire
        bank_sel_inv_pin = self.bank_sel_inv.get_pin("A")
        xoffset_bank_sel = bank_sel_inv_pin.lx()
        bank_sel_line_pos = vector(xoffset_bank_sel, 0)
        bank_sel_line_end = vector(xoffset_bank_sel, self.yoffset_maxpoint)
        self.add_path("metal2", [bank_sel_line_pos, bank_sel_line_end])
        self.add_via_center(layers=("metal1", "via1", "metal2"),
                            offset=bank_sel_inv_pin.lc())

        # Route the pin to the left edge as well
        bank_sel_pin_pos = vector(0, 0)
        bank_sel_pin_end = vector(bank_sel_line_pos.x, bank_sel_pin_pos.y)
        self.add_layout_pin_segment_center(text="bank_sel",
                                           layer="metal3",
                                           start=bank_sel_pin_pos,
                                           end=bank_sel_pin_end)
        self.add_via_center(layers=("metal2", "via2", "metal3"),
                            offset=bank_sel_pin_end,
                            directions=("H", "H"))

        # bank_sel_bar is vertical wire
        bank_sel_bar_pin = self.bank_sel_inv.get_pin("Z")
        xoffset_bank_sel_bar = bank_sel_bar_pin.rx()
        self.add_label_pin(text="bank_sel_bar",
                           layer="metal2",
                           offset=vector(xoffset_bank_sel_bar, 0),
                           height=self.inv4x.height)
        self.add_via_center(layers=("metal1", "via1", "metal2"),
                            offset=bank_sel_bar_pin.rc())

        for i in range(self.num_control_lines):

            logic_inst = self.logic_inst[i]
            inv_inst = self.inv_inst[i]

            input_name = self.input_control_signals[i]
            gated_name = self.control_signals[i]
            if input_name in ("clk_buf"):
                xoffset_bank_signal = xoffset_bank_sel_bar
            else:
                xoffset_bank_signal = xoffset_bank_sel

            # Connect the logic output to inverter input
            pre = logic_inst.get_pin("Z").lc()
            out_position = logic_inst.get_pin("Z").rc() + vector(
                0.5 * self.m1_width, 0)
            in_position = inv_inst.get_pin("A").lc() + vector(
                0.5 * self.m1_width, 0)
            post = inv_inst.get_pin("A").rc()
            self.add_path("metal1", [pre, out_position, in_position, post])

            # Connect the logic B input to bank_sel/bank_sel_bar
            logic_pos = logic_inst.get_pin("B").lc() - vector(
                0.5 * contact.m1m2.height, 0)
            input_pos = vector(xoffset_bank_signal, logic_pos.y)
            self.add_path("metal2", [logic_pos, input_pos])
            self.add_via_center(layers=("metal1", "via1", "metal2"),
                                offset=logic_pos,
                                directions=("H", "H"))

            # Connect the logic A input to the input pin
            logic_pos = logic_inst.get_pin("A").lc()
            input_pos = vector(0, logic_pos.y)
            self.add_via_center(layers=("metal1", "via1", "metal2"),
                                offset=logic_pos,
                                directions=("H", "H"))
            self.add_via_center(layers=("metal2", "via2", "metal3"),
                                offset=logic_pos,
                                directions=("H", "H"))
            self.add_layout_pin_segment_center(text=input_name,
                                               layer="metal3",
                                               start=input_pos,
                                               end=logic_pos)

            # Add output pins
            out_pin = inv_inst.get_pin("Z")
            self.add_layout_pin(text=gated_name,
                                layer=out_pin.layer,
                                offset=out_pin.ll(),
                                width=inv_inst.rx() - out_pin.lx(),
                                height=out_pin.height())

        # Find the x offsets for where the vias/pins should be placed
        a_xoffset = self.logic_inst[0].lx()
        b_xoffset = self.inv_inst[0].lx()
        for num in range(self.num_control_lines):
            # Route both supplies
            for n in ["vdd", "gnd"]:
                supply_pin = self.inv_inst[num].get_pin(n)
                supply_offset = supply_pin.ll().scale(0, 1)
                self.add_rect(layer="metal1",
                              offset=supply_offset,
                              width=self.width)

                # Add pins in two locations
                for xoffset in [a_xoffset, b_xoffset]:
                    pin_pos = vector(xoffset, supply_pin.cy())
                    self.add_via_center(layers=("metal1", "via1", "metal2"),
                                        offset=pin_pos,
                                        directions=("H", "H"))
                    self.add_via_center(layers=("metal2", "via2", "metal3"),
                                        offset=pin_pos,
                                        directions=("H", "H"))
                    self.add_layout_pin_rect_center(text=n,
                                                    layer="metal3",
                                                    offset=pin_pos)

            # Add vdd/gnd supply rails
            gnd_pin = inv_inst.get_pin("gnd")
            left_gnd_pos = vector(0, gnd_pin.cy())
            self.add_layout_pin_segment_center(text="gnd",
                                               layer="metal1",
                                               start=left_gnd_pos,
                                               end=gnd_pin.rc())

            vdd_pin = inv_inst.get_pin("vdd")
            left_vdd_pos = vector(0, vdd_pin.cy())
            self.add_layout_pin_segment_center(text="vdd",
                                               layer="metal1",
                                               start=left_vdd_pos,
                                               end=vdd_pin.rc())
Exemplo n.º 48
0
 def place_bitcell_array(self):
     """ Placing Bitcell Array """
     self.bitcell_array_inst.place(vector(0, 0))
Exemplo n.º 49
0
    def create_layout(self):
        # Wordline enable connection
        en_pin=self.add_layout_pin(text="en",
                                   layer="metal2",
                                   offset=[drc["minwidth_metal1"] + 2 * drc["metal1_to_metal1"],0],
                                   width=drc["minwidth_metal2"],
                                   height=self.height)
        
        self.add_layout_pin(text="gnd",
                            layer="metal1",
                            offset=[0, -0.5*drc["minwidth_metal1"]],
                            width=self.x_offset0,
                            height=drc["minwidth_metal1"])
        
        for row in range(self.rows):
            name_inv1 = "wl_driver_inv_en{}".format(row)
            name_nand = "wl_driver_nand{}".format(row)
            name_inv2 = "wl_driver_inv{}".format(row)

            inv_nand2B_connection_height = (abs(self.inv.get_pin("Z").ll().y 
                                                - self.nand2.get_pin("B").ll().y)
                                            + drc["minwidth_metal1"])

            if (row % 2):
                y_offset = self.inv.height*(row + 1)
                inst_mirror = "MX"
                cell_dir = vector(0,-1)
                m1tm2_rotate=270
                m1tm2_mirror="R0"
            else:
                y_offset = self.inv.height*row
                inst_mirror = "R0"
                cell_dir = vector(0,1)
                m1tm2_rotate=90
                m1tm2_mirror="MX"

            name_inv1_offset = [self.x_offset0, y_offset]
            nand2_offset=[self.x_offset1, y_offset]
            inv2_offset=[self.x_offset2, y_offset]
            base_offset = vector(self.width, y_offset)

            # Extend vdd and gnd of wordline_driver
            yoffset = (row + 1) * self.inv.height - 0.5 * drc["minwidth_metal1"]
            if (row % 2):
                pin_name = "gnd"
            else:
                pin_name = "vdd"
                
            self.add_layout_pin(text=pin_name,
                                layer="metal1",
                                offset=[0, yoffset],
                                width=self.x_offset0,
                                height=drc["minwidth_metal1"])
            
            
            # add inv1 based on the info above
            inv1_inst=self.add_inst(name=name_inv1,
                                    mod=self.inv,
                                    offset=name_inv1_offset,
                                    mirror=inst_mirror )
            self.connect_inst(["en", "en_bar[{0}]".format(row),
                               "vdd", "gnd"])
            # add nand 2
            nand_inst=self.add_inst(name=name_nand,
                                    mod=self.nand2,
                                    offset=nand2_offset,
                                    mirror=inst_mirror)
            self.connect_inst(["in[{0}]".format(row),
                               "en_bar[{0}]".format(row),
                               "net[{0}]".format(row),
                               "vdd", "gnd"])
            # add inv2
            inv2_inst=self.add_inst(name=name_inv2,
                                mod=self.inv,
                                    offset=inv2_offset,
                                    mirror=inst_mirror)
            self.connect_inst(["net[{0}]".format(row),
                               "wl[{0}]".format(row),
                               "vdd", "gnd"])

            # en connection
            a_pin = inv1_inst.get_pin("A")
            a_pos = a_pin.lc()
            clk_offset = vector(en_pin.bc().x,a_pos.y)
            self.add_center_rect(layer="metal1",
                                 start=clk_offset,
                                 end=a_pos)
            m1m2_via = self.add_center_via(layers=("metal1", "via1", "metal2"),
                                           offset=clk_offset)

            # first inv to nand2 B
            zl_pos = inv1_inst.get_pin("Z").lc()
            zr_pos = inv1_inst.get_pin("Z").rc()
            bl_pos = nand_inst.get_pin("B").lc()
            br_pos = nand_inst.get_pin("B").rc()
            self.add_path("metal1", [zl_pos, zr_pos, bl_pos, br_pos])

            # Nand2 out to 2nd inv
            zl_pos = nand_inst.get_pin("Z").lc()
            zr_pos = nand_inst.get_pin("Z").rc()
            bl_pos = inv2_inst.get_pin("A").lc()
            br_pos = inv2_inst.get_pin("A").rc()
            self.add_path("metal1", [zl_pos, zr_pos, bl_pos, br_pos])

            # connect the decoder input pin to nand2 A
            a_pin = nand_inst.get_pin("A")
            a_pos = a_pin.lc()
            input_offset = vector(0,a_pos.y)
            mid_via_offset = vector(clk_offset.x,a_pos.y) + vector(0.5*drc["minwidth_metal2"]+drc["metal2_to_metal2"]+0.5*m1m2_via.width,0) 
            # must under the clk line in M1
            self.add_center_layout_pin(text="in[{0}]".format(row),
                                       layer="metal1",
                                       start=input_offset,
                                       end=mid_via_offset)
            self.add_center_via(layers=("metal1", "via1", "metal2"),
                                offset=mid_via_offset)

            # now connect to the nand2 A
            self.add_center_rect(layer="metal2",
                                 start=mid_via_offset,
                                 end=a_pos)
            self.add_center_via(layers=("metal1", "via1", "metal2"),
                                offset=a_pos + vector(0.5*m1m2_via.height,0),
                                rotate=90)


            # output each WL on the right
            wl_offset = inv2_inst.get_pin("Z").rc()
            self.add_center_layout_pin(text="wl[{0}]".format(row),
                                       layer="metal1",
                                       start=wl_offset,
                                       end=wl_offset-vector(drc["minwidth_metal1"],0))
Exemplo n.º 50
0
    def setup_layout_constants(self):
        """
        Pre-compute some handy layout parameters.
        """

        if self.num_contacts == None:
            self.num_contacts = self.calculate_num_contacts()

        # Determine layer types needed
        if self.tx_type == "nmos":
            self.implant_type = "n"
            self.well_type = "p"
        elif self.tx_type == "pmos":
            self.implant_type = "p"
            self.well_type = "n"
        else:
            self.error("Invalid transitor type.", -1)

        # This is not actually instantiated but used for calculations
        self.active_contact = contact(layer_stack=("active", "contact",
                                                   "metal1"),
                                      dimensions=(1, self.num_contacts))

        # The contacted poly pitch (or uncontacted in an odd technology)
        self.poly_pitch = max(
            2 * self.contact_to_gate + self.contact_width + self.poly_width,
            self.poly_space)

        # The contacted poly pitch (or uncontacted in an odd technology)
        self.contact_pitch = 2 * self.contact_to_gate + self.contact_width + self.poly_width

        # The enclosure of an active contact. Not sure about second term.
        active_enclose_contact = max(drc["active_enclosure_contact"],
                                     (self.active_width - self.contact_width) /
                                     2)
        # This is the distance from the edge of poly to the contacted end of active
        self.end_to_poly = active_enclose_contact + self.contact_width + self.contact_to_gate

        # Active width is determined by enclosure on both ends and contacted pitch,
        # at least one poly and n-1 poly pitches
        self.active_width = 2 * self.end_to_poly + self.poly_width + (
            self.mults - 1) * self.poly_pitch

        # Active height is just the transistor width
        self.active_height = self.tx_width

        # Poly height must include poly extension over active
        self.poly_height = self.tx_width + 2 * self.poly_extend_active

        # The active offset is due to the well extension
        self.active_offset = vector([self.well_enclose_active] * 2)

        # Well enclosure of active, ensure minwidth as well
        if info["has_{}well".format(self.well_type)]:
            self.cell_well_width = max(
                self.active_width + 2 * self.well_enclose_active,
                self.well_width)
            self.cell_well_height = max(
                self.tx_width + 2 * self.well_enclose_active, self.well_width)
            # We are going to shift the 0,0, so include that in the width and height
            self.height = self.cell_well_height - self.active_offset.y
            self.width = self.cell_well_width - self.active_offset.x
        else:
            # If no well, use the boundary of the active and poly
            self.height = self.poly_height
            self.width = self.active_width

        # The active offset is due to the well extension
        self.active_offset = vector([self.well_enclose_active] * 2)

        # This is the center of the first active contact offset (centered vertically)
        self.contact_offset = self.active_offset + vector(
            active_enclose_contact + 0.5 * self.contact_width,
            0.5 * self.active_height)

        # Min area results are just flagged for now.
        debug.check(
            self.active_width * self.active_height >= drc["minarea_active"],
            "Minimum active area violated.")
        # We do not want to increase the poly dimensions to fix an area problem as it would cause an LVS issue.
        debug.check(self.poly_width * self.poly_height >= drc["minarea_poly"],
                    "Minimum poly area violated.")
Exemplo n.º 51
0
 def normalize(self):
     """ Re-find the LL and UR points after a transform """
     (first, second) = self.boundary
     ll = vector(min(first[0], second[0]), min(first[1], second[1]))
     ur = vector(max(first[0], second[0]), max(first[1], second[1]))
     self.boundary = [ll, ur]
Exemplo n.º 52
0
    def route_dff(self, port):

        route_map = []
        
        # column mux dff
        if self.col_addr_size > 0:
            dff_names = ["dout_{}".format(x) for x in range(self.col_addr_size)]
            dff_pins = [self.col_addr_dff_insts[port].get_pin(x) for x in dff_names]
            bank_names = ["addr{0}_{1}".format(port, x) for x in range(self.col_addr_size)]
            bank_pins = [self.bank_inst.get_pin(x) for x in bank_names]
            route_map.extend(list(zip(bank_pins, dff_pins)))
        
        # wmask dff
        if self.num_wmasks > 0 and port in self.write_ports:
            dff_names = ["dout_{}".format(x) for x in range(self.num_wmasks)]
            dff_pins = [self.wmask_dff_insts[port].get_pin(x) for x in dff_names]
            bank_names = ["bank_wmask{0}_{1}".format(port, x) for x in range(self.num_wmasks)]
            bank_pins = [self.bank_inst.get_pin(x) for x in bank_names]
            route_map.extend(list(zip(bank_pins, dff_pins)))

        if port in self.write_ports:
            # synchronized inputs from data dff
            dff_names = ["dout_{}".format(x) for x in range(self.word_size + self.num_spare_cols)]
            dff_pins = [self.data_dff_insts[port].get_pin(x) for x in dff_names]
            bank_names = ["din{0}_{1}".format(port, x) for x in range(self.word_size + self.num_spare_cols)]
            bank_pins = [self.bank_inst.get_pin(x) for x in bank_names]
            route_map.extend(list(zip(bank_pins, dff_pins)))
            
        if port in self.readwrite_ports and OPTS.perimeter_pins:
            # outputs from sense amp
            # These are the output pins which had their pin placed on the perimeter, so route from the
            # sense amp which should not align with write driver input
            sram_names = ["dout{0}[{1}]".format(port, x) for x in range(self.word_size + self.num_spare_cols)]
            sram_pins = [self.get_pin(x) for x in sram_names]
            bank_names = ["dout{0}_{1}".format(port, x) for x in range(self.word_size + self.num_spare_cols)]
            bank_pins = [self.bank_inst.get_pin(x) for x in bank_names]
            route_map.extend(list(zip(bank_pins, sram_pins)))

        if self.num_wmasks > 0 and port in self.write_ports:
            layer_stack = self.m3_stack
        else:
            layer_stack = self.m1_stack
                
        if port == 0:
            offset = vector(self.control_logic_insts[port].rx() + self.dff.width,
                            - self.data_bus_size[port] + 2 * self.m1_pitch)
        else:
            offset = vector(0,
                            self.bank.height + 2 * self.m1_space)

        if len(route_map) > 0:
            self.create_horizontal_channel_route(netlist=route_map,
                                                 offset=offset,
                                                 layer_stack=layer_stack)

        # Route these separately because sometimes the pin pitch on the write driver is too narrow for M3 (FreePDK45)
        # spare wen dff
        if self.num_spare_cols > 0 and port in self.write_ports:
            dff_names = ["dout_{}".format(x) for x in range(self.num_spare_cols)]
            dff_pins = [self.spare_wen_dff_insts[port].get_pin(x) for x in dff_names]
            bank_names = ["bank_spare_wen{0}_{1}".format(port, x) for x in range(self.num_spare_cols)]
            bank_pins = [self.bank_inst.get_pin(x) for x in bank_names]
            route_map = zip(bank_pins, dff_pins)
            self.create_horizontal_channel_route(netlist=route_map,
                                                 offset=offset,
                                                 layer_stack=self.m1_stack)
Exemplo n.º 53
0
    def place_insts(self):
        # Add INV1 to the right
        self.inv1_inst.place(vector(0, 0))

        # Add INV2 to the right
        self.inv2_inst.place(vector(self.inv1_inst.rx(), 0))
Exemplo n.º 54
0
    def route_read_access(self):
        """  Routes read access transistors to the storage component of the bitcell """
        # add poly to metal1 contacts for gates of the inverters
        left_storage_contact = vector(
            self.inverter_nmos_left.get_pin("G").lc().x -
            drc["poly_to_polycontact"] - 0.5 * contact.poly.width,
            self.cross_couple_upper_ypos)
        self.add_contact_center(layers=("poly", "contact", "metal1"),
                                offset=left_storage_contact,
                                rotate=90)

        right_storage_contact = vector(
            self.inverter_nmos_right.get_pin("G").rc().x +
            drc["poly_to_polycontact"] + 0.5 * contact.poly.width,
            self.cross_couple_upper_ypos)
        self.add_contact_center(layers=("poly", "contact", "metal1"),
                                offset=right_storage_contact,
                                rotate=90)

        inverter_gate_offset_left = vector(
            self.inverter_nmos_left.get_pin("G").lc().x,
            self.cross_couple_upper_ypos)
        self.add_path("poly",
                      [left_storage_contact, inverter_gate_offset_left])

        inverter_gate_offset_right = vector(
            self.inverter_nmos_right.get_pin("G").rc().x,
            self.cross_couple_upper_ypos)
        self.add_path("poly",
                      [right_storage_contact, inverter_gate_offset_right])

        # add poly to metal1 contacts for gates of read-access transistors
        # route from read-access contacts to inverter contacts on metal1
        for k in range(self.num_r_ports):
            port_contact_offset = self.read_access_nmos_left[k].get_pin(
                "G").uc() + vector(
                    0, self.gate_contact_yoffset - self.poly_extend_active)

            self.add_contact_center(layers=("poly", "contact", "metal1"),
                                    offset=port_contact_offset)

            self.add_path("poly", [
                self.read_access_nmos_left[k].get_pin("G").uc(),
                port_contact_offset
            ])

            mid = vector(self.read_access_nmos_left[k].get_pin("G").uc().x,
                         self.cross_couple_upper_ypos)
            self.add_path(
                "metal1",
                [port_contact_offset, mid + vector(0, 0.5 * self.m1_width)],
                width=contact.poly.second_layer_width)
            self.add_path("metal1", [mid, left_storage_contact])

            port_contact_offset = self.read_access_nmos_right[k].get_pin(
                "G").uc() + vector(
                    0, self.gate_contact_yoffset - self.poly_extend_active)

            self.add_contact_center(layers=("poly", "contact", "metal1"),
                                    offset=port_contact_offset)

            self.add_path("poly", [
                self.read_access_nmos_right[k].get_pin("G").uc(),
                port_contact_offset
            ])

            mid = vector(self.read_access_nmos_right[k].get_pin("G").uc().x,
                         self.cross_couple_upper_ypos)
            self.add_path(
                "metal1",
                [port_contact_offset, mid + vector(0, 0.5 * self.m1_width)],
                width=contact.poly.second_layer_width)
            self.add_path("metal1", [mid, right_storage_contact])
Exemplo n.º 55
0
    def place_read_ports(self):
        """ Places the read ports in the bit cell """
        # define read transistor variables as empty arrays based on the number of read ports
        self.rwl_positions = [None] * self.num_r_ports
        self.rbl_positions = [None] * self.num_r_ports
        self.rbr_positions = [None] * self.num_r_ports

        # calculate offset to overlap the drain of the read-access transistor with the source of the read transistor
        overlap_offset = self.read_nmos.get_pin(
            "D").cx() - self.read_nmos.get_pin("S").cx()

        # iterate over the number of read ports
        for k in range(0, self.num_r_ports):
            # calculate transistor offsets
            left_read_transistor_xpos = self.left_building_edge \
                                        - (k+1)*self.read_port_spacing \
                                        - (k+1)*self.read_port_width

            right_read_transistor_xpos = self.right_building_edge \
                                         + (k+1)*self.read_port_spacing \
                                         + k*self.read_port_width

            # add read-access transistors
            self.read_access_nmos_left[k].place(offset=[
                left_read_transistor_xpos + overlap_offset, self.port_ypos
            ])

            self.read_access_nmos_right[k].place(
                offset=[right_read_transistor_xpos, self.port_ypos])

            # add read transistors
            self.read_nmos_left[k].place(
                offset=[left_read_transistor_xpos, self.port_ypos])

            self.read_nmos_right[k].place(offset=[
                right_read_transistor_xpos + overlap_offset, self.port_ypos
            ])

            # add pin for RWL
            rwl_ypos = rwwl_ypos = self.rowline_offset - self.num_rw_ports * self.rowline_spacing - self.num_w_ports * self.rowline_spacing - k * self.rowline_spacing
            self.rwl_positions[k] = vector(0, rwl_ypos)
            self.add_layout_pin_rect_center(text=self.r_wl_names[k],
                                            layer="metal1",
                                            offset=self.rwl_positions[k],
                                            width=self.width,
                                            height=self.m1_width)

            # add pins for RBL and RBR
            rbl_xpos = left_read_transistor_xpos - self.bitline_offset + 0.5 * self.m2_width
            self.rbl_positions[k] = vector(rbl_xpos, self.center_ypos)
            self.add_layout_pin_rect_center(text=self.r_bl_names[k],
                                            layer="metal2",
                                            offset=self.rbl_positions[k],
                                            width=drc["minwidth_metal2"],
                                            height=self.height)

            rbr_xpos = right_read_transistor_xpos + self.read_port_width + self.bitline_offset - 0.5 * self.m2_width
            self.rbr_positions[k] = vector(rbr_xpos, self.center_ypos)
            self.add_layout_pin_rect_center(text=self.r_br_names[k],
                                            layer="metal2",
                                            offset=self.rbr_positions[k],
                                            width=drc["minwidth_metal2"],
                                            height=self.height)
Exemplo n.º 56
0
    def add_supply_routing(self):

        rows_start = self.rail_1_start_x + self.overall_rail_1_gap
        rows_end = max(self.row_1_end_x, self.row_2_end_x, self.row_3_end_x)
        vdd_rail_position = vector(self.rail_1_x_offsets["vdd"], 0)
        well_width = drc["minwidth_well"]

        # M1 gnd rail from inv1 to max
        start_offset = self.clk_inv1.get_pin("gnd").lc()
        row1_gnd_end_offset = vector(rows_end, start_offset.y)
        self.add_path("metal1", [start_offset, row1_gnd_end_offset])
        rail_position = vector(self.rail_1_x_offsets["gnd"], start_offset.y)
        self.add_wire(("metal1", "via1", "metal2"), [
            vector(rows_start, start_offset.y), rail_position,
            rail_position + vector(0, self.m2_pitch)
        ])

        # also add a well + around the rail
        self.add_rect(layer="pwell",
                      offset=vector(rows_start, start_offset.y),
                      width=rows_end - rows_start,
                      height=well_width)
        self.add_rect(layer="vtg",
                      offset=vector(rows_start, start_offset.y),
                      width=rows_end - rows_start,
                      height=well_width)

        # M1 vdd rail from inv1 to max
        start_offset = self.clk_inv1.get_pin("vdd").lc()
        row1_vdd_end_offset = vector(rows_end, start_offset.y)
        self.add_path("metal1", [start_offset, row1_vdd_end_offset])
        rail_position = vector(self.rail_1_x_offsets["vdd"], start_offset.y)
        self.add_wire(("metal1", "via1", "metal2"), [
            vector(rows_start, start_offset.y), rail_position,
            rail_position - vector(0, self.m2_pitch)
        ])

        # also add a well +- around the rail
        self.add_rect(layer="nwell",
                      offset=vector(rows_start, start_offset.y) -
                      vector(0, 0.5 * well_width),
                      width=rows_end - rows_start,
                      height=well_width)
        self.add_rect(layer="vtg",
                      offset=vector(rows_start, start_offset.y) -
                      vector(0, 0.5 * well_width),
                      width=rows_end - rows_start,
                      height=well_width)

        # M1 gnd rail from inv1 to max
        start_offset = vector(rows_start, self.tri_en.get_pin("gnd").lc().y)
        row3_gnd_end_offset = vector(rows_end, start_offset.y)
        self.add_path("metal1", [start_offset, row3_gnd_end_offset])
        rail_position = vector(self.rail_1_x_offsets["gnd"], start_offset.y)
        self.add_wire(("metal1", "via1", "metal2"), [
            vector(rows_start, start_offset.y), rail_position,
            rail_position - vector(0, self.m2_pitch)
        ])

        # also add a well +- around the rail
        self.add_rect(layer="pwell",
                      offset=vector(rows_start, start_offset.y) -
                      vector(0, 0.5 * well_width),
                      width=rows_end - rows_start,
                      height=well_width)
        self.add_rect(layer="vtg",
                      offset=vector(rows_start, start_offset.y) -
                      vector(0, 0.5 * well_width),
                      width=rows_end - rows_start,
                      height=well_width)

        # M1 vdd rail from inv1 to max
        start_offset = vector(rows_start, self.w_en_bar.get_pin("vdd").lc().y)
        row3_vdd_end_offset = vector(rows_end, start_offset.y)
        self.add_path("metal1", [start_offset, row3_vdd_end_offset])
        rail_position = vector(self.rail_1_x_offsets["vdd"], start_offset.y)
        self.add_wire(("metal1", "via1", "metal2"), [
            vector(rows_start, start_offset.y), rail_position,
            rail_position - vector(0, self.m2_pitch)
        ])

        # Now connect the vdd and gnd rails between the replica bitline and the control logic
        (rbl_row3_gnd, rbl_row1_gnd) = self.rbl.get_pins("gnd")
        (rbl_row3_vdd, rbl_row1_vdd) = self.rbl.get_pins("vdd")

        self.add_path("metal1", [row1_gnd_end_offset, rbl_row1_gnd.lc()])
        self.add_path("metal1", [row1_vdd_end_offset, rbl_row1_vdd.lc()])
        self.add_path("metal1", [row3_gnd_end_offset, rbl_row3_gnd.lc()])
        # row 3 may have a jog due to unequal row heights, so force the full overlap at the end
        self.add_path("metal1", [
            row3_vdd_end_offset - vector(self.m1_pitch, 0),
            row3_vdd_end_offset,
            rbl_row3_vdd.ul()
        ])

        # also add a well - around the rail
        self.add_rect(layer="nwell",
                      offset=vector(rows_start, start_offset.y) -
                      vector(0, well_width),
                      width=rows_end - rows_start,
                      height=well_width)
        self.add_rect(layer="vtg",
                      offset=vector(rows_start, start_offset.y) -
                      vector(0, well_width),
                      width=rows_end - rows_start,
                      height=well_width)
Exemplo n.º 57
0
    def add_layout_pins(self):
        """
        Add the top-level pins for a single bank SRAM with control.
        """
        highest_coord = self.find_highest_coords()
        lowest_coord = self.find_lowest_coords()
        bbox = [lowest_coord, highest_coord]
        
        for port in self.all_ports:
            # Depending on the port, use the bottom/top or left/right sides
            # Port 0 is left/bottom
            # Port 1 is right/top
            bottom_or_top = "bottom" if port==0 else "top"
            left_or_right = "left" if port==0 else "right"

            # Connect the control pins as inputs
            for signal in self.control_logic_inputs[port]:
                if signal == "clk":
                    continue
                if OPTS.perimeter_pins:
                    self.add_perimeter_pin(name=signal + "{}".format(port),
                                           pin=self.control_logic_insts[port].get_pin(signal),
                                           side=left_or_right,
                                           bbox=bbox)
                else:
                    self.copy_layout_pin(self.control_logic_insts[port],
                                         signal,
                                         signal + "{}".format(port))

            if OPTS.perimeter_pins:
                self.add_perimeter_pin(name="clk{}".format(port),
                                       pin=self.control_logic_insts[port].get_pin("clk"),
                                       side=bottom_or_top,
                                       bbox=bbox)
            else:
                self.copy_layout_pin(self.control_logic_insts[port],
                                     "clk",
                                     "clk{}".format(port))

            # Data input pins go to BOTTOM/TOP
            din_ports = []
            if port in self.write_ports:
                for bit in range(self.word_size + self.num_spare_cols):
                    if OPTS.perimeter_pins:
                        p = self.add_perimeter_pin(name="din{0}[{1}]".format(port, bit),
                                                   pin=self.data_dff_insts[port].get_pin("din_{0}".format(bit)),
                                                   side=bottom_or_top,
                                                   bbox=bbox)
                        din_ports.append(p)
                    else:
                        self.copy_layout_pin(self.data_dff_insts[port],
                                             "din_{}".format(bit),
                                             "din{0}[{1}]".format(port, bit))
                        
            # Data output pins go to BOTTOM/TOP
            if port in self.readwrite_ports and OPTS.perimeter_pins:
                for bit in range(self.word_size + self.num_spare_cols):
                    # This should be routed next to the din pin
                    p = din_ports[bit]
                    self.add_layout_pin_rect_center(text="dout{0}[{1}]".format(port, bit),
                                                    layer=p.layer,
                                                    offset=p.center() + vector(self.m3_pitch, 0),
                                                    width=p.width(),
                                                    height=p.height())
            elif port in self.read_ports:
                for bit in range(self.word_size + self.num_spare_cols):
                    if OPTS.perimeter_pins:
                        # This should have a clear route to the perimeter if there are no din routes
                        self.add_perimeter_pin(name="dout{0}[{1}]".format(port, bit),
                                               pin=self.bank_inst.get_pin("dout{0}_{1}".format(port, bit)),
                                               side=bottom_or_top,
                                               bbox=bbox)
                    else:
                        self.copy_layout_pin(self.bank_inst,
                                             "dout{0}_{1}".format(port, bit),
                                             "dout{0}[{1}]".format(port, bit))
                    
                        

            # Lower address bits go to BOTTOM/TOP
            for bit in range(self.col_addr_size):
                if OPTS.perimeter_pins:
                    self.add_perimeter_pin(name="addr{0}[{1}]".format(port, bit),
                                           pin=self.col_addr_dff_insts[port].get_pin("din_{}".format(bit)),
                                           side=bottom_or_top,
                                           bbox=bbox)
                else:
                    self.copy_layout_pin(self.col_addr_dff_insts[port],
                                         "din_{}".format(bit),
                                         "addr{0}[{1}]".format(port, bit))
                
            # Upper address bits go to LEFT/RIGHT
            for bit in range(self.row_addr_size):
                if OPTS.perimeter_pins:
                    self.add_perimeter_pin(name="addr{0}[{1}]".format(port, bit + self.col_addr_size),
                                           pin=self.row_addr_dff_insts[port].get_pin("din_{}".format(bit)),
                                           side=left_or_right,
                                           bbox=bbox)
                else:
                    self.copy_layout_pin(self.row_addr_dff_insts[port],
                                         "din_{}".format(bit),
                                         "addr{0}[{1}]".format(port, bit + self.col_addr_size))
                    
            # Write mask pins go to BOTTOM/TOP
            if port in self.write_ports:
                if self.write_size:
                    for bit in range(self.num_wmasks):
                        if OPTS.perimeter_pins:
                            self.add_perimeter_pin(name="wmask{0}[{1}]".format(port, bit),
                                                   pin=self.wmask_dff_insts[port].get_pin("din_{}".format(bit)),
                                                   side=bottom_or_top,
                                                   bbox=bbox)
                        else:
                            self.copy_layout_pin(self.wmask_dff_insts[port],
                                                 "din_{}".format(bit),
                                                 "wmask{0}[{1}]".format(port, bit))

            # Spare wen pins go to BOTTOM/TOP
            if port in self.write_ports:
                for bit in range(self.num_spare_cols):
                    if OPTS.perimeter_pins:
                        self.add_perimeter_pin(name="spare_wen{0}[{1}]".format(port, bit),
                                               pin=self.spare_wen_dff_insts[port].get_pin("din_{}".format(bit)),
                                               side=left_or_right,
                                               bbox=bbox)
                    else:
                        self.copy_layout_pin(self.spare_wen_dff_insts[port],
                                             "din_{}".format(bit),
                                             "spare_wen{0}[{1}]".format(port, bit))
Exemplo n.º 58
0
 def lr(self):
     """ Return the lower right corner """
     return vector(self.boundary[1].x, self.boundary[0].y)
Exemplo n.º 59
0
    def place_instances(self):
        """
        This places the instances for a single bank SRAM with control
        logic and up to 2 ports.
        """
        
        # No orientation or offset
        self.place_bank(self.bank_inst, [0, 0], 1, 1)

        # The control logic is placed such that the vertical center (between the delay/RBL and
        # the actual control logic is aligned with the vertical center of the bank (between
        # the sense amps/column mux and cell array)
        # The x-coordinate is placed to allow a single clock wire (plus an extra pitch)
        # up to the row address DFFs.
        control_pos = [None] * len(self.all_ports)
        row_addr_pos = [None] * len(self.all_ports)
        col_addr_pos = [None] * len(self.all_ports)
        wmask_pos = [None] * len(self.all_ports)
        spare_wen_pos = [None] * len(self.all_ports)
        data_pos = [None] * len(self.all_ports)

        # These positions utilize the channel route sizes.
        # FIXME: Auto-compute these rather than manual computation.
        # If a horizontal channel, they rely on the vertical channel non-preferred (contacted) pitch.
        # If a vertical channel, they rely on the horizontal channel non-preferred (contacted) pitch.
        # So, m3 non-pref pitch means that this is routed on the m2 layer.
        self.data_bus_gap = self.m4_nonpref_pitch * 2

        # Spare wen are on a separate layer so not included
        # Start with 1 track minimum
        self.data_bus_size = [1] * len(self.all_ports)
        for port in self.all_ports:
            # All ports need the col addr flops
            self.data_bus_size[port] += self.col_addr_size
            # Write ports need the data input flops and write mask flops
            if port in self.write_ports:
                self.data_bus_size[port] += self.num_wmasks + self.word_size
            # This is for the din pins that get routed in the same channel
            # when we have dout and din together
            if port in self.readwrite_ports:
                self.data_bus_size[port] += self.word_size
            # Convert to length
            self.data_bus_size[port] *= self.m4_nonpref_pitch
            # Add the gap in unit length
            self.data_bus_size[port] += self.data_bus_gap
        
        # Port 0
        port = 0

        # This includes 2 M2 pitches for the row addr clock line.
        # The delay line is aligned with the bitcell array while the control logic is aligned with the port_data
        # using the control_logic_center value.
        control_pos[port] = vector(-self.control_logic_insts[port].width - 2 * self.m2_pitch,
                                   self.bank.bank_array_ll.y - self.control_logic_insts[port].mod.control_logic_center.y)
        self.control_logic_insts[port].place(control_pos[port])
        
        # The row address bits are placed above the control logic aligned on the right.
        x_offset = self.control_logic_insts[port].rx() - self.row_addr_dff_insts[port].width
        # It is above the control logic but below the top of the bitcell array
        y_offset = max(self.control_logic_insts[port].uy(), self.bank_inst.uy() - self.row_addr_dff_insts[port].height)
        row_addr_pos[port] = vector(x_offset, y_offset)
        self.row_addr_dff_insts[port].place(row_addr_pos[port])

        # Add the col address flops below the bank to the right of the control logic
        x_offset = self.control_logic_insts[port].rx() + self.dff.width
        y_offset = - self.data_bus_size[port] - self.dff.height
        if self.col_addr_dff:
            col_addr_pos[port] = vector(x_offset,
                                        y_offset)
            self.col_addr_dff_insts[port].place(col_addr_pos[port])
            x_offset = self.col_addr_dff_insts[port].rx()
        else:
            col_addr_pos[port] = vector(x_offset, 0)
            
        if port in self.write_ports:
            if self.write_size:
                # Add the write mask flops below the write mask AND array.
                wmask_pos[port] = vector(x_offset,
                                         y_offset)
                self.wmask_dff_insts[port].place(wmask_pos[port])
                x_offset = self.wmask_dff_insts[port].rx()

            # Add the data flops below the write mask flops.
            data_pos[port] = vector(x_offset,
                                    y_offset)
            self.data_dff_insts[port].place(data_pos[port])
            x_offset = self.data_dff_insts[port].rx()

            # Add spare write enable flops to the right of data flops since the spare columns
            # will be on the right
            if self.num_spare_cols:
                spare_wen_pos[port] = vector(x_offset,
                                             y_offset)
                self.spare_wen_dff_insts[port].place(spare_wen_pos[port])
                x_offset = self.spare_wen_dff_insts[port].rx()

        else:
            wmask_pos[port] = vector(x_offset, y_offset)
            data_pos[port] = vector(x_offset, y_offset)
            spare_wen_pos[port] = vector(x_offset, y_offset)

        if len(self.all_ports)>1:
            # Port 1
            port = 1
        
            # This includes 2 M2 pitches for the row addr clock line
            # The delay line is aligned with the bitcell array while the control logic is aligned with the port_data
            # using the control_logic_center value.
            control_pos[port] = vector(self.bank_inst.rx() + self.control_logic_insts[port].width + 2 * self.m2_pitch,
                                       self.bank.bank_array_ur.y
                                       + self.control_logic_insts[port].height
                                       - self.control_logic_insts[port].height
                                       + self.control_logic_insts[port].mod.control_logic_center.y)
            self.control_logic_insts[port].place(control_pos[port], mirror="XY")
        
            # The row address bits are placed above the control logic aligned on the left.
            x_offset = control_pos[port].x - self.control_logic_insts[port].width + self.row_addr_dff_insts[port].width
            # It is below the control logic but below the bottom of the bitcell array
            y_offset = min(self.control_logic_insts[port].by(), self.bank_inst.by() + self.row_addr_dff_insts[port].height)
            row_addr_pos[port] = vector(x_offset, y_offset)
            self.row_addr_dff_insts[port].place(row_addr_pos[port], mirror="XY")

            # Add the col address flops below the bank to the right of the control logic
            x_offset = self.control_logic_insts[port].lx() - 2 * self.dff.width
            y_offset = self.bank.height + self.data_bus_size[port] + self.dff.height
            if self.col_addr_dff:
                col_addr_pos[port] = vector(x_offset - self.col_addr_dff_insts[port].width,
                                            y_offset)
                self.col_addr_dff_insts[port].place(col_addr_pos[port], mirror="MX")
                x_offset = self.col_addr_dff_insts[port].lx()
            else:
                col_addr_pos[port] = vector(x_offset, y_offset)
            
            if port in self.write_ports:
                # Add spare write enable flops to the right of the data flops since the spare
                # columns will be on the left
                if self.num_spare_cols:
                    spare_wen_pos[port] = vector(x_offset - self.spare_wen_dff_insts[port].width,
                                                 y_offset)
                    self.spare_wen_dff_insts[port].place(spare_wen_pos[port], mirror="MX")
                    x_offset = self.spare_wen_dff_insts[port].lx()

                if self.write_size:
                    # Add the write mask flops below the write mask AND array.
                    wmask_pos[port] = vector(x_offset - self.wmask_dff_insts[port].width,
                                             y_offset)
                    self.wmask_dff_insts[port].place(wmask_pos[port], mirror="MX")
                    x_offset = self.wmask_dff_insts[port].lx()

                # Add the data flops below the write mask flops.
                data_pos[port] = vector(x_offset - self.data_dff_insts[port].width,
                                        y_offset)
                self.data_dff_insts[port].place(data_pos[port], mirror="MX")
        else:
            wmask_pos[port] = vector(x_offset, y_offset)
            data_pos[port] = vector(x_offset, y_offset)
            spare_wen_pos[port] = vector(x_offset, y_offset)
Exemplo n.º 60
0
 def ul(self):
     """ Return the upper left corner """
     return vector(self.boundary[0].x, self.boundary[1].y)