mirror of https://github.com/VLSIDA/OpenRAM.git
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:
parent
7ec20a72c8
commit
d77216d6dd
|
|
@ -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):
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
|
||||||
|
|
@ -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."""
|
||||||
|
|
|
||||||
137
compiler/path.py
137
compiler/path.py
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
@ -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
|
|
@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
130
compiler/wire.py
130
compiler/wire.py
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue