mirror of https://github.com/VLSIDA/OpenRAM.git
Merge branch 'tech_migration' into dev
This commit is contained in:
commit
dff28a9997
|
|
@ -172,6 +172,20 @@ class design(hierarchy_design):
|
||||||
self.well_extend_active = max(self.well_extend_active, self.nwell_extend_active)
|
self.well_extend_active = max(self.well_extend_active, self.nwell_extend_active)
|
||||||
if "pwell" in layer:
|
if "pwell" in layer:
|
||||||
self.well_extend_active = max(self.well_extend_active, self.pwell_extend_active)
|
self.well_extend_active = max(self.well_extend_active, self.pwell_extend_active)
|
||||||
|
|
||||||
|
# The active offset is due to the well extension
|
||||||
|
if "pwell" in layer:
|
||||||
|
self.pwell_enclose_active = drc("pwell_enclose_active")
|
||||||
|
else:
|
||||||
|
self.pwell_enclose_active = 0
|
||||||
|
if "nwell" in layer:
|
||||||
|
self.nwell_enclose_active = drc("nwell_enclose_active")
|
||||||
|
else:
|
||||||
|
self.nwell_enclose_active = 0
|
||||||
|
# Use the max of either so that the poly gates will align properly
|
||||||
|
self.well_enclose_active = max(self.pwell_enclose_active,
|
||||||
|
self.nwell_enclose_active,
|
||||||
|
self.active_space)
|
||||||
|
|
||||||
# These are for debugging previous manual rules
|
# These are for debugging previous manual rules
|
||||||
if False:
|
if False:
|
||||||
|
|
|
||||||
|
|
@ -695,8 +695,8 @@ class layout():
|
||||||
# we should add a boundary just for DRC in some technologies
|
# we should add a boundary just for DRC in some technologies
|
||||||
if not self.is_library_cell and not self.bounding_box:
|
if not self.is_library_cell and not self.bounding_box:
|
||||||
# If there is a boundary layer, and we didn't create one, add one.
|
# If there is a boundary layer, and we didn't create one, add one.
|
||||||
if "stdc" in techlayer.keys():
|
if "boundary" in techlayer.keys():
|
||||||
boundary_layer = "stdc"
|
boundary_layer = "boundary"
|
||||||
boundary = [self.find_lowest_coords(),
|
boundary = [self.find_lowest_coords(),
|
||||||
self.find_highest_coords()]
|
self.find_highest_coords()]
|
||||||
debug.check(boundary[0] and boundary[1], "No shapes to make a boundary.")
|
debug.check(boundary[0] and boundary[1], "No shapes to make a boundary.")
|
||||||
|
|
@ -1259,10 +1259,7 @@ class layout():
|
||||||
if OPTS.netlist_only:
|
if OPTS.netlist_only:
|
||||||
return
|
return
|
||||||
|
|
||||||
if "stdc" in techlayer.keys():
|
boundary_layer = "boundary"
|
||||||
boundary_layer = "stdc"
|
|
||||||
else:
|
|
||||||
boundary_layer = "boundary"
|
|
||||||
if not ur:
|
if not ur:
|
||||||
self.bounding_box = self.add_rect(layer=boundary_layer,
|
self.bounding_box = self.add_rect(layer=boundary_layer,
|
||||||
offset=ll,
|
offset=ll,
|
||||||
|
|
@ -1307,13 +1304,10 @@ class layout():
|
||||||
pin.ll(),
|
pin.ll(),
|
||||||
pin.width(),
|
pin.width(),
|
||||||
pin.height())
|
pin.height())
|
||||||
elif pin.layer == "m1":
|
|
||||||
self.add_power_pin(name, pin.center())
|
|
||||||
else:
|
|
||||||
debug.warning("{0} pins of {1} should be on {2} or metal1 for "\
|
|
||||||
"supply router."
|
|
||||||
.format(name, inst.name, self.pwr_grid_layer))
|
|
||||||
|
|
||||||
|
else:
|
||||||
|
self.add_power_pin(name, pin.center(), start_layer=pin.layer)
|
||||||
|
|
||||||
def add_power_pin(self, name, loc, size=[1, 1], directions=None, start_layer="m1"):
|
def add_power_pin(self, name, loc, size=[1, 1], directions=None, start_layer="m1"):
|
||||||
"""
|
"""
|
||||||
Add a single power pin from the lowest power_grid layer down to M1 (or li) at
|
Add a single power pin from the lowest power_grid layer down to M1 (or li) at
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
#
|
#
|
||||||
import debug
|
import debug
|
||||||
import design
|
import design
|
||||||
from tech import parameter
|
from tech import parameter, layer
|
||||||
from tech import cell_properties as props
|
from tech import cell_properties as props
|
||||||
from vector import vector
|
from vector import vector
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
|
|
@ -52,7 +52,6 @@ class dff_buf(design.design):
|
||||||
def create_layout(self):
|
def create_layout(self):
|
||||||
self.place_instances()
|
self.place_instances()
|
||||||
self.width = self.inv2_inst.rx()
|
self.width = self.inv2_inst.rx()
|
||||||
|
|
||||||
self.height = self.dff.height
|
self.height = self.dff.height
|
||||||
self.route_wires()
|
self.route_wires()
|
||||||
self.add_layout_pins()
|
self.add_layout_pins()
|
||||||
|
|
@ -120,39 +119,37 @@ class dff_buf(design.design):
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
self.inv1_inst.place(vector(self.dff_inst.rx() + well_spacing + self.well_extend_active, 0))
|
self.inv1_inst.place(vector(self.dff_inst.rx() + well_spacing + self.well_extend_active, 0))
|
||||||
|
|
||||||
# Add INV2 to the right
|
# Add INV2 to the right
|
||||||
self.inv2_inst.place(vector(self.inv1_inst.rx(), 0))
|
self.inv2_inst.place(vector(self.inv1_inst.rx(), 0))
|
||||||
|
|
||||||
def route_wires(self):
|
def route_wires(self):
|
||||||
|
if "li" in layer:
|
||||||
|
self.route_layer = "li"
|
||||||
|
else:
|
||||||
|
self.route_layer = "m1"
|
||||||
|
|
||||||
# Route dff q to inv1 a
|
# Route dff q to inv1 a
|
||||||
q_pin = self.dff_inst.get_pin("Q")
|
q_pin = self.dff_inst.get_pin("Q")
|
||||||
a1_pin = self.inv1_inst.get_pin("A")
|
a1_pin = self.inv1_inst.get_pin("A")
|
||||||
mid_x_offset = 0.5 * (a1_pin.cx() + q_pin.cx())
|
mid1 = vector(a1_pin.cx(), q_pin.cy())
|
||||||
mid1 = vector(mid_x_offset, q_pin.cy())
|
self.add_path(q_pin.layer, [q_pin.center(), mid1, a1_pin.center()])
|
||||||
mid2 = vector(mid_x_offset, a1_pin.cy())
|
self.add_via_stack_center(from_layer=a1_pin.layer,
|
||||||
self.add_path("m3", [q_pin.center(), mid1, mid2, a1_pin.center()])
|
to_layer=q_pin.layer,
|
||||||
self.add_via_center(layers=self.m2_stack,
|
offset=a1_pin.center())
|
||||||
offset=q_pin.center())
|
|
||||||
self.add_via_center(layers=self.m2_stack,
|
|
||||||
offset=a1_pin.center())
|
|
||||||
self.add_via_center(layers=self.m1_stack,
|
|
||||||
offset=a1_pin.center())
|
|
||||||
|
|
||||||
# Route inv1 z to inv2 a
|
# Route inv1 z to inv2 a
|
||||||
z1_pin = self.inv1_inst.get_pin("Z")
|
z1_pin = self.inv1_inst.get_pin("Z")
|
||||||
a2_pin = self.inv2_inst.get_pin("A")
|
a2_pin = self.inv2_inst.get_pin("A")
|
||||||
mid_x_offset = 0.5 * (z1_pin.cx() + a2_pin.cx())
|
self.mid_qb_pos = vector(0.5 * (z1_pin.cx() + a2_pin.cx()), z1_pin.cy())
|
||||||
self.mid_qb_pos = vector(mid_x_offset, z1_pin.cy())
|
self.add_zjog(z1_pin.layer, z1_pin.center(), a2_pin.center())
|
||||||
mid2 = vector(mid_x_offset, a2_pin.cy())
|
|
||||||
self.add_path("m1", [z1_pin.center(), self.mid_qb_pos, mid2, a2_pin.center()])
|
|
||||||
|
|
||||||
def add_layout_pins(self):
|
def add_layout_pins(self):
|
||||||
|
|
||||||
# Continous vdd rail along with label.
|
# Continous vdd rail along with label.
|
||||||
vdd_pin=self.dff_inst.get_pin("vdd")
|
vdd_pin=self.dff_inst.get_pin("vdd")
|
||||||
self.add_layout_pin(text="vdd",
|
self.add_layout_pin(text="vdd",
|
||||||
layer="m1",
|
layer=vdd_pin.layer,
|
||||||
offset=vdd_pin.ll(),
|
offset=vdd_pin.ll(),
|
||||||
width=self.width,
|
width=self.width,
|
||||||
height=vdd_pin.height())
|
height=vdd_pin.height())
|
||||||
|
|
@ -160,7 +157,7 @@ class dff_buf(design.design):
|
||||||
# Continous gnd rail along with label.
|
# Continous gnd rail along with label.
|
||||||
gnd_pin=self.dff_inst.get_pin("gnd")
|
gnd_pin=self.dff_inst.get_pin("gnd")
|
||||||
self.add_layout_pin(text="gnd",
|
self.add_layout_pin(text="gnd",
|
||||||
layer="m1",
|
layer=gnd_pin.layer,
|
||||||
offset=gnd_pin.ll(),
|
offset=gnd_pin.ll(),
|
||||||
width=self.width,
|
width=self.width,
|
||||||
height=vdd_pin.height())
|
height=vdd_pin.height())
|
||||||
|
|
@ -185,17 +182,20 @@ class dff_buf(design.design):
|
||||||
self.add_layout_pin_rect_center(text="Q",
|
self.add_layout_pin_rect_center(text="Q",
|
||||||
layer="m2",
|
layer="m2",
|
||||||
offset=q_pos)
|
offset=q_pos)
|
||||||
self.add_path("m1", [dout_pin.center(), mid_pos, q_pos])
|
self.add_path(self.route_layer, [dout_pin.center(), mid_pos, q_pos])
|
||||||
self.add_via_center(layers=self.m1_stack,
|
self.add_via_stack_center(from_layer=dout_pin.layer,
|
||||||
offset=q_pos)
|
to_layer="m2",
|
||||||
|
offset=q_pos)
|
||||||
|
|
||||||
qb_pos = self.mid_qb_pos + vector(0, self.m2_pitch)
|
qb_pos = self.mid_qb_pos + vector(0, self.m2_pitch)
|
||||||
self.add_layout_pin_rect_center(text="Qb",
|
self.add_layout_pin_rect_center(text="Qb",
|
||||||
layer="m2",
|
layer="m2",
|
||||||
offset=qb_pos)
|
offset=qb_pos)
|
||||||
self.add_path("m1", [self.mid_qb_pos, qb_pos])
|
self.add_path(self.route_layer, [self.mid_qb_pos, qb_pos])
|
||||||
self.add_via_center(layers=self.m1_stack,
|
a2_pin = self.inv2_inst.get_pin("A")
|
||||||
offset=qb_pos)
|
self.add_via_stack_center(from_layer=a2_pin.layer,
|
||||||
|
to_layer="m2",
|
||||||
|
offset=qb_pos)
|
||||||
|
|
||||||
def get_clk_cin(self):
|
def get_clk_cin(self):
|
||||||
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff"""
|
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff"""
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,7 @@ class replica_column(design.design):
|
||||||
bl_pin = self.cell_inst[0].get_pin(bl_name)
|
bl_pin = self.cell_inst[0].get_pin(bl_name)
|
||||||
self.add_layout_pin(text=bl_name,
|
self.add_layout_pin(text=bl_name,
|
||||||
layer=bl_pin.layer,
|
layer=bl_pin.layer,
|
||||||
offset=bl_pin.ll(),
|
offset=bl_pin.ll().scale(1, 0),
|
||||||
width=bl_pin.width(),
|
width=bl_pin.width(),
|
||||||
height=self.height)
|
height=self.height)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,8 @@ class pgate(design.design):
|
||||||
# This is the space from a S/D contact to the supply rail
|
# This is the space from a S/D contact to the supply rail
|
||||||
contact_to_vdd_rail_space = 0.5 * self.m1_width + self.m1_space
|
contact_to_vdd_rail_space = 0.5 * self.m1_width + self.m1_space
|
||||||
# This is a poly-to-poly of a flipped cell
|
# This is a poly-to-poly of a flipped cell
|
||||||
poly_to_poly_gate_space = self.poly_extend_active + self.poly_space
|
poly_to_poly_gate_space = self.poly_extend_active + 0.5 * self.poly_space
|
||||||
|
|
||||||
self.top_bottom_space = max(contact_to_vdd_rail_space,
|
self.top_bottom_space = max(contact_to_vdd_rail_space,
|
||||||
poly_to_poly_gate_space)
|
poly_to_poly_gate_space)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import debug
|
||||||
import pgate
|
import pgate
|
||||||
from vector import vector
|
from vector import vector
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
|
from tech import layer
|
||||||
|
|
||||||
class pinvbuf(pgate.pgate):
|
class pinvbuf(pgate.pgate):
|
||||||
"""
|
"""
|
||||||
|
|
@ -111,33 +111,45 @@ class pinvbuf(pgate.pgate):
|
||||||
mirror="MX")
|
mirror="MX")
|
||||||
|
|
||||||
def route_wires(self):
|
def route_wires(self):
|
||||||
|
if "li" in layer:
|
||||||
|
route_stack = self.li_stack
|
||||||
|
else:
|
||||||
|
route_stack = self.m1_stack
|
||||||
|
|
||||||
# inv1 Z to inv2 A
|
# inv1 Z to inv2 A
|
||||||
z1_pin = self.inv1_inst.get_pin("Z")
|
z1_pin = self.inv1_inst.get_pin("Z")
|
||||||
a2_pin = self.inv2_inst.get_pin("A")
|
a2_pin = self.inv2_inst.get_pin("A")
|
||||||
mid_point = vector(z1_pin.cx(), a2_pin.cy())
|
mid_point = vector(z1_pin.cx(), a2_pin.cy())
|
||||||
self.add_path("m1", [z1_pin.center(), mid_point, a2_pin.center()])
|
self.add_path(z1_pin.layer, [z1_pin.center(), mid_point, a2_pin.center()])
|
||||||
|
self.add_via_stack_center(from_layer=z1_pin.layer,
|
||||||
|
to_layer=a2_pin.layer,
|
||||||
|
offset=a2_pin.center())
|
||||||
|
|
||||||
# inv2 Z to inv3 A
|
# inv2 Z to inv3 A
|
||||||
z2_pin = self.inv2_inst.get_pin("Z")
|
z2_pin = self.inv2_inst.get_pin("Z")
|
||||||
a3_pin = self.inv3_inst.get_pin("A")
|
a3_pin = self.inv3_inst.get_pin("A")
|
||||||
mid_point = vector(z2_pin.cx(), a3_pin.cy())
|
mid_point = vector(z2_pin.cx(), a3_pin.cy())
|
||||||
self.add_path("m1", [z2_pin.center(), mid_point, a3_pin.center()])
|
self.add_path(z2_pin.layer, [z2_pin.center(), mid_point, a3_pin.center()])
|
||||||
|
self.add_via_stack_center(from_layer=z2_pin.layer,
|
||||||
|
to_layer=a3_pin.layer,
|
||||||
|
offset=a3_pin.center())
|
||||||
|
|
||||||
# inv1 Z to inv4 A (up and over)
|
# inv1 Z to inv4 A (up and over)
|
||||||
z1_pin = self.inv1_inst.get_pin("Z")
|
z1_pin = self.inv1_inst.get_pin("Z")
|
||||||
a4_pin = self.inv4_inst.get_pin("A")
|
a4_pin = self.inv4_inst.get_pin("A")
|
||||||
mid_point = vector(z1_pin.cx(), a4_pin.cy())
|
mid_point = vector(z1_pin.cx(), a4_pin.cy())
|
||||||
self.add_wire(self.m1_stack,
|
self.add_wire(route_stack,
|
||||||
[z1_pin.center(), mid_point, a4_pin.center()])
|
[z1_pin.center(), mid_point, a4_pin.center()])
|
||||||
self.add_via_center(layers=self.m1_stack,
|
self.add_via_stack_center(from_layer=z1_pin.layer,
|
||||||
offset=z1_pin.center())
|
to_layer=route_stack[2],
|
||||||
|
offset=z1_pin.center())
|
||||||
|
|
||||||
def add_layout_pins(self):
|
def add_layout_pins(self):
|
||||||
|
|
||||||
# Continous vdd rail along with label.
|
# Continous vdd rail along with label.
|
||||||
vdd_pin = self.inv1_inst.get_pin("vdd")
|
vdd_pin = self.inv1_inst.get_pin("vdd")
|
||||||
self.add_layout_pin(text="vdd",
|
self.add_layout_pin(text="vdd",
|
||||||
layer="m1",
|
layer=vdd_pin.layer,
|
||||||
offset=vdd_pin.ll().scale(0, 1),
|
offset=vdd_pin.ll().scale(0, 1),
|
||||||
width=self.width,
|
width=self.width,
|
||||||
height=vdd_pin.height())
|
height=vdd_pin.height())
|
||||||
|
|
@ -145,7 +157,7 @@ class pinvbuf(pgate.pgate):
|
||||||
# Continous vdd rail along with label.
|
# Continous vdd rail along with label.
|
||||||
gnd_pin = self.inv4_inst.get_pin("gnd")
|
gnd_pin = self.inv4_inst.get_pin("gnd")
|
||||||
self.add_layout_pin(text="gnd",
|
self.add_layout_pin(text="gnd",
|
||||||
layer="m1",
|
layer=gnd_pin.layer,
|
||||||
offset=gnd_pin.ll().scale(0, 1),
|
offset=gnd_pin.ll().scale(0, 1),
|
||||||
width=self.width,
|
width=self.width,
|
||||||
height=gnd_pin.height())
|
height=gnd_pin.height())
|
||||||
|
|
@ -153,31 +165,25 @@ class pinvbuf(pgate.pgate):
|
||||||
# Continous gnd rail along with label.
|
# Continous gnd rail along with label.
|
||||||
gnd_pin = self.inv1_inst.get_pin("gnd")
|
gnd_pin = self.inv1_inst.get_pin("gnd")
|
||||||
self.add_layout_pin(text="gnd",
|
self.add_layout_pin(text="gnd",
|
||||||
layer="m1",
|
layer=gnd_pin.layer,
|
||||||
offset=gnd_pin.ll().scale(0, 1),
|
offset=gnd_pin.ll().scale(0, 1),
|
||||||
width=self.width,
|
width=self.width,
|
||||||
height=vdd_pin.height())
|
height=vdd_pin.height())
|
||||||
|
|
||||||
z_pin = self.inv4_inst.get_pin("Z")
|
z_pin = self.inv4_inst.get_pin("Z")
|
||||||
self.add_layout_pin_rect_center(text="Z",
|
self.add_layout_pin_rect_center(text="Z",
|
||||||
layer="m2",
|
layer=z_pin.layer,
|
||||||
offset=z_pin.center())
|
offset=z_pin.center())
|
||||||
self.add_via_center(layers=self.m1_stack,
|
|
||||||
offset=z_pin.center())
|
|
||||||
|
|
||||||
zb_pin = self.inv3_inst.get_pin("Z")
|
zb_pin = self.inv3_inst.get_pin("Z")
|
||||||
self.add_layout_pin_rect_center(text="Zb",
|
self.add_layout_pin_rect_center(text="Zb",
|
||||||
layer="m2",
|
layer=zb_pin.layer,
|
||||||
offset=zb_pin.center())
|
offset=zb_pin.center())
|
||||||
self.add_via_center(layers=self.m1_stack,
|
|
||||||
offset=zb_pin.center())
|
|
||||||
|
|
||||||
a_pin = self.inv1_inst.get_pin("A")
|
a_pin = self.inv1_inst.get_pin("A")
|
||||||
self.add_layout_pin_rect_center(text="A",
|
self.add_layout_pin_rect_center(text="A",
|
||||||
layer="m2",
|
layer=a_pin.layer,
|
||||||
offset=a_pin.center())
|
offset=a_pin.center())
|
||||||
self.add_via_center(layers=self.m1_stack,
|
|
||||||
offset=a_pin.center())
|
|
||||||
|
|
||||||
def determine_clk_buf_stage_efforts(self, external_cout, inp_is_rise=False):
|
def determine_clk_buf_stage_efforts(self, external_cout, inp_is_rise=False):
|
||||||
"""Get the stage efforts of the clk -> clk_buf path"""
|
"""Get the stage efforts of the clk -> clk_buf path"""
|
||||||
|
|
|
||||||
|
|
@ -177,9 +177,9 @@ class pnand2(pgate.pgate):
|
||||||
|
|
||||||
|
|
||||||
# Top of NMOS drain
|
# Top of NMOS drain
|
||||||
nmos_pin = self.nmos2_inst.get_pin("D")
|
bottom_pin = self.nmos2_inst.get_pin("D")
|
||||||
bottom_pin_offset = nmos_pin.uy()
|
self.inputA_yoffset = max(bottom_pin.uy() + self.m1_pitch,
|
||||||
self.inputA_yoffset = bottom_pin_offset + self.m1_pitch
|
self.nmos2_inst.uy() + self.poly_to_active)
|
||||||
|
|
||||||
self.inputB_yoffset = self.inputA_yoffset + self.m3_pitch
|
self.inputB_yoffset = self.inputA_yoffset + self.m3_pitch
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ from vector import vector
|
||||||
import logical_effort
|
import logical_effort
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
|
import contact
|
||||||
|
|
||||||
class pnand3(pgate.pgate):
|
class pnand3(pgate.pgate):
|
||||||
"""
|
"""
|
||||||
|
|
@ -209,13 +209,21 @@ class pnand3(pgate.pgate):
|
||||||
def route_inputs(self):
|
def route_inputs(self):
|
||||||
""" Route the A and B and C inputs """
|
""" Route the A and B and C inputs """
|
||||||
|
|
||||||
|
# We can use this pitch because the contacts and overlap won't be adjacent
|
||||||
|
non_contact_pitch = 0.5 * self.m1_width + self.m1_space + 0.5 * contact.poly_contact.second_layer_height
|
||||||
pmos_drain_bottom = self.pmos1_inst.get_pin("D").by()
|
pmos_drain_bottom = self.pmos1_inst.get_pin("D").by()
|
||||||
self.output_yoffset = pmos_drain_bottom - 0.5 * self.route_layer_width - self.route_layer_space
|
self.output_yoffset = pmos_drain_bottom - 0.5 * self.route_layer_width - self.route_layer_space
|
||||||
|
|
||||||
# This is a more compact offset, but the bottom one works better in the decoders to "center" the pins
|
bottom_pin = self.nmos1_inst.get_pin("D")
|
||||||
# in the height of the gates
|
# active contact metal to poly contact metal spacing
|
||||||
self.inputA_yoffset = self.output_yoffset - 0.5 * self.route_layer_width - self.route_layer_space
|
active_contact_to_poly_contact = bottom_pin.uy() + self.m1_space + 0.5 * contact.poly_contact.second_layer_height
|
||||||
# self.inputA_yoffset = self.output_yoffset - self.m1_pitch
|
# active diffusion to poly contact spacing
|
||||||
|
# doesn't use nmos uy because that is calculated using offset + poly height
|
||||||
|
active_to_poly_contact = self.nmos1_inst.by() + self.nmos1_inst.mod.active_height \
|
||||||
|
+ self.poly_to_active + 0.5 * contact.poly_contact.first_layer_height
|
||||||
|
|
||||||
|
self.inputA_yoffset = max(active_contact_to_poly_contact,
|
||||||
|
active_to_poly_contact)
|
||||||
self.route_input_gate(self.pmos1_inst,
|
self.route_input_gate(self.pmos1_inst,
|
||||||
self.nmos1_inst,
|
self.nmos1_inst,
|
||||||
self.inputA_yoffset,
|
self.inputA_yoffset,
|
||||||
|
|
@ -223,14 +231,14 @@ class pnand3(pgate.pgate):
|
||||||
position="left")
|
position="left")
|
||||||
|
|
||||||
# Put B right on the well line
|
# Put B right on the well line
|
||||||
self.inputB_yoffset = self.inputA_yoffset - self.m1_pitch
|
self.inputB_yoffset = self.inputA_yoffset + non_contact_pitch
|
||||||
self.route_input_gate(self.pmos2_inst,
|
self.route_input_gate(self.pmos2_inst,
|
||||||
self.nmos2_inst,
|
self.nmos2_inst,
|
||||||
self.inputB_yoffset,
|
self.inputB_yoffset,
|
||||||
"B",
|
"B",
|
||||||
position="center")
|
position="center")
|
||||||
|
|
||||||
self.inputC_yoffset = self.inputB_yoffset - self.m1_pitch
|
self.inputC_yoffset = self.inputB_yoffset + non_contact_pitch
|
||||||
self.route_input_gate(self.pmos3_inst,
|
self.route_input_gate(self.pmos3_inst,
|
||||||
self.nmos3_inst,
|
self.nmos3_inst,
|
||||||
self.inputC_yoffset,
|
self.inputC_yoffset,
|
||||||
|
|
|
||||||
|
|
@ -149,13 +149,9 @@ class precharge(design.design):
|
||||||
# Compute the other pmos2 location,
|
# Compute the other pmos2 location,
|
||||||
# but determining offset to overlap the source and drain pins
|
# but determining offset to overlap the source and drain pins
|
||||||
overlap_offset = self.pmos.get_pin("D").ll() - self.pmos.get_pin("S").ll()
|
overlap_offset = self.pmos.get_pin("D").ll() - self.pmos.get_pin("S").ll()
|
||||||
# This is how much the contact is placed inside the ptx active
|
|
||||||
contact_xdiff = self.pmos.get_pin("S").lx()
|
|
||||||
|
|
||||||
# adds the lower pmos to layout
|
# adds the lower pmos to layout
|
||||||
bl_xoffset = self.bitcell_bl_pin.lx()
|
self.lower_pmos_position = vector(self.well_enclose_active + 0.5 * self.m1_width,
|
||||||
self.lower_pmos_position = vector(max(bl_xoffset - contact_xdiff,
|
|
||||||
self.nwell_enclose_active),
|
|
||||||
self.initial_yoffset)
|
self.initial_yoffset)
|
||||||
self.lower_pmos_inst.place(self.lower_pmos_position)
|
self.lower_pmos_inst.place(self.lower_pmos_position)
|
||||||
|
|
||||||
|
|
@ -218,7 +214,7 @@ class precharge(design.design):
|
||||||
|
|
||||||
# adds the contact from active to metal1
|
# adds the contact from active to metal1
|
||||||
offset_height = self.upper_pmos1_inst.uy() + \
|
offset_height = self.upper_pmos1_inst.uy() + \
|
||||||
0.5 * contact.active_contact.height + \
|
contact.active_contact.height + \
|
||||||
self.nwell_extend_active
|
self.nwell_extend_active
|
||||||
self.well_contact_pos = self.upper_pmos1_inst.get_pin("D").center().scale(1, 0) + \
|
self.well_contact_pos = self.upper_pmos1_inst.get_pin("D").center().scale(1, 0) + \
|
||||||
vector(0, offset_height)
|
vector(0, offset_height)
|
||||||
|
|
|
||||||
|
|
@ -205,28 +205,15 @@ class ptx(design.design):
|
||||||
# Poly height must include poly extension over active
|
# Poly height must include poly extension over active
|
||||||
self.poly_height = self.tx_width + 2 * self.poly_extend_active
|
self.poly_height = self.tx_width + 2 * self.poly_extend_active
|
||||||
|
|
||||||
# The active offset is due to the well extension
|
self.active_offset = vector([self.well_enclose_active] * 2)
|
||||||
if "pwell" in layer:
|
|
||||||
pwell_enclose_active = drc("pwell_enclose_active")
|
|
||||||
else:
|
|
||||||
pwell_enclose_active = 0
|
|
||||||
if "nwell" in layer:
|
|
||||||
nwell_enclose_active = drc("nwell_enclose_active")
|
|
||||||
else:
|
|
||||||
nwell_enclose_active = 0
|
|
||||||
# Use the max of either so that the poly gates will align properly
|
|
||||||
well_enclose_active = max(pwell_enclose_active,
|
|
||||||
nwell_enclose_active)
|
|
||||||
self.active_offset = vector([well_enclose_active] * 2)
|
|
||||||
|
|
||||||
# Well enclosure of active, ensure minwidth as well
|
# Well enclosure of active, ensure minwidth as well
|
||||||
well_name = "{}well".format(self.well_type)
|
well_name = "{}well".format(self.well_type)
|
||||||
if well_name in layer:
|
if well_name in layer:
|
||||||
well_width_rule = drc("minwidth_" + well_name)
|
well_width_rule = drc("minwidth_" + well_name)
|
||||||
well_enclose_active = drc(well_name + "_enclose_active")
|
self.well_width = max(self.active_width + 2 * self.well_enclose_active,
|
||||||
self.well_width = max(self.active_width + 2 * well_enclose_active,
|
|
||||||
well_width_rule)
|
well_width_rule)
|
||||||
self.well_height = max(self.active_height + 2 * well_enclose_active,
|
self.well_height = max(self.active_height + 2 * self.well_enclose_active,
|
||||||
well_width_rule)
|
well_width_rule)
|
||||||
# We are going to shift the 0,0, so include that in the width and height
|
# We are going to shift the 0,0, so include that in the width and height
|
||||||
self.height = self.well_height - self.active_offset.y
|
self.height = self.well_height - self.active_offset.y
|
||||||
|
|
|
||||||
|
|
@ -29,10 +29,6 @@ class pand2_test(openram_test):
|
||||||
a = pand2.pand2(name="pand2x4", size=4)
|
a = pand2.pand2(name="pand2x4", size=4)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
debug.info(2, "Testing vertical pand2 gate 4x")
|
|
||||||
a = pand2.pand2(name="pand2x4", size=4, vertical=True)
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
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
|
||||||
|
|
|
||||||
|
|
@ -29,10 +29,6 @@ class pand3_test(openram_test):
|
||||||
a = pand3.pand3(name="pand3x4", size=4)
|
a = pand3.pand3(name="pand3x4", size=4)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
debug.info(2, "Testing vertical pand3 gate 4x")
|
|
||||||
a = pand3.pand3(name="pand3x4", size=4, vertical=True)
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
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
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# See LICENSE for licensing information.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016-2019 Regents of the University of California and The Board
|
||||||
|
# of Regents for the Oklahoma Agricultural and Mechanical College
|
||||||
|
# (acting for and on behalf of Oklahoma State University)
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
import unittest
|
||||||
|
from testutils import *
|
||||||
|
import sys,os
|
||||||
|
sys.path.append(os.getenv("OPENRAM_HOME"))
|
||||||
|
import globals
|
||||||
|
from globals import OPTS
|
||||||
|
from sram_factory import factory
|
||||||
|
import debug
|
||||||
|
|
||||||
|
|
||||||
|
class precharge_test(openram_test):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
|
# check precharge array in multi-port
|
||||||
|
OPTS.num_rw_ports = 1
|
||||||
|
OPTS.num_r_ports = 1
|
||||||
|
OPTS.num_w_ports = 0
|
||||||
|
globals.setup_bitcell()
|
||||||
|
|
||||||
|
debug.info(2, "Checking precharge for 1rw1r port 0")
|
||||||
|
tx = factory.create(module_type="precharge", size=1, bitcell_bl="bl0", bitcell_br="br0")
|
||||||
|
self.local_check(tx)
|
||||||
|
|
||||||
|
factory.reset()
|
||||||
|
debug.info(2, "Checking precharge for 1rw1r port 1")
|
||||||
|
tx = factory.create(module_type="precharge", size=1, bitcell_bl="bl1", bitcell_br="br1")
|
||||||
|
self.local_check(tx)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
|
# run the test from the command line
|
||||||
|
if __name__ == "__main__":
|
||||||
|
(OPTS, args) = globals.parse_args()
|
||||||
|
del sys.argv[1:]
|
||||||
|
header(__file__, OPTS.tech_name)
|
||||||
|
unittest.main(testRunner=debugTestRunner())
|
||||||
|
|
@ -17,7 +17,7 @@ import debug
|
||||||
|
|
||||||
#@unittest.skip("SKIPPING 05_bitcell_1rw_1r_array_test")
|
#@unittest.skip("SKIPPING 05_bitcell_1rw_1r_array_test")
|
||||||
|
|
||||||
class bitcell_1rw_1r_array_test(openram_test):
|
class bitcell_array_1rw_1r_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# See LICENSE for licensing information.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016-2019 Regents of the University of California and The Board
|
||||||
|
# of Regents for the Oklahoma Agricultural and Mechanical College
|
||||||
|
# (acting for and on behalf of Oklahoma State University)
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
import unittest
|
||||||
|
from testutils import *
|
||||||
|
import sys,os
|
||||||
|
sys.path.append(os.getenv("OPENRAM_HOME"))
|
||||||
|
import globals
|
||||||
|
from globals import OPTS
|
||||||
|
from sram_factory import factory
|
||||||
|
import debug
|
||||||
|
|
||||||
|
class sense_amp_test(openram_test):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
|
OPTS.num_rw_ports = 1
|
||||||
|
OPTS.num_r_ports = 1
|
||||||
|
OPTS.num_w_ports = 0
|
||||||
|
globals.setup_bitcell()
|
||||||
|
|
||||||
|
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=1")
|
||||||
|
a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=1)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2")
|
||||||
|
a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=2)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=4")
|
||||||
|
a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=4)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
|
# run the test from the command line
|
||||||
|
if __name__ == "__main__":
|
||||||
|
(OPTS, args) = globals.parse_args()
|
||||||
|
del sys.argv[1:]
|
||||||
|
header(__file__, OPTS.tech_name)
|
||||||
|
unittest.main(testRunner=debugTestRunner())
|
||||||
|
|
@ -13,7 +13,7 @@ from globals import OPTS
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
import debug
|
import debug
|
||||||
|
|
||||||
class replica_bitcell_array_test(openram_test):
|
class replica_bitcell_array_1rw_1r_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# See LICENSE for licensing information.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016-2019 Regents of the University of California
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
import unittest
|
||||||
|
from testutils import *
|
||||||
|
import sys,os
|
||||||
|
sys.path.append(os.getenv("OPENRAM_HOME"))
|
||||||
|
import globals
|
||||||
|
from globals import OPTS
|
||||||
|
from sram_factory import factory
|
||||||
|
import debug
|
||||||
|
|
||||||
|
class replica_column_test(openram_test):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
|
OPTS.num_rw_ports = 1
|
||||||
|
OPTS.num_r_ports = 1
|
||||||
|
OPTS.num_w_ports = 0
|
||||||
|
globals.setup_bitcell()
|
||||||
|
|
||||||
|
debug.info(2, "Testing replica column for 6t_cell")
|
||||||
|
a = factory.create(module_type="replica_column", rows=4, left_rbl=1, right_rbl=0, replica_bit=1)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
debug.info(2, "Testing replica column for 6t_cell")
|
||||||
|
a = factory.create(module_type="replica_column", rows=4, left_rbl=1, right_rbl=1, replica_bit=6)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
debug.info(2, "Testing replica column for 6t_cell")
|
||||||
|
a = factory.create(module_type="replica_column", rows=4, left_rbl=2, right_rbl=0, replica_bit=2)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
|
# run the test from the command line
|
||||||
|
if __name__ == "__main__":
|
||||||
|
(OPTS, args) = globals.parse_args()
|
||||||
|
del sys.argv[1:]
|
||||||
|
header(__file__, OPTS.tech_name)
|
||||||
|
unittest.main(testRunner=debugTestRunner())
|
||||||
|
|
@ -15,7 +15,6 @@ from globals import OPTS
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
import debug
|
import debug
|
||||||
|
|
||||||
@unittest.skip("SKIPPING 20_psram_1bank_4mux_1rw_1r_test - Matt sucks, don't do this")
|
|
||||||
class psram_1bank_4mux_1rw_1r_test(openram_test):
|
class psram_1bank_4mux_1rw_1r_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
|
|
|
||||||
|
|
@ -22,14 +22,26 @@ header(__file__, OPTS.tech_name)
|
||||||
# get a list of all files in the tests directory
|
# get a list of all files in the tests directory
|
||||||
files = os.listdir(sys.path[0])
|
files = os.listdir(sys.path[0])
|
||||||
|
|
||||||
|
# load a file with all tests to skip in a given technology
|
||||||
|
# since tech_name is dynamically loaded, we can't use @skip directives
|
||||||
|
try:
|
||||||
|
skip_file_name = "{0}/tests/skip_tests_{1}.txt".format(os.getenv("OPENRAM_HOME"), OPTS.tech_name)
|
||||||
|
skip_file = open(skip_file_name, "r")
|
||||||
|
skip_tests = skip_file.read().splitlines()
|
||||||
|
for st in skip_tests:
|
||||||
|
debug.warning("Skipping: " + st)
|
||||||
|
except FileNotFoundError:
|
||||||
|
skip_tests = []
|
||||||
|
|
||||||
# assume any file that ends in "test.py" in it is a regression test
|
# assume any file that ends in "test.py" in it is a regression test
|
||||||
nametest = re.compile("test\.py$", re.IGNORECASE)
|
nametest = re.compile("test\.py$", re.IGNORECASE)
|
||||||
tests = list(filter(nametest.search, files))
|
all_tests = list(filter(nametest.search, files))
|
||||||
tests.sort()
|
filtered_tests = list(filter(lambda i: i not in skip_tests, all_tests))
|
||||||
|
filtered_tests.sort()
|
||||||
|
|
||||||
# import all of the modules
|
# import all of the modules
|
||||||
filenameToModuleName = lambda f: os.path.splitext(f)[0]
|
filenameToModuleName = lambda f: os.path.splitext(f)[0]
|
||||||
moduleNames = map(filenameToModuleName, tests)
|
moduleNames = map(filenameToModuleName, filtered_tests)
|
||||||
modules = map(__import__, moduleNames)
|
modules = map(__import__, moduleNames)
|
||||||
suite = unittest.TestSuite()
|
suite = unittest.TestSuite()
|
||||||
load = unittest.defaultTestLoader.loadTestsFromModule
|
load = unittest.defaultTestLoader.loadTestsFromModule
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
04_dummy_pbitcell_test.py
|
||||||
|
04_pbitcell_test.py
|
||||||
|
04_precharge_pbitcell_test.py
|
||||||
|
04_replica_pbitcell_test.py
|
||||||
|
04_single_level_column_mux_pbitcell_test.py
|
||||||
|
05_bitcell_1rw_1r_array_test.py
|
||||||
|
05_bitcell_array_test.py
|
||||||
|
05_dummy_array_test.py
|
||||||
|
05_pbitcell_array_test.py
|
||||||
|
06_hierarchical_decoder_pbitcell_test.py
|
||||||
|
06_hierarchical_decoder_test.py
|
||||||
|
06_hierarchical_predecode2x4_pbitcell_test.py
|
||||||
|
06_hierarchical_predecode2x4_test.py
|
||||||
|
06_hierarchical_predecode3x8_pbitcell_test.py
|
||||||
|
06_hierarchical_predecode3x8_test.py
|
||||||
|
06_hierarchical_predecode4x16_test.py
|
||||||
|
07_single_level_column_mux_array_pbitcell_test.py
|
||||||
|
08_wordline_driver_array_pbitcell_test.py
|
||||||
|
08_wordline_driver_array_test.py
|
||||||
|
09_sense_amp_array_test_pbitcell.py
|
||||||
|
09_sense_amp_array_test.py
|
||||||
|
10_write_driver_array_pbitcell_test.py
|
||||||
|
10_write_driver_array_test.py
|
||||||
|
10_write_driver_array_wmask_pbitcell_test.py
|
||||||
|
10_write_driver_array_wmask_test.py
|
||||||
|
10_write_mask_and_array_pbitcell_test.py
|
||||||
|
10_write_mask_and_array_test.py
|
||||||
|
12_tri_gate_array_test.py
|
||||||
|
14_replica_pbitcell_array_test.py
|
||||||
|
14_replica_bitcell_array_test.py
|
||||||
|
14_replica_column_test.py
|
||||||
|
14_replica_column_1rw_1r_test.py
|
||||||
|
18_port_address_test.py
|
||||||
|
18_port_data_test.py
|
||||||
|
18_port_data_wmask_test.py
|
||||||
|
19_bank_select_pbitcell_test.py
|
||||||
|
19_bank_select_test.py
|
||||||
|
19_psingle_bank_test.py
|
||||||
|
19_bank_select_pbitcell_test.py
|
||||||
|
19_pmulti_bank_test.py
|
||||||
|
19_multi_bank_test.py
|
||||||
|
19_psingle_bank_test.py
|
||||||
|
19_single_bank_1w_1r_test.py
|
||||||
|
19_single_bank_wmask_1rw_1r_test.py
|
||||||
|
19_single_bank_1rw_1r_test.py
|
||||||
|
19_single_bank_test.py
|
||||||
|
19_single_bank_wmask_test.py
|
||||||
|
20_psram_1bank_2mux_1rw_1w_test.py
|
||||||
|
20_psram_1bank_2mux_1rw_1w_wmask_test.py
|
||||||
|
20_psram_1bank_2mux_1w_1r_test.py
|
||||||
|
20_psram_1bank_2mux_test.py
|
||||||
|
20_psram_1bank_4mux_1rw_1r_test.py
|
||||||
|
20_sram_1bank_2mux_1w_1r_test.py
|
||||||
|
20_sram_1bank_2mux_test.py
|
||||||
|
20_sram_1bank_2mux_wmask_test.py
|
||||||
|
20_sram_1bank_32b_1024_wmask_test.py
|
||||||
|
20_sram_1bank_4mux_test.py
|
||||||
|
20_sram_1bank_8mux_test.py
|
||||||
|
20_sram_1bank_nomux_test.py
|
||||||
|
20_sram_1bank_nomux_wmask_test.py
|
||||||
|
20_sram_2bank_test.py
|
||||||
|
21_hspice_delay_test.py
|
||||||
|
21_hspice_setuphold_test.py
|
||||||
|
21_model_delay_test.py
|
||||||
|
21_ngspice_delay_test.py
|
||||||
|
21_ngspice_setuphold_test.py
|
||||||
|
22_psram_1bank_2mux_func_test.py
|
||||||
|
22_psram_1bank_4mux_func_test.py
|
||||||
|
22_psram_1bank_8mux_func_test.py
|
||||||
|
22_psram_1bank_nomux_func_test.py
|
||||||
|
22_sram_1bank_2mux_func_test.py
|
||||||
|
22_sram_1bank_4mux_func_test.py
|
||||||
|
22_sram_1bank_8mux_func_test.py
|
||||||
|
22_sram_1bank_nomux_func_test.py
|
||||||
|
22_sram_1rw_1r_1bank_nomux_func_test.py
|
||||||
|
22_sram_wmask_func_test.py
|
||||||
|
23_lib_sram_model_corners_test.py
|
||||||
|
23_lib_sram_model_test.py
|
||||||
|
23_lib_sram_prune_test.py
|
||||||
|
23_lib_sram_test.py
|
||||||
|
24_lef_sram_test.py
|
||||||
|
25_verilog_sram_test.py
|
||||||
|
26_hspice_pex_pinv_test.py
|
||||||
|
26_ngspice_pex_pinv_test.py
|
||||||
|
26_pex_test.py
|
||||||
|
30_openram_back_end_test.py
|
||||||
|
30_openram_front_end_test.py
|
||||||
Binary file not shown.
Loading…
Reference in New Issue