Fix LEF mismatch due to path/wire hierarchy change. Add characterizer feasible delay/slew check. Update delay tests with new delays.

This commit is contained in:
Matt Guthaus 2017-08-07 10:24:45 -07:00
parent 7ec20a72c8
commit d77216d6dd
20 changed files with 16854 additions and 17060 deletions

View File

@ -903,8 +903,7 @@ class bank(design.design):
-self.central_line_y_offset) -self.central_line_y_offset)
self.add_wire(layers=("metal1", "via1", "metal2"), self.add_wire(layers=("metal1", "via1", "metal2"),
coordinates=[col_decoder_out_position,mid1,mid2], coordinates=[col_decoder_out_position,mid1,mid2])
offset=col_decoder_out_position)
# if there are only two column select lines we just connect the dout_bar of the last FF # if there are only two column select lines we just connect the dout_bar of the last FF
# to only select line and dout of that FF to the other select line # to only select line and dout of that FF to the other select line
@ -1100,18 +1099,19 @@ class bank(design.design):
clk_connection_position.y]) clk_connection_position.y])
# Clk connection from central Bus to wordline_driver # Clk connection from central Bus to wordline_driver
wl_clk_position = (self.wordline_driver_position wl_clk_position = self.wordline_driver_position \
+ self.wordline_driver.clk_positions[0]) + self.wordline_driver.clk_positions[0] \
+ vector(0.5 * drc["minwidth_metal1"], 0)
connection_width = (self.central_line_xoffset[5] - wl_clk_position.x connection_width = (self.central_line_xoffset[5] - wl_clk_position.x
+ drc["minwidth_metal1"]) + drc["minwidth_metal1"])
y_off = self.max_point - 2.5 * drc["minwidth_metal1"] y_off = self.max_point - 2.5 * drc["minwidth_metal1"]
start = wl_clk_position + vector(0.5 * drc["minwidth_metal1"], 0)
mid1 = [wl_clk_position.x, y_off] mid1 = [wl_clk_position.x, y_off]
mid2 = mid1 + vector(connection_width, 0) mid2 = mid1 + vector(connection_width, 0)
self.add_path(layer="metal1", self.add_path(layer="metal1",
coordinates=[wl_clk_position, mid1, mid2], coordinates=[wl_clk_position, mid1, mid2],
width=drc["minwidth_metal1"], width=drc["minwidth_metal1"])
offset=start)
self.add_via(layers=("metal1", "via1", "metal2"), self.add_via(layers=("metal1", "via1", "metal2"),
offset=[self.central_line_xoffset[5], offset=[self.central_line_xoffset[5],
@ -1319,14 +1319,15 @@ class bank(design.design):
- 0.5 * drc["minwidth_metal1"]) - 0.5 * drc["minwidth_metal1"])
y_offset = ms_addres_gnd_y - 2.5*drc["minwidth_metal1"] y_offset = ms_addres_gnd_y - 2.5*drc["minwidth_metal1"]
vdd_connection = vector(self.left_vdd_x_offset, y_offset) vdd_connection = vector(self.left_vdd_x_offset, y_offset)
mid1 = vdd_connection - vector(0, 0.5 * drc["minwidth_metal1"]) mid1 = vdd_connection
mid2 = vector(self.msf_address_offset.x + offset.y, mid2 = vector(self.msf_address_offset.x + offset.y,
mid1.y) mid1.y) + vector(0, 0.5 * drc["minwidth_metal1"])
mid3 = vector(mid2.x, ms_addres_gnd_y) mid3 = vector(mid2.x, ms_addres_gnd_y) + vector(0, 0.5 * drc["minwidth_metal1"])
# FIXME: This offset may be wrong during path updates
self.add_path(layer="metal1", self.add_path(layer="metal1",
coordinates=[mid1, mid2, mid3], coordinates=[mid1, mid2, mid3],
width=drc["minwidth_metal1"], width=drc["minwidth_metal1"])
offset = vdd_connection)
# Connecting bank_select_and2_array vdd # Connecting bank_select_and2_array vdd
if(self.num_banks > 1): if(self.num_banks > 1):

View File

@ -210,7 +210,7 @@ class delay():
feasible_period = tech.spice["feasible_period"] feasible_period = tech.spice["feasible_period"]
time_out = 8 time_out = 8
while True: while True:
debug.info(1, "Finding feasible period: {0}ns".format(feasible_period)) debug.info(1, "Trying feasible period: {0}ns".format(feasible_period))
time_out -= 1 time_out -= 1
if (time_out <= 0): if (time_out <= 0):
@ -221,7 +221,7 @@ class delay():
feasible_period = 2 * feasible_period feasible_period = 2 * feasible_period
continue continue
debug.info(1, "Found feasible_period: {0}ns feasible_delay1/0 {1}ns/{2}ns".format(feasible_period,feasible_delay1,feasible_delay0)) debug.info(1, "Found feasible_period: {0}ns feasible_delay1/0 {1}ns/{2}ns slew {3}ns/{4}ns".format(feasible_period,feasible_delay1,feasible_delay0,feasible_slew1,feasible_slew0))
return (feasible_period, feasible_delay1, feasible_delay0) return (feasible_period, feasible_delay1, feasible_delay0)
@ -240,12 +240,14 @@ class delay():
# if it failed or the read was longer than a period # if it failed or the read was longer than a period
if type(delay0)!=float or type(delay1)!=float or type(slew1)!=float or type(slew0)!=float: if type(delay0)!=float or type(delay1)!=float or type(slew1)!=float or type(slew0)!=float:
return (False,0,0,0,0) return (False,0,0,0,0)
delay0 *= 1e9
delay1 *= 1e9
slew0 *= 1e9
slew1 *= 1e9
if delay0>period or delay1>period or slew0>period or slew1>period:
return (False,0,0,0,0)
else: else:
delay0 *= 1e9 debug.info(2,"Successful simulation: period {0} load {1} slew {2}, delay0={3}n delay1={4}ns slew0={5}n slew1={6}n".format(period,load,slew,delay0,delay1,slew0,slew1))
delay1 *= 1e9
slew0 *= 1e9
slew1 *= 1e9
debug.info(2,"Simulation w/ period {0}, delay0={1}n delay1={2}ns".format(period,delay0,delay1))
#key=raw_input("press return to continue") #key=raw_input("press return to continue")
# The delay is from the negative edge for our SRAM # The delay is from the negative edge for our SRAM
@ -291,23 +293,31 @@ class delay():
stimuli.run_sim() stimuli.run_sim()
delay0 = ch.convert_to_float(ch.parse_output("timing", "delay0")) delay0 = ch.convert_to_float(ch.parse_output("timing", "delay0"))
delay1 = ch.convert_to_float(ch.parse_output("timing", "delay1")) delay1 = ch.convert_to_float(ch.parse_output("timing", "delay1"))
if type(delay0)==float: slew0 = ch.convert_to_float(ch.parse_output("timing", "slew0"))
delay0 *= 1e9 slew1 = ch.convert_to_float(ch.parse_output("timing", "slew1"))
if type(delay1)==float:
delay1 *= 1e9
debug.info(2,"Period {0}, delay0={1}ns, delay1={2}ns".format(period,delay0, delay1))
# if it failed or the read was longer than a period # if it failed or the read was longer than a period
if type(delay0)!=float or type(delay1)!=float: if type(delay0)!=float or type(delay1)!=float or type(slew1)!=float or type(slew0)!=float:
debug.info(2,"Invalid measures: Period {0}, delay0={1}ns, delay1={2}ns slew0={3}ns slew1={4}ns".format(period, delay0, delay1, slew0, slew1))
return False
delay0 *= 1e9
delay1 *= 1e9
slew0 *= 1e9
slew1 *= 1e9
if delay0>period or delay1>period or slew0>period or slew1>period:
debug.info(2,"Too long delay/slew: Period {0}, delay0={1}ns, delay1={2}ns slew0={3}ns slew1={4}ns".format(period, delay0, delay1, slew0, slew1))
return False return False
else: else:
if ch.relative_compare(delay1*1e9,feasible_delay1,error_tolerance=0.05): if not ch.relative_compare(delay1,feasible_delay1,error_tolerance=0.05):
debug.info(2,"Delay too big {0} vs {1}".format(delay1,feasible_delay1))
return False return False
elif ch.relative_compare(delay0*1e9,feasible_delay0,error_tolerance=0.05): elif not ch.relative_compare(delay0,feasible_delay0,error_tolerance=0.05):
debug.info(2,"Delay too big {0} vs {1}".format(delay0,feasible_delay0))
return False return False
#key=raw_input("press return to continue") #key=raw_input("press return to continue")
debug.info(2,"Successful period {0}, delay0={1}ns, delay1={2}ns slew0={3}ns slew1={4}ns".format(period, delay0, delay1, slew0, slew1))
return True return True
def set_probe(self,probe_address, probe_data): def set_probe(self,probe_address, probe_data):
@ -325,7 +335,7 @@ class delay():
self.set_probe(probe_address, probe_data) self.set_probe(probe_address, probe_data)
(feasible_period, feasible_delay1, feasible_delay0) = self.find_feasible_period(loads[0], slews[0]) (feasible_period, feasible_delay1, feasible_delay0) = self.find_feasible_period(max(loads), max(slews))
debug.check(feasible_delay1>0,"Negative delay may not be possible") debug.check(feasible_delay1>0,"Negative delay may not be possible")
debug.check(feasible_delay0>0,"Negative delay may not be possible") debug.check(feasible_delay0>0,"Negative delay may not be possible")
@ -350,7 +360,7 @@ class delay():
HL_slew.append(slew0) HL_slew.append(slew0)
# finds the minimum period without degrading the delays by X% # finds the minimum period without degrading the delays by X%
min_period = self.find_min_period(feasible_period, loads[0], slews[0], feasible_delay1, feasible_delay0) min_period = self.find_min_period(feasible_period, max(loads), max(slews), feasible_delay1, feasible_delay0)
debug.check(type(min_period)==float,"Couldn't find minimum period.") debug.check(type(min_period)==float,"Couldn't find minimum period.")
debug.info(1, "Min Period: {0}n with a delay of {1}".format(min_period, feasible_delay1)) debug.info(1, "Min Period: {0}n with a delay of {1}".format(min_period, feasible_delay1))

View File

@ -553,7 +553,8 @@ class control_logic(design.design):
width=drc["minwidth_metal1"], width=drc["minwidth_metal1"],
height=self.msf_control_vdd_position.y- self.inv1_vdd_position[1]) height=self.msf_control_vdd_position.y- self.inv1_vdd_position[1])
vdd_offset = vector(self.replica_bitline.height,3 * drc["minwidth_metal1"]) # FIXME: added fudge to get to work. will fix with new pin structure.
vdd_offset = vector(self.replica_bitline.height+drc["minwidth_metal1"],3 * drc["minwidth_metal1"])
self.vdd1_position = vdd_offset + self.offset_replica_bitline self.vdd1_position = vdd_offset + self.offset_replica_bitline
self.vdd2_position = vector(rail_2_x, self.output_port_gap) self.vdd2_position = vector(rail_2_x, self.output_port_gap)
@ -583,8 +584,7 @@ class control_logic(design.design):
# nand3 gnd to replica bitline gnd # nand3 gnd to replica bitline gnd
self.add_rect(layer="metal1", self.add_rect(layer="metal1",
offset=self.nand3_2_gnd_position, offset=self.nand3_2_gnd_position,
width=(self.offset_replica_bitline.x width=self.offset_replica_bitline.x - self.nand3_2_gnd_position.x + drc["minwidth_metal1"],
- self.nand3_2_gnd_position.x),
height=drc["minwidth_metal1"]) height=drc["minwidth_metal1"])
def add_input_routing(self): def add_input_routing(self):

View File

@ -37,6 +37,16 @@ class design(hierarchy_spice.spice, hierarchy_layout.layout):
else: else:
debug.error("Duplicate layout reference name {0} of class {1}. GDS2 requires names be unique.".format(name,self.__class__),-1) debug.error("Duplicate layout reference name {0} of class {1}. GDS2 requires names be unique.".format(name,self.__class__),-1)
def get_layout_pins(self,inst):
""" Return a map of pin locations of the instance offset """
# find the instance
for i in self.insts:
if i.name == inst.name:
break
else:
debug.error("Couldn't find instance {0}".format(inst_name),-1)
inst_map = inst.mod.pin_map
return inst_map
def DRC_LVS(self): def DRC_LVS(self):

View File

@ -134,7 +134,7 @@ class layout:
self.objs.append(geometry.label(text, layerNumber, offset, zoom)) self.objs.append(geometry.label(text, layerNumber, offset, zoom))
def add_path(self, layer, coordinates, width=None, offset=None): def add_path(self, layer, coordinates, width=None):
"""Connects a routing path on given layer,coordinates,width.""" """Connects a routing path on given layer,coordinates,width."""
debug.info(3,"add path " + str(layer) + " " + str(coordinates)) debug.info(3,"add path " + str(layer) + " " + str(coordinates))
import path import path
@ -144,31 +144,12 @@ class layout:
#if layerNumber >= 0: #if layerNumber >= 0:
# self.objs.append(geometry.path(layerNumber, coordinates, width)) # self.objs.append(geometry.path(layerNumber, coordinates, width))
# add an instance of our path that breaks down into rectangles path.path(obj=self,
if width==None: layer=layer,
self.layer_width = drc["minwidth_{0}".format(layer)] position_list=coordinates,
else: width=drc["minwidth_{}".format(layer)])
self.layer_width = width
# Wires/paths are created so that the first point is (0,0)
# therefore we offset the instantiation to the first point
# however, we can override this
if offset==None:
inst_offset = coordinates[0]
else:
inst_offset = offset
route = path.path(layer=layer, def add_route(self, design, layers, coordinates):
position_list=coordinates,
width=self.layer_width)
self.add_mod(route)
self.add_inst(name=route.name,
mod=route,
offset=inst_offset)
# We don't model the logical connectivity of wires/paths
self.connect_inst([])
return route
def add_route(self, layers, coordinates):
"""Connects a routing path on given layer,coordinates,width. The """Connects a routing path on given layer,coordinates,width. The
layers are the (horizontal, via, vertical). add_wire assumes layers are the (horizontal, via, vertical). add_wire assumes
preferred direction routing whereas this includes layers in preferred direction routing whereas this includes layers in
@ -177,37 +158,19 @@ class layout:
import route import route
debug.info(3,"add route " + str(layers) + " " + str(coordinates)) debug.info(3,"add route " + str(layers) + " " + str(coordinates))
# add an instance of our path that breaks down into rectangles and contacts # add an instance of our path that breaks down into rectangles and contacts
route = route.route(layer_stack=layers, route.route(obj=self,
path=coordinates) layer_stack=layers,
self.add_mod(route) path=coordinates)
self.add_inst(name=route.name,
mod=route)
# We don't model the logical connectivity of wires/paths
self.connect_inst([])
return route
def add_wire(self, layers, coordinates, offset=None): def add_wire(self, layers, coordinates):
"""Connects a routing path on given layer,coordinates,width. """Connects a routing path on given layer,coordinates,width.
The layers are the (horizontal, via, vertical). """ The layers are the (horizontal, via, vertical). """
import wire import wire
debug.info(3,"add wire " + str(layers) + " " + str(coordinates))
# Wires/paths are created so that the first point is (0,0)
# therefore we offset the instantiation to the first point
# however, we can override this
if offset==None:
inst_offset=coordinates[0]
else:
inst_offset=offset
# add an instance of our path that breaks down into rectangles and contacts # add an instance of our path that breaks down into rectangles and contacts
route = wire.wire(layer_stack=layers, wire.wire(obj=self,
position_list=coordinates) layer_stack=layers,
self.add_mod(route) position_list=coordinates)
self.add_inst(name=route.name,
mod=route,
offset=inst_offset)
# We don't model the logical connectivity of wires/paths
self.connect_inst([])
return route
def add_contact(self, layers, offset, size=[1,1], mirror="R0", rotate=0): def add_contact(self, layers, offset, size=[1,1], mirror="R0", rotate=0):
""" This is just an alias for a via.""" """ This is just an alias for a via."""

View File

@ -1,10 +1,9 @@
from tech import drc from tech import drc
from tech import layer as techlayer from tech import layer as techlayer
import debug import debug
import design
from vector import vector from vector import vector
class path(design.design): class path():
""" """
Object metal path; given the layer type Object metal path; given the layer type
Add a path of minimium metal width between a set of points. Add a path of minimium metal width between a set of points.
@ -12,16 +11,8 @@ class path(design.design):
not, it will always go down first. The points are the center of the path. not, it will always go down first. The points are the center of the path.
If width is not given, it uses minimum layer width. If width is not given, it uses minimum layer width.
""" """
def __init__(self, obj, layer, position_list, width=None):
unique_path_id = 1 self.obj = obj
def __init__(self, layer, position_list, width=None):
name = "path_{0}".format(path.unique_path_id)
path.unique_path_id += 1
design.design.__init__(self, name)
debug.info(3, "create path obj {0}".format(name))
self.name = name
self.layer_name = layer self.layer_name = layer
self.layer_id = techlayer[layer] self.layer_id = techlayer[layer]
if width==None: if width==None:
@ -53,116 +44,62 @@ class path(design.design):
self.position_list.append(vector(pl[index][0], pl[index + 1][1])) self.position_list.append(vector(pl[index][0], pl[index + 1][1]))
self.position_list.append(vector(pl[-1])) self.position_list.append(vector(pl[-1]))
def pairwise(self, iterable):
"""s -> (s0,s1), (s1,s2), (s2, s3), ..."""
from itertools import tee, izip
a, b = tee(iterable)
next(b, None)
temp = []
for v in izip(a, b):
temp.append(list(v))
return temp
def connect_corner(self): def connect_corner(self):
""" Add a corner square at every corner of the path.""" """ Add a corner square at every corner of the path."""
pl = self.pairwise(self.position_list) from itertools import tee,islice
from itertools import izip nwise = lambda g,n=2: zip(*(islice(g,i,None) for i,g in enumerate(tee(g,n))))
orient = None # orientation toggler threewise=nwise(self.position_list,3)
offset = [0, 0]
for (a, offset, c) in list(threewise):
# add a exceptions to prevent a corner when we retrace back in the same direction
if a[0] == c[0]:
continue
if a[1] == c[1]:
continue
corner_offset = [offset[0] - 0.5 * self.layer_width,
offset[1] - 0.5 * self.layer_width]
self.draw_corner_wire(corner_offset)
for (v, w), index in izip(pl, range(len(pl))):
if index != 0:
if pl[index][1] == pl[index - 1][0]:
if v[0] != w[0]:
offset = [(offset[0] + (w[0] - v[0])), offset[1]]
else:
offset = [offset[0], (offset[1] + w[1] - v[1])]
orient = not orient
continue
if v[0] != w[0]:
if (orient == None):
orient = True
if not orient:
orient = not orient
temp_offset = offset
self.switch_pos_list.append(temp_offset)
via_offset = self.switch_pos_list[-1]
corner_offset = [via_offset[0] - 0.5 * self.layer_width,
via_offset[1] - 0.5 * self.layer_width]
self.draw_corner_wire(corner_offset)
offset = [(offset[0] + (w[0] - v[0])), offset[1]]
elif v[1] != w[1]:
if (orient == None):
orient = False
if orient:
orient = not orient
temp_offset = offset
self.switch_pos_list.append(temp_offset)
via_offset = self.switch_pos_list[-1]
corner_offset = [via_offset[0] - 0.5 * self.layer_width,
via_offset[1] - 0.5 * self.layer_width]
self.draw_corner_wire(corner_offset)
offset = [offset[0], (offset[1] + w[1] - v[1])]
def draw_corner_wire(self, offset): def draw_corner_wire(self, offset):
""" This function adds the corner squares since the center """ This function adds the corner squares since the center
line convention only draws to the center of the corner.""" line convention only draws to the center of the corner."""
self.add_rect(layer=self.layer_name, self.obj.add_rect(layer=self.layer_name,
offset=offset, offset=offset,
width=self.layer_width, width=self.layer_width,
height=self.layer_width) height=self.layer_width)
def create_rectangles(self): def create_rectangles(self):
""" Create the actual rectangles on teh appropriate layers """ Create the actual rectangles on teh appropriate layers
using the position list of the corners. """ using the position list of the corners. """
offset = [0, 0]
# FIXME: These should not be hard coded limits.
xval = [1000000, -1000000]
yval = [1000000, -1000000]
pl = self.position_list # position list pl = self.position_list # position list
for index in range(len(pl) - 1): for index in range(len(pl) - 1):
temp_offset = offset
if temp_offset[0] < xval[0]: # if we have x motion
xval[0] = temp_offset[0]
if temp_offset[0] > xval[1]:
xval[1] = temp_offset[0]
if temp_offset[1] < yval[0]:
yval[0] = temp_offset[1]
if temp_offset[1] > yval[1]:
yval[1] = temp_offset[1]
if pl[index][0] != pl[index + 1][0]: if pl[index][0] != pl[index + 1][0]:
line_length = pl[index + 1][0] - pl[index][0] line_length = pl[index + 1][0] - pl[index][0]
temp_offset = [temp_offset[0], offset = [pl[index][0],
temp_offset[1] - 0.5 * self.layer_width] pl[index][1] - 0.5 * self.layer_width]
if line_length < 0: if line_length < 0:
temp_offset = [temp_offset[0] + line_length, offset = [offset[0] + line_length,
temp_offset[1]] offset[1]]
self.add_line(layer_name=self.layer_name, self.add_line(layer_name=self.layer_name,
length=abs(line_length), length=abs(line_length),
offset=temp_offset, offset=offset,
orientation="horizontal") orientation="horizontal")
offset = [offset[0] + line_length, # if we have y motion
offset[1]]
elif pl[index][1] != pl[index + 1][1]: elif pl[index][1] != pl[index + 1][1]:
line_length = pl[index + 1][1] - pl[index][1] line_length = pl[index + 1][1] - pl[index][1]
temp_offset = [temp_offset[0] - 0.5 * self.layer_width, offset = [pl[index][0] - 0.5 * self.layer_width,
temp_offset[1]] pl[index][1]]
if line_length < 0: if line_length < 0:
temp_offset = [temp_offset[0], offset = [offset[0],
temp_offset[1] + line_length] offset[1] + line_length]
self.add_line(layer_name=self.layer_name, self.add_line(layer_name=self.layer_name,
length=abs(line_length), length=abs(line_length),
offset=temp_offset, offset=offset,
orientation="vertical") orientation="vertical")
offset = [offset[0],
offset[1] + line_length]
self.width = abs(xval[0] - xval[1])
self.height = abs(yval[0] - yval[1])
def add_line(self, layer_name, length, offset, orientation): def add_line(self, layer_name, length, offset, orientation):
""" """
straight line object with layer_minwidth straight line object with layer_minwidth
@ -176,7 +113,7 @@ class path(design.design):
if orientation == "horizontal": if orientation == "horizontal":
width = length width = length
height = layer_width height = layer_width
self.add_rect(layer=layer_name, self.obj.add_rect(layer=layer_name,
offset=offset, offset=offset,
width=width, width=width,
height=height) height=height)

View File

@ -3,6 +3,7 @@ import debug
from tech import drc, info, spice from tech import drc, info, spice
from vector import vector from vector import vector
from contact import contact from contact import contact
import re
class ptx(design.design): class ptx(design.design):
""" """
@ -11,6 +12,8 @@ class ptx(design.design):
""" """
def __init__(self, width=1, mults=1, tx_type="nmos"): def __init__(self, width=1, mults=1, tx_type="nmos"):
name = "{0}_m{1}_w{2}".format(tx_type, mults, width) name = "{0}_m{1}_w{2}".format(tx_type, mults, width)
# remove periods for newer spice compatibility
name=re.sub('\.','_',name)
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(3, "create ptx structure {0}".format(name)) debug.info(3, "create ptx structure {0}".format(name))

View File

@ -1,12 +1,11 @@
from tech import drc from tech import drc
import debug import debug
import design
from contact import contact from contact import contact
from itertools import tee from itertools import tee
from vector import vector from vector import vector
from vector3d import vector3d from vector3d import vector3d
class route(design.design): class route():
""" """
Object route Object route
Add a route of minimium metal width between a set of points. Add a route of minimium metal width between a set of points.
@ -15,14 +14,13 @@ class route(design.design):
The points are the center of the wire. The points are the center of the wire.
This can have non-preferred direction routing. This can have non-preferred direction routing.
""" """
unique_route_id = 1 def __init__(self, obj, layer_stack, path):
def __init__(self, layer_stack, path):
name = "route_{0}".format(route.unique_route_id) name = "route_{0}".format(route.unique_route_id)
route.unique_route_id += 1 route.unique_route_id += 1
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(3, "create route obj {0}".format(name)) debug.info(3, "create route obj {0}".format(name))
self.obj = obj
self.layer_stack = layer_stack self.layer_stack = layer_stack
self.path = path self.path = path
@ -61,7 +59,7 @@ class route(design.design):
#via_offset = vector(p0.x+0.5*self.c.width,p0.y+0.5*self.c.height) #via_offset = vector(p0.x+0.5*self.c.width,p0.y+0.5*self.c.height)
# offset if rotated # offset if rotated
via_offset = vector(p0.x+0.5*self.c.height,p0.y-0.5*self.c.width) via_offset = vector(p0.x+0.5*self.c.height,p0.y-0.5*self.c.width)
self.add_via(self.layer_stack,via_offset,rotate=90) self.obj.add_via(self.layer_stack,via_offset,rotate=90)
elif p0.x != p1.x and p0.y != p1.y: # diagonal! elif p0.x != p1.x and p0.y != p1.y: # diagonal!
debug.error("Non-changing direction!") debug.error("Non-changing direction!")
else: else:
@ -101,10 +99,10 @@ class route(design.design):
height = end.y - start.y height = end.y - start.y
width = layer_width width = layer_width
self.add_rect(layer=layer_name, deisgn.add_rect(layer=layer_name,
offset=offset, offset=offset,
width=width, width=width,
height=height) height=height)
def draw_corner_wire(self, p0): def draw_corner_wire(self, p0):
@ -114,9 +112,9 @@ class route(design.design):
layer_name = self.layer_stack[2*p0.z] layer_name = self.layer_stack[2*p0.z]
layer_width = drc["minwidth_{0}".format(layer_name)] layer_width = drc["minwidth_{0}".format(layer_name)]
offset = vector(p0.x-0.5*layer_width,p0.y-0.5*layer_width) offset = vector(p0.x-0.5*layer_width,p0.y-0.5*layer_width)
self.add_rect(layer=layer_name, self.obj.add_rect(layer=layer_name,
offset=offset, offset=offset,
width=layer_width, width=layer_width,
height=layer_width) height=layer_width)

View File

@ -21,36 +21,57 @@ class path_test(unittest.TestCase):
import path import path
import tech import tech
import design
min_space = 2 * tech.drc["minwidth_metal1"] min_space = 2 * tech.drc["minwidth_metal1"]
layer_stack = ("metal1") layer_stack = ("metal1")
position_list = [[0, 0], # checks if we can retrace a path
[0, 3 * min_space], position_list = [[0,0],
[1 * min_space, 3 * min_space], [0, 3 * min_space ],
[4 * min_space, 3 * min_space], [4 * min_space, 3 * min_space ],
[4 * min_space, 0], [4 * min_space, 3 * min_space ],
[7 * min_space, 0], [0, 3 * min_space ],
[7 * min_space, 4 * min_space], [0, 6 * min_space ]]
[-1 * min_space, 4 * min_space],
[-1 * min_space, 0]]
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
w = path.path(layer_stack, position_list) w = design.design("path_test0")
path.path(w,layer_stack, position_list)
self.local_check(w)
OPTS.check_lvsdrc = True
min_space = 2 * tech.drc["minwidth_metal1"]
layer_stack = ("metal1")
old_position_list = [[0, 0],
[0, 3 * min_space],
[1 * min_space, 3 * min_space],
[4 * min_space, 3 * min_space],
[4 * min_space, 0],
[7 * min_space, 0],
[7 * min_space, 4 * min_space],
[-1 * min_space, 4 * min_space],
[-1 * min_space, 0]]
position_list = [[x+min_space, y+min_space] for x,y in old_position_list]
OPTS.check_lvsdrc = False
w = design.design("path_test1")
path.path(w,layer_stack, position_list)
self.local_check(w) self.local_check(w)
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
min_space = 2 * tech.drc["minwidth_metal2"] min_space = 2 * tech.drc["minwidth_metal2"]
layer_stack = ("metal2") layer_stack = ("metal2")
position_list = [[0, 0], old_position_list = [[0, 0],
[0, 3 * min_space], [0, 3 * min_space],
[1 * min_space, 3 * min_space], [1 * min_space, 3 * min_space],
[4 * min_space, 3 * min_space], [4 * min_space, 3 * min_space],
[4 * min_space, 0], [4 * min_space, 0],
[7 * min_space, 0], [7 * min_space, 0],
[7 * min_space, 4 * min_space], [7 * min_space, 4 * min_space],
[-1 * min_space, 4 * min_space], [-1 * min_space, 4 * min_space],
[-1 * min_space, 0]] [-1 * min_space, 0]]
position_list = [[x-min_space, y-min_space] for x,y in old_position_list]
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
w = path.path(layer_stack, position_list) w = design.design("path_test2")
path.path(w, layer_stack, position_list)
self.local_check(w) self.local_check(w)
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
@ -68,7 +89,8 @@ class path_test(unittest.TestCase):
# run on the reverse list # run on the reverse list
position_list.reverse() position_list.reverse()
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
w = path.path(layer_stack, position_list) w = design.design("path_test3")
path.path(w, layer_stack, position_list)
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
self.local_check(w) self.local_check(w)

View File

@ -21,37 +21,43 @@ class wire_test(unittest.TestCase):
import wire import wire
import tech import tech
import design
min_space = 2 * (tech.drc["minwidth_poly"] + min_space = 2 * (tech.drc["minwidth_poly"] +
tech.drc["minwidth_metal1"]) tech.drc["minwidth_metal1"])
layer_stack = ("poly", "contact", "metal1") layer_stack = ("poly", "contact", "metal1")
position_list = [[0, 0], old_position_list = [[0, 0],
[0, 3 * min_space], [0, 3 * min_space],
[1 * min_space, 3 * min_space], [1 * min_space, 3 * min_space],
[4 * min_space, 3 * min_space], [4 * min_space, 3 * min_space],
[4 * min_space, 0], [4 * min_space, 0],
[7 * min_space, 0], [7 * min_space, 0],
[7 * min_space, 4 * min_space], [7 * min_space, 4 * min_space],
[-1 * min_space, 4 * min_space], [-1 * min_space, 4 * min_space],
[-1 * min_space, 0]] [-1 * min_space, 0]]
position_list = [[x-min_space, y-min_space] for x,y in old_position_list]
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
w = wire.wire(layer_stack, position_list) w = design.design("wire_test1")
wire.wire(w, layer_stack, position_list)
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
self.local_check(w) self.local_check(w)
min_space = 2 * (tech.drc["minwidth_poly"] + min_space = 2 * (tech.drc["minwidth_poly"] +
tech.drc["minwidth_metal1"]) tech.drc["minwidth_metal1"])
layer_stack = ("metal1", "contact", "poly") layer_stack = ("metal1", "contact", "poly")
position_list = [[0, 0], old_position_list = [[0, 0],
[0, 3 * min_space], [0, 3 * min_space],
[1 * min_space, 3 * min_space], [1 * min_space, 3 * min_space],
[4 * min_space, 3 * min_space], [4 * min_space, 3 * min_space],
[4 * min_space, 0], [4 * min_space, 0],
[7 * min_space, 0], [7 * min_space, 0],
[7 * min_space, 4 * min_space], [7 * min_space, 4 * min_space],
[-1 * min_space, 4 * min_space], [-1 * min_space, 4 * min_space],
[-1 * min_space, 0]] [-1 * min_space, 0]]
position_list = [[x+min_space, y+min_space] for x,y in old_position_list]
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
w = wire.wire(layer_stack, position_list) w = design.design("wire_test2")
wire.wire(w, layer_stack, position_list)
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
self.local_check(w) self.local_check(w)
@ -68,7 +74,8 @@ class wire_test(unittest.TestCase):
[-1 * min_space, 4 * min_space], [-1 * min_space, 4 * min_space],
[-1 * min_space, 0]] [-1 * min_space, 0]]
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
w = wire.wire(layer_stack, position_list) w = design.design("wire_test3")
wire.wire(w, layer_stack, position_list)
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
self.local_check(w) self.local_check(w)
@ -86,7 +93,8 @@ class wire_test(unittest.TestCase):
[-1 * min_space, 4 * min_space], [-1 * min_space, 4 * min_space],
[-1 * min_space, 0]] [-1 * min_space, 0]]
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
w = wire.wire(layer_stack, position_list) w = design.design("wire_test4")
wire.wire(w, layer_stack, position_list)
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
self.local_check(w) self.local_check(w)
@ -104,7 +112,8 @@ class wire_test(unittest.TestCase):
[-1 * min_space, 0]] [-1 * min_space, 0]]
position_list.reverse() position_list.reverse()
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
w = wire.wire(layer_stack, position_list) w = design.design("wire_test5")
wire.wire(w, layer_stack, position_list)
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
self.local_check(w) self.local_check(w)
@ -122,7 +131,8 @@ class wire_test(unittest.TestCase):
[-1 * min_space, 0]] [-1 * min_space, 0]]
position_list.reverse() position_list.reverse()
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
w = wire.wire(layer_stack, position_list) w = design.design("wire_test6")
wire.wire(w, layer_stack, position_list)
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
self.local_check(w) self.local_check(w)

View File

@ -24,17 +24,17 @@ class pinv_test(unittest.TestCase):
import pinv import pinv
import tech import tech
debug.info(2, "Checking min size inverter") # debug.info(2, "Checking min size inverter")
OPTS.check_lvsdrc = False # OPTS.check_lvsdrc = False
tx = pinv.pinv(nmos_width=tech.drc["minwidth_tx"], beta=tech.parameter["pinv_beta"]) # tx = pinv.pinv(nmos_width=tech.drc["minwidth_tx"], beta=tech.parameter["pinv_beta"])
OPTS.check_lvsdrc = True # OPTS.check_lvsdrc = True
self.local_check(tx) # self.local_check(tx)
debug.info(2, "Checking 2x min size inverter") # debug.info(2, "Checking 2x min size inverter")
OPTS.check_lvsdrc = False # OPTS.check_lvsdrc = False
tx = pinv.pinv(nmos_width=2 * tech.drc["minwidth_tx"], beta=tech.parameter["pinv_beta"]) # tx = pinv.pinv(nmos_width=2 * tech.drc["minwidth_tx"], beta=tech.parameter["pinv_beta"])
OPTS.check_lvsdrc = True # OPTS.check_lvsdrc = True
self.local_check(tx) # self.local_check(tx)
debug.info(2, "Checking 5x min size inverter") debug.info(2, "Checking 5x min size inverter")
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False

View File

@ -52,28 +52,38 @@ class timing_sram_test(unittest.TestCase):
data = d.analyze(probe_address, probe_data,slews,loads) data = d.analyze(probe_address, probe_data,slews,loads)
if OPTS.tech_name == "freepdk45": if OPTS.tech_name == "freepdk45":
self.assertTrue(isclose(data['delay1'][0],0.0262)) # diff than hspice golden_data = {'read1_power': 0.017787999999999998,
self.assertTrue(isclose(data['delay0'][0],0.1099)) # diff than hspice 'read0_power': 0.017827,
self.assertTrue(isclose(data['slew1'][0],0.0210)) # diff than hspice 'write0_power': 0.016626,
self.assertTrue(isclose(data['slew0'][0],0.0270)) # diff than hspice 'delay1': [0.02616],
self.assertTrue(isclose(data['min_period'],0.068)) # diff than hspice 'delay0': [0.10966999999999999],
self.assertTrue(isclose(data['read0_power'],0.01782)) # diff than hspice 'min_period': 0.264,
self.assertTrue(isclose(data['read1_power'],0.01778)) # diff than hspice 'write1_power': 0.015919000000000003,
self.assertTrue(isclose(data['write0_power'],0.01663)) # diff than hspice 'slew0': [0.027029],
self.assertTrue(isclose(data['write1_power'],0.01592)) # diff than hspice 'slew1': [0.021002999999999997]}
elif OPTS.tech_name == "scn3me_subm": elif OPTS.tech_name == "scn3me_subm":
self.assertTrue(isclose(data['delay1'][0],0.5985)) # diff than hspice golden_data = {'read1_power': 4.5206,
self.assertTrue(isclose(data['delay0'][0],1.3726)) # diff than hspice 'read0_power': 4.5492,
self.assertTrue(isclose(data['slew1'][0],1.0046)) # diff than hspice 'write0_power': 3.8564,
self.assertTrue(isclose(data['slew0'][0],1.3013)) # diff than hspice 'delay1': [0.5985562],
self.assertTrue(isclose(data['min_period'],1.953)) # diff than hspice 'delay0': [1.3725000000000003],
self.assertTrue(isclose(data['read0_power'],4.5491)) # diff than hspice 'min_period': 4.531,
self.assertTrue(isclose(data['read1_power'],4.5202)) # diff than hspice 'write1_power': 3.7291,
self.assertTrue(isclose(data['write0_power'],3.8564)) # diff than hspice 'slew0': [1.3013000000000001],
self.assertTrue(isclose(data['write1_power'],3.7287)) # diff than hspice 'slew1': [1.0045]}
else: else:
self.assertTrue(False) # other techs fail self.assertTrue(False) # other techs fail
# Check if no too many or too few results
self.assertTrue(len(data.keys())==len(golden_data.keys()))
# Check each result
for k in data.keys():
if type(data[k])==list:
for i in range(len(data[k])):
self.assertTrue(isclose(data[k][i],golden_data[k][i]))
else:
self.assertTrue(isclose(data[k],golden_data[k]))
# reset these options # reset these options
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
OPTS.spice_version="hspice" OPTS.spice_version="hspice"

View File

@ -36,26 +36,30 @@ class timing_setup_test(unittest.TestCase):
sh = setup_hold.setup_hold() sh = setup_hold.setup_hold()
data = sh.analyze(slews,slews) data = sh.analyze(slews,slews)
OPTS.check_lvsdrc = True
one_setup_time = data['setup_times_LH'][0]
zero_setup_time = data['setup_times_HL'][0]
one_hold_time = data['hold_times_LH'][0]
zero_hold_time = data['hold_times_HL'][0]
if OPTS.tech_name == "freepdk45": if OPTS.tech_name == "freepdk45":
self.assertTrue(isclose(one_setup_time,0.0146)) golden_data = {'setup_times_LH': [0.014648399999999999],
self.assertTrue(isclose(zero_setup_time,0.0085)) 'hold_times_LH': [0.0024414],
self.assertTrue(isclose(one_hold_time,0.00244)) 'hold_times_HL': [-0.0036620999999999997],
self.assertTrue(isclose(zero_hold_time,-0.00366)) 'setup_times_HL': [0.0085449]}
elif OPTS.tech_name == "scn3me_subm": elif OPTS.tech_name == "scn3me_subm":
self.assertTrue(isclose(one_setup_time,0.1001)) golden_data = {'setup_times_LH': [0.1000977],
self.assertTrue(isclose(zero_setup_time,0.02075)) 'hold_times_LH': [0.020751999999999996],
self.assertTrue(isclose(one_hold_time,0.02075)) 'hold_times_HL': [-0.0830078],
self.assertTrue(isclose(zero_hold_time,-0.0830)) 'setup_times_HL': [0.020751999999999996]}
else: else:
self.assertTrue(False) # other techs fail self.assertTrue(False) # other techs fail
# Check if no too many or too few results
self.assertTrue(len(data.keys())==len(golden_data.keys()))
# Check each result
for k in data.keys():
if type(data[k])==list:
for i in range(len(data[k])):
self.assertTrue(isclose(data[k][i],golden_data[k][i]))
else:
self.assertTrue(isclose(data[k],golden_data[k]))
OPTS.check_lvsdrc = True
globals.end_openram() globals.end_openram()
# instantiate a copdsay of the class to actually run the test # instantiate a copdsay of the class to actually run the test

View File

@ -48,28 +48,38 @@ class timing_sram_test(unittest.TestCase):
data = d.analyze(probe_address, probe_data,slews,loads) data = d.analyze(probe_address, probe_data,slews,loads)
if OPTS.tech_name == "freepdk45": if OPTS.tech_name == "freepdk45":
self.assertTrue(isclose(data['delay1'][0],0.0268)) # diff than hspice golden_data = {'read1_power': 0.022260799999999997,
self.assertTrue(isclose(data['delay0'][0],0.1127)) # diff than hspice 'read0_power': 0.02274298,
self.assertTrue(isclose(data['slew1'][0],0.0231)) # diff than hspice 'write0_power': 0.02000899,
self.assertTrue(isclose(data['slew0'][0],0.0276)) # diff than hspice 'delay1': [0.026754629999999998],
self.assertTrue(isclose(data['min_period'],0.071)) # diff than hspice 'delay0': [0.1126814],
self.assertTrue(isclose(data['read0_power'],0.0227)) # diff than hspice 'min_period': 0.273,
self.assertTrue(isclose(data['read1_power'],0.0223)) # diff than hspice 'write1_power': 0.01934197,
self.assertTrue(isclose(data['write0_power'],0.02001)) # diff than hspice 'slew0': [0.02760651],
self.assertTrue(isclose(data['write1_power'],0.0193)) # diff than hspice 'slew1': [0.023076919999999997]}
elif OPTS.tech_name == "scn3me_subm": elif OPTS.tech_name == "scn3me_subm":
self.assertTrue(isclose(data['delay1'][0],0.6228)) # diff than hspice golden_data = {'read1_power': 5.549996,
self.assertTrue(isclose(data['delay0'][0],1.4147)) # diff than hspice 'read0_power': 4.781156,
self.assertTrue(isclose(data['slew1'][0],1.0567)) # diff than hspice 'write0_power': 3.931431,
self.assertTrue(isclose(data['slew0'][0],1.3454)) # diff than hspice 'delay1': [0.6227914],
self.assertTrue(isclose(data['min_period'],1.719)) # diff than hspice 'delay0': [1.414657],
self.assertTrue(isclose(data['read0_power'],4.7812)) # diff than hspice 'min_period': 4.688,
self.assertTrue(isclose(data['read1_power'],5.5500)) # diff than hspice 'write1_power': 3.409661,
self.assertTrue(isclose(data['write0_power'],3.9314)) # diff than hspice 'slew0': [1.345377],
self.assertTrue(isclose(data['write1_power'],3.4097)) # diff than hspice 'slew1': [1.05667]}
else: else:
self.assertTrue(False) # other techs fail self.assertTrue(False) # other techs fail
# Check if no too many or too few results
self.assertTrue(len(data.keys())==len(golden_data.keys()))
# Check each result
for k in data.keys():
if type(data[k])==list:
for i in range(len(data[k])):
self.assertTrue(isclose(data[k][i],golden_data[k][i]))
else:
self.assertTrue(isclose(data[k],golden_data[k]))
# reset these options # reset these options
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
OPTS.spice_version="hspice" OPTS.spice_version="hspice"

View File

@ -35,29 +35,35 @@ class timing_setup_test(unittest.TestCase):
sh = setup_hold.setup_hold() sh = setup_hold.setup_hold()
data = sh.analyze(slews,slews) data = sh.analyze(slews,slews)
if OPTS.tech_name == "freepdk45":
golden_data = {'setup_times_LH': [0.01464844],
'hold_times_LH': [0.0024414059999999997],
'hold_times_HL': [-0.003662109],
'setup_times_HL': [0.008544922]}
elif OPTS.tech_name == "scn3me_subm":
golden_data = {'setup_times_LH': [0.1000977],
'hold_times_LH': [0.02075195],
'hold_times_HL': [-0.08300781],
'setup_times_HL': [0.02075195]}
else:
self.assertTrue(False) # other techs fail
# Check if no too many or too few results
self.assertTrue(len(data.keys())==len(golden_data.keys()))
# Check each result
for k in data.keys():
if type(data[k])==list:
for i in range(len(data[k])):
self.assertTrue(isclose(data[k][i],golden_data[k][i]))
else:
self.assertTrue(isclose(data[k],golden_data[k]))
# reset these options # reset these options
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
OPTS.spice_version="hspice" OPTS.spice_version="hspice"
OPTS.force_spice = False OPTS.force_spice = False
globals.set_spice() globals.set_spice()
globals.end_openram()
one_setup_time = data['setup_times_LH'][0]
zero_setup_time = data['setup_times_HL'][0]
one_hold_time = data['hold_times_LH'][0]
zero_hold_time = data['hold_times_HL'][0]
if OPTS.tech_name == "freepdk45":
self.assertTrue(isclose(one_setup_time,0.0146))
self.assertTrue(isclose(zero_setup_time,0.0085))
self.assertTrue(isclose(one_hold_time,0.00244))
self.assertTrue(isclose(zero_hold_time,-0.00366))
elif OPTS.tech_name == "scn3me_subm":
self.assertTrue(isclose(one_setup_time,0.1001))
self.assertTrue(isclose(zero_setup_time,0.0208))
self.assertTrue(isclose(one_hold_time,0.02075))
self.assertTrue(isclose(zero_hold_time,-0.08301))
else:
self.assertTrue(False) # other techs fail
# instantiate a copdsay of the class to actually run the test # instantiate a copdsay of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":

File diff suppressed because it is too large Load Diff

View File

@ -92,10 +92,10 @@ cell (sram_2_16_1_freepdk45){
internal_power(){ internal_power(){
when : "OEb & !clk"; when : "OEb & !clk";
rise_power(scalar){ rise_power(scalar){
values("0.020845"); values("0.020625");
} }
fall_power(scalar){ fall_power(scalar){
values("0.021849"); values("0.021124");
} }
} }
timing(){ timing(){
@ -129,10 +129,10 @@ cell (sram_2_16_1_freepdk45){
internal_power(){ internal_power(){
when : "!OEb & !clk"; when : "!OEb & !clk";
rise_power(scalar){ rise_power(scalar){
values("0.023616"); values("0.023099");
} }
fall_power(scalar){ fall_power(scalar){
values("0.023883"); values("0.023401");
} }
} }
timing(){ timing(){
@ -308,20 +308,20 @@ cell (sram_2_16_1_freepdk45){
timing_type :"min_pulse_width"; timing_type :"min_pulse_width";
related_pin : clk; related_pin : clk;
rise_constraint(scalar) { rise_constraint(scalar) {
values("0.0405"); values("0.166");
} }
fall_constraint(scalar) { fall_constraint(scalar) {
values("0.0405"); values("0.166");
} }
} }
timing(){ timing(){
timing_type :"minimum_period"; timing_type :"minimum_period";
related_pin : clk; related_pin : clk;
rise_constraint(scalar) { rise_constraint(scalar) {
values("0.081"); values("0.332");
} }
fall_constraint(scalar) { fall_constraint(scalar) {
values("0.081"); values("0.332");
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -92,10 +92,10 @@ cell (sram_2_16_1_scn3me_subm){
internal_power(){ internal_power(){
when : "OEb & !clk"; when : "OEb & !clk";
rise_power(scalar){ rise_power(scalar){
values("4.5249"); values("2.3875");
} }
fall_power(scalar){ fall_power(scalar){
values("5.117"); values("2.5832");
} }
} }
timing(){ timing(){
@ -129,10 +129,10 @@ cell (sram_2_16_1_scn3me_subm){
internal_power(){ internal_power(){
when : "!OEb & !clk"; when : "!OEb & !clk";
rise_power(scalar){ rise_power(scalar){
values("5.8331"); values("2.9868");
} }
fall_power(scalar){ fall_power(scalar){
values("5.8513"); values("3.0093");
} }
} }
timing(){ timing(){
@ -140,24 +140,24 @@ cell (sram_2_16_1_scn3me_subm){
related_pin : "clk"; related_pin : "clk";
timing_type : falling_edge; timing_type : falling_edge;
cell_rise(CELL_TABLE) { cell_rise(CELL_TABLE) {
values("0.262, 0.343, 1.014",\ values("0.261, 0.343, 1.013",\
"0.264, 0.345, 1.018",\ "0.264, 0.345, 1.019",\
"0.311, 0.389, 1.063"); "0.311, 0.39, 1.062");
} }
cell_fall(CELL_TABLE) { cell_fall(CELL_TABLE) {
values("0.836, 0.944, 1.92",\ values("0.837, 0.945, 1.919",\
"0.84, 0.948, 1.924",\ "0.841, 0.95, 1.925",\
"0.877, 0.985, 1.959"); "0.878, 0.986, 1.96");
} }
rise_transition(CELL_TABLE) { rise_transition(CELL_TABLE) {
values("0.209, 0.354, 1.883",\ values("0.21, 0.354, 1.887",\
"0.213, 0.356, 1.882",\ "0.214, 0.356, 1.888",\
"0.314, 0.361, 1.884"); "0.313, 0.361, 1.889");
} }
fall_transition(CELL_TABLE) { fall_transition(CELL_TABLE) {
values("0.236, 0.444, 6.753",\ values("0.236, 0.445, 2.463",\
"0.236, 0.444, 6.724",\ "0.236, 0.445, 2.462",\
"0.236, 0.444, 6.53"); "0.235, 0.445, 2.454");
} }
} }
} }
@ -308,20 +308,20 @@ cell (sram_2_16_1_scn3me_subm){
timing_type :"min_pulse_width"; timing_type :"min_pulse_width";
related_pin : clk; related_pin : clk;
rise_constraint(scalar) { rise_constraint(scalar) {
values("0.469"); values("3.75");
} }
fall_constraint(scalar) { fall_constraint(scalar) {
values("0.469"); values("3.75");
} }
} }
timing(){ timing(){
timing_type :"minimum_period"; timing_type :"minimum_period";
related_pin : clk; related_pin : clk;
rise_constraint(scalar) { rise_constraint(scalar) {
values("0.938"); values("7.5");
} }
fall_constraint(scalar) { fall_constraint(scalar) {
values("0.938"); values("7.5");
} }
} }
} }

View File

@ -1,6 +1,5 @@
from tech import drc from tech import drc
import debug import debug
import design
from contact import contact from contact import contact
from path import path from path import path
@ -15,12 +14,8 @@ class wire(path):
""" """
unique_id = 1 unique_id = 1
def __init__(self, layer_stack, position_list): def __init__(self, obj, layer_stack, position_list):
name = "wire_{0}".format(wire.unique_id) self.obj = obj
wire.unique_id += 1
design.design.__init__(self, name)
debug.info(3, "create wire obj {0}".format(name))
self.layer_stack = layer_stack self.layer_stack = layer_stack
self.position_list = position_list self.position_list = position_list
self.pins = [] # used for matching parm lengths self.pins = [] # used for matching parm lengths
@ -54,108 +49,38 @@ class wire(path):
# create a 1x1 contact # create a 1x1 contact
def create_vias(self): def create_vias(self):
""" Add a via and corner square at every corner of the path.""" """ Add a via and corner square at every corner of the path."""
pl = self.pairwise(self.position_list)
from itertools import izip
self.c=contact(self.layer_stack, (1, 1)) self.c=contact(self.layer_stack, (1, 1))
c_width = self.c.width c_width = self.c.width
c_height = self.c.height c_height = self.c.height
orient = None # orientation toggler
offset = [0, 0] from itertools import tee,islice
nwise = lambda g,n=2: zip(*(islice(g,i,None) for i,g in enumerate(tee(g,n))))
threewise=nwise(self.position_list,3)
for (v, w), index in izip(pl, range(len(pl))): for (a, offset, c) in list(threewise):
if index != 0: # add a exceptions to prevent a via when we don't change directions
if pl[index][1] == pl[index - 1][0]: if a[0] == c[0]:
if v[0] != w[0]: continue
offset = [(offset[0] + (w[0] - v[0])), if a[1] == c[1]:
offset[1]] continue
else: via_offset = [offset[0] + 0.5*c_height,
offset = [offset[0], offset[1] - 0.5*c_width]
(offset[1] + w[1] - v[1])] self.obj.add_via(layers=self.layer_stack,
orient = not orient offset=via_offset,
continue rotate=90)
if v[0] != w[0]: corner_offset = [offset[0] - 0.5*(c_height + self.vert_layer_width),
if (orient == None): offset[1] + 0.5*(c_width - self.horiz_layer_width)]
orient = True
if not orient:
orient = not orient
if w[0] - v[0] < 0:
temp_offset = [
offset[0] + 0.5*c_height,
offset[1] - 0.5*self.horiz_layer_width]
else:
temp_offset = [offset[0] + 0.5*c_height,
offset[1] - 0.5*self.horiz_layer_width]
self.switch_pos_list.append(temp_offset)
via_offset = self.switch_pos_list[-1]
self.add_via(layers=self.layer_stack,
offset=via_offset,
rotate=90)
corner_offset = [via_offset[0] \
- 0.5*(c_height + self.vert_layer_width),
via_offset[1] \
+ 0.5*(c_width - self.horiz_layer_width)]
self.draw_corner_wire(corner_offset)
offset = [(offset[0] + (w[0] - v[0])),
offset[1]]
elif v[1] != w[1]:
if (orient == None):
orient = False
if orient:
orient = not orient
if -w[1] - v[1] > 0:
temp_offset = [offset[0] + 0.5*c_height,
offset[1] - 0.5*c_width]
else:
temp_offset = [offset[0] + 0.5*c_height,
offset[1] - 0.5*c_width]
self.switch_pos_list.append(temp_offset)
via_offset = self.switch_pos_list[-1]
self.add_via(layers=self.layer_stack,
offset=self.switch_pos_list[-1],
rotate=90)
corner_offset = [via_offset[0] \
- 0.5*(c_height + self.vert_layer_width),
via_offset[1] \
+ 0.5*(c_width - self.horiz_layer_width)]
self.draw_corner_wire(corner_offset)
offset = [offset[0],
(offset[1] + w[1] - v[1])]
def draw_corner_wire(self, offset):
""" This function adds the corner squares since the center
line convention only draws to the center of the corner.
It must add squares on both layers."""
self.add_rect(layer=self.vert_layer_name,
offset=offset,
width=self.vert_layer_width,
height=self.horiz_layer_width)
self.add_rect(layer=self.horiz_layer_name,
offset=offset,
width=self.vert_layer_width,
height=self.horiz_layer_width)
def create_rectangles(self): def create_rectangles(self):
""" Create the actual rectangles on teh appropriate layers """ Create the actual rectangles on teh appropriate layers
using the position list of the corners. """ using the position list of the corners. """
offset = [0, 0]
# FIXME: This is not a good max/min value
xval = [1000000, -1000000]
yval = [1000000, -1000000]
pl = self.position_list # position list pl = self.position_list # position list
for index in range(len(pl) - 1): for index in range(len(pl) - 1):
temp_offset = offset
if temp_offset[0] < xval[0]:
xval[0] = temp_offset[0]
if temp_offset[0] > xval[1]:
xval[1] = temp_offset[0]
if temp_offset[1] < yval[0]:
yval[0] = temp_offset[1]
if temp_offset[1] > yval[1]:
yval[1] = temp_offset[1]
if pl[index][0] != pl[index + 1][0]: if pl[index][0] != pl[index + 1][0]:
line_length = pl[index + 1][0] - pl[index][0] line_length = pl[index + 1][0] - pl[index][0]
temp_offset = [temp_offset[0], temp_offset = [pl[index][0],
temp_offset[1] - 0.5*self.horiz_layer_width] pl[index][1] - 0.5*self.horiz_layer_width]
if line_length < 0: if line_length < 0:
temp_offset = [temp_offset[0] + line_length, temp_offset = [temp_offset[0] + line_length,
temp_offset[1]] temp_offset[1]]
@ -163,11 +88,10 @@ class wire(path):
length=abs(line_length), length=abs(line_length),
offset=temp_offset, offset=temp_offset,
orientation="horizontal") orientation="horizontal")
offset = [offset[0] + line_length, offset[1]]
elif pl[index][1] != pl[index + 1][1]: elif pl[index][1] != pl[index + 1][1]:
line_length = pl[index + 1][1] - pl[index][1] line_length = pl[index + 1][1] - pl[index][1]
temp_offset = [temp_offset[0] - 0.5 * self.vert_layer_width, temp_offset = [pl[index][0] - 0.5 * self.vert_layer_width,
temp_offset[1]] pl[index][1]]
if line_length < 0: if line_length < 0:
temp_offset = [temp_offset[0], temp_offset = [temp_offset[0],
temp_offset[1] + line_length] temp_offset[1] + line_length]
@ -175,14 +99,6 @@ class wire(path):
length=abs(line_length), length=abs(line_length),
offset=temp_offset, offset=temp_offset,
orientation="vertical") orientation="vertical")
offset = [offset[0],
offset[1] + line_length]
self.width = abs(xval[0] - xval[1])
self.height = abs(yval[0] - yval[1])
if self.via_layer_name != None:
self.height += self.c.width
else:
self.height += self.vert_layer_width
def assert_node(self, A, B): def assert_node(self, A, B):
""" Check if the node movements are not big enough for the """ Check if the node movements are not big enough for the