Skip to content

Fixes to support TSMC18 technology port #116

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 38 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
c415b2a
Several changes to match the requirements of tsmc18. 90% done
ckdur Apr 9, 2021
c5ffad3
Final touches to all pgates
ckdur Apr 10, 2021
cb0f271
LVS confirmation
ckdur Apr 13, 2021
9e0711b
Changed some rules to pass scmos tests
ckdur Apr 13, 2021
5087201
Modifications for passing LVS. Added some configurations for lvs_spic…
ckdur Apr 13, 2021
a33d050
Sync with VLSIDA remote
ckdur Apr 21, 2021
852dea1
Fixes to pin_layout.py for supporting +p in layer names
ckdur Apr 22, 2021
8414912
Adding to the delay test the tsmc18
ckdur Apr 22, 2021
5a0cd20
Merge branch 'dev' of https://github.com/VLSIDA/OpenRAM into dev
ckdur May 1, 2021
96bf7d2
Added support for the grid power routing. LEF generation now supports…
ckdur May 1, 2021
cb0cccc
Added a lambda rect intersection in pin_group. This helps for segment…
ckdur May 10, 2021
5bb1c81
Miscellaneous fixes on the overlap. Removing the (V, V) creation of v…
ckdur May 10, 2021
bfdf65b
Delete some of the generated files for debug
ckdur May 11, 2021
471d763
Supply pins only on corners when grid routing
ckdur May 14, 2021
fe374f9
Supply rails now only get exposed in the edges
ckdur May 14, 2021
f879b25
Supply grid faster. Supply grid and escape routing both are in the pe…
ckdur May 15, 2021
70143a8
Fixed errors with the blockage removal in the router (reflected only …
ckdur May 15, 2021
d9c8a2f
Avoid large border intersections in VDD or GND
ckdur May 17, 2021
3097599
Quitting the 1-step margin of the LEF obs
ckdur May 18, 2021
a4cece4
Remove the LEF m5 cover
ckdur May 18, 2021
99a0152
Update from VLSIDA
ckdur Jun 17, 2021
1a1900f
Merge with VLSIDA/dev on 21/11/02
ckdur Nov 2, 2021
c5f28a5
Fixes for working with the latest version
ckdur Nov 2, 2021
e4d3940
LAPIS20 addition whenever the tsmc18 is used
ckdur Nov 4, 2021
fae2b8d
Avoid the 'multiple' additional ring boundary when generating the gri…
ckdur Nov 11, 2021
06e08f7
Fixed the connected
ckdur Nov 11, 2021
3be3748
Prints removed
ckdur Nov 11, 2021
1b21d49
Added rohm180
ckdur Dec 28, 2021
ea588ab
all pinv/nand/nor have extensions for rohm180
ckdur Jan 13, 2022
c75c361
all pinv/nand/nor have extensions for rohm180
ckdur Jan 13, 2022
1c99624
Test for rounding the wirepath with the unit instead of the grid
ckdur Jan 14, 2022
6a723fa
snap_to_grid already do this
ckdur Jan 14, 2022
0faa8e6
Round to grid to the nwell offset for the implant
ckdur Jan 14, 2022
79b5c02
Adding snap_to_grid for position in mos for the logic pgates only
ckdur Jan 14, 2022
9592003
Previous area fix in the input pins with a ratio of 1.2
ckdur Jan 14, 2022
adae3c5
pnand3 fixed DRC for ROHM180
ckdur Jan 21, 2022
5ad1db9
Update issue templates
mguthaus Nov 22, 2022
960b6cd
Merge branch 'stable' of https://github.com/VLSIDA/OpenRAM into dev
ckdur Nov 30, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''

---

**Describe the bug**
A clear and concise description of what the bug is.

**Version**
Which commit are you using?

**To Reproduce**
What did you do to demonstrate the bug?
Please include your configuration file used.

**Expected behavior**
A clear and concise description of what you expected to happen.

**Logs**
If applicable, add logs or output to help explain your problem.

**Additional context**
Add any other context about the problem here.
4 changes: 2 additions & 2 deletions compiler/base/geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -501,8 +501,8 @@ def __init__(self, lpp, offset, width, height):
self.name = "rect"
self.offset = vector(offset).snap_to_grid()
self.size = vector(width, height).snap_to_grid()
self.width = round_to_grid(self.size.x)
self.height = round_to_grid(self.size.y)
self.width = self.size.x # round_to_grid(self.size.x) # NOTE: snap_to_grid already do this!
self.height = self.size.y # round_to_grid(self.size.y)
self.compute_boundary(offset, "", 0)

debug.info(4, "creating rectangle (" + str(self.layerNumber) + "): "
Expand Down
20 changes: 20 additions & 0 deletions compiler/base/hierarchy_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -1915,6 +1915,16 @@ def add_power_pin(self, name, loc, directions=None, start_layer="m1"):
min_area = drc["minarea_{}".format(self.pwr_grid_layers[1])]
width = round_to_grid(sqrt(min_area))
height = round_to_grid(min_area / width)
elif OPTS.tech_name in ["tsmc18", "lapis20", "rohm180"]:
min_area = drc["minarea_{}".format(self.pwr_grid_layer)]
min_width = drc["minwidth_{}".format(self.pwr_grid_layer)]
dir = preferred_directions[self.pwr_grid_layer]
if dir == "V":
width = round_to_grid(min_width)
height = round_to_grid(min_area / width)
else:
height = round_to_grid(min_width)
width = round_to_grid(min_area / height)
else:
width = None
height = None
Expand Down Expand Up @@ -1961,6 +1971,16 @@ def copy_power_pin(self, pin, loc=None, directions=None, new_name=""):
min_area = drc["minarea_{}".format(self.pwr_grid_layers[1])]
width = round_to_grid(sqrt(min_area))
height = round_to_grid(min_area / width)
elif OPTS.tech_name in ["tsmc18", "lapis20", "rohm180"]:
min_area = drc["minarea_{}".format(self.pwr_grid_layer)]
min_width = drc["minwidth_{}".format(self.pwr_grid_layer)]
dir = preferred_directions[self.pwr_grid_layer]
if dir == "V":
width = round_to_grid(min_width)
height = round_to_grid(min_area / width)
else:
height = round_to_grid(min_width)
width = round_to_grid(min_area / height)
else:
width = None
height = None
Expand Down
3 changes: 2 additions & 1 deletion compiler/base/lef.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ def compute_abstract_blockages(self):
# Start with blockages on all layers the size of the block
# minus the pin escape margin (hard coded to 4 x m3 pitch)
# These are a pin_layout to use their geometric functions
perimeter_margin = self.m3_pitch
# TODO: The escape is already set to 0. Is not anymore 4xm3. Perimeter is now 0
perimeter_margin = 0 # self.m3_pitch
self.blockages = {}
for layer_name in self.lef_layers:
self.blockages[layer_name]=[]
Expand Down
91 changes: 48 additions & 43 deletions compiler/base/pin_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ def __init__(self, name, rect, layer_name_pp):

# These are the valid pin layers
valid_layers = {x: layer[x] for x in layer_indices.keys()}
# search for the "+p" pins also
valid_pin_layers = {}
for x in layer_indices.keys():
y = x + "p"
if y in layer:
valid_pin_layers[x] = layer[y]

# if it's a string, use the name
if type(layer_name_pp) == str:
Expand All @@ -47,17 +53,24 @@ def __init__(self, name, rect, layer_name_pp):
break

else:
try:
from tech import layer_override
from tech import layer_override_name
if layer_override[name]:
self.lpp = layer_override[name]
self.layer = "pwellp"
self._recompute_hash()
return
except:
debug.error("Layer {} is not a valid routing layer in the tech file.".format(layer_name_pp), -1)

for (layer_name, lpp) in valid_pin_layers.items():
if not lpp:
continue
if self.same_lpp(layer_name_pp, lpp):
self._layer = layer_name
break
else:
try:
from tech import layer_override
from tech import layer_override_name
if layer_override[name]:
self.lpp = layer_override[name]
self.layer = "pwellp"
self._recompute_hash()
return
except:
debug.error("Layer {} is not a valid routing layer in the tech file.".format(layer_name_pp), -1)

self.lpp = layer[self.layer]
self._recompute_hash()

Expand Down Expand Up @@ -193,32 +206,15 @@ def intersection(self, other):

def xoverlaps(self, other):
""" Check if shape has x overlap """
(ll, ur) = self.rect
(oll, our) = other.rect
x_overlaps = False
# check if self is within other x range
if (ll.x >= oll.x and ll.x <= our.x) or (ur.x >= oll.x and ur.x <= our.x):
x_overlaps = True
# check if other is within self x range
if (oll.x >= ll.x and oll.x <= ur.x) or (our.x >= ll.x and our.x <= ur.x):
x_overlaps = True

return x_overlaps
a = self.rect
b = other.rect
return a[0].x < b[1].x and a[1].x > b[0].x

def yoverlaps(self, other):
""" Check if shape has x overlap """
(ll, ur) = self.rect
(oll, our) = other.rect
y_overlaps = False

# check if self is within other y range
if (ll.y >= oll.y and ll.y <= our.y) or (ur.y >= oll.y and ur.y <= our.y):
y_overlaps = True
# check if other is within self y range
if (oll.y >= ll.y and oll.y <= ur.y) or (our.y >= ll.y and our.y <= ur.y):
y_overlaps = True

return y_overlaps
a = self.rect
b = other.rect
return a[0].y < b[1].y and a[1].y > b[0].y

def xcontains(self, other):
""" Check if shape contains the x overlap """
Expand Down Expand Up @@ -423,6 +419,7 @@ def gds_write_file(self, newLayout):
except ImportError:
label_purpose = purpose


newLayout.addBox(layerNumber=layer_num,
purposeNumber=purpose,
offsetInMicrons=self.ll(),
Expand All @@ -444,11 +441,19 @@ def gds_write_file(self, newLayout):
zoom = GDS["zoom"]
except KeyError:
zoom = None
newLayout.addText(text=self.name,
layerNumber=layer_num,
purposeNumber=label_purpose,
magnification=zoom,
offsetInMicrons=self.center())
# Draw a second pin text too if it is different
if pin_layer_num != layer_num:
newLayout.addText(text=self.name,
layerNumber=pin_layer_num,
purposeNumber=pin_purpose,
magnification=zoom,
offsetInMicrons=self.center())
else:
newLayout.addText(text=self.name,
layerNumber=layer_num,
purposeNumber=label_purpose,
magnification=zoom,
offsetInMicrons=self.center())

def compute_overlap(self, other):
""" Calculate the rectangular overlap of two rectangles. """
Expand Down Expand Up @@ -525,7 +530,7 @@ def overlap_length(self, other):
new_shape = pin_layout("", [ll, ur], self.lpp)
return max(new_shape.height(), new_shape.width())
else:
# This is where we had a corner intersection or none
# This is where we had a corner intersection or none (1 or 0)
return 0


Expand Down Expand Up @@ -580,9 +585,9 @@ def on_segment(self, p, q, r):
Given three co-linear points, determine if q lies on segment pr
"""
if q.x <= max(p.x, r.x) and \
q.x >= min(p.x, r.x) and \
q.y <= max(p.y, r.y) and \
q.y >= min(p.y, r.y):
q.x >= min(p.x, r.x) and \
q.y <= max(p.y, r.y) and \
q.y >= min(p.y, r.y):
return True

return False
Expand Down
19 changes: 19 additions & 0 deletions compiler/base/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,25 @@ def snap_to_grid(offset):
return [round_to_grid(offset[0]),
round_to_grid(offset[1])]

# NOTE: To snap to the unit instead of the grid. Grid is for geometries, unit is for routes or wires.
def round_to_unit(number):
"""
Rounds an arbitrary number to the unit.
"""
grid = tech.GDS["unit"][0]
# this gets the nearest integer value
number_grid = int(round(round((number / grid), 2), 0))
number_off = number_grid * grid
return number_off


def snap_to_unit(offset):
"""
Changes the coodrinate to match the unit settings
"""
return [round_to_unit(offset[0]),
round_to_unit(offset[1])]


def pin_center(boundary):
"""
Expand Down
12 changes: 10 additions & 2 deletions compiler/modules/bank.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,10 +239,14 @@ def compute_instance_port0_offsets(self):
# control logic to allow control signals to easily pass over in M3
# by placing 1 1/4 a cell pitch down because both power connections and inputs/outputs
# may be routed in M3 or M4
# TODO: In tsmc180, is not 1.25 (dff is 6.72. crosses with the first gnd)
mult = 1.25
if OPTS.tech_name in ["tsmc18", "lapis20", "rohm180"]:
mult = 1.35
x_offset = self.central_bus_width[port] + self.port_address[port].wordline_driver_array.width
if self.col_addr_size > 0:
x_offset += self.column_decoder.width + self.col_addr_bus_width
y_offset = 1.25 * self.dff.height + self.column_decoder.height
y_offset = mult * self.dff.height + self.column_decoder.height
else:
y_offset = 0
self.column_decoder_offsets[port] = vector(-x_offset, -y_offset)
Expand Down Expand Up @@ -283,10 +287,14 @@ def compute_instance_port1_offsets(self):
# control logic to allow control signals to easily pass over in M3
# by placing 1 1/4 a cell pitch down because both power connections and inputs/outputs
# may be routed in M3 or M4
# TODO: In tsmc180, is not 1.25 (dff is 6.72. crosses with the first gnd)
mult = 1.25
if OPTS.tech_name in ["tsmc18", "lapis20", "rohm180"]:
mult = 1.5
x_offset = self.bitcell_array_right + self.central_bus_width[port] + self.port_address[port].wordline_driver_array.width
if self.col_addr_size > 0:
x_offset += self.column_decoder.width + self.col_addr_bus_width
y_offset = self.bitcell_array_top + 1.25 * self.dff.height + self.column_decoder.height
y_offset = self.bitcell_array_top + mult * self.dff.height + self.column_decoder.height
else:
y_offset = self.bitcell_array_top
self.column_decoder_offsets[port] = vector(x_offset, y_offset)
Expand Down
27 changes: 26 additions & 1 deletion compiler/modules/column_mux.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from sram_factory import factory
from tech import cell_properties as cell_props
from globals import OPTS
from utils import round_to_grid


class column_mux(pgate):
Expand Down Expand Up @@ -232,7 +233,7 @@ def add_pn_wells(self):
active_pos = vector(rbc_width,
self.nmos_upper.by() - 0.5 * self.poly_space)

self.add_via_center(layers=self.active_stack,
self.well_contact = self.add_via_center(layers=self.active_stack,
offset=active_pos,
implant_type="p",
well_type="p")
Expand All @@ -251,3 +252,27 @@ def add_pn_wells(self):
offset=vector(0, 0),
width=rbc_width,
height=self.height)

# TSMC18 gate port hack
if OPTS.tech_name in ["tsmc18", "lapis20", "rohm180"]:
# Body connection
min_area = drc["minarea_{}".format(self.active_stack[0])]
width = round_to_grid(self.well_contact.mod.first_layer_width)
height = round_to_grid(min_area / width)
width_impl = width + 2 * drc("implant_enclose_active")
height_impl = height + 2 * drc("implant_enclose_active") # contact.py:250
self.add_rect_center(layer=self.active_stack[0],
offset=active_pos,
width=width,
height=height)
self.add_rect_center(layer="pimplant",
offset=active_pos,
width=width_impl,
height=height_impl)
if "pwell" in layer:
width_well = width + 2 * self.well_contact.mod.well_enclose_active
height_well = height + 2 * self.well_contact.mod.well_enclose_active # contact.py:264
self.add_rect_center(layer="pwell",
offset=active_pos,
width=width_well,
height=height_well)
27 changes: 27 additions & 0 deletions compiler/modules/pand2.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
from base import vector
from .pgate import *
from sram_factory import factory
from globals import OPTS
from tech import drc


class pand2(pgate):
Expand Down Expand Up @@ -82,6 +84,31 @@ def place_insts(self):
# Add INV to the right
self.inv_inst.place(offset=vector(self.nand_inst.rx(), 0))

# Extension of the imp in both n and p for tsmc18
if OPTS.tech_name in ["tsmc18", "lapis20", "rohm180"]:
pmos_rightmost_nand = self.nand_inst.mod.pmos2_pos
pmos_leftmost_inv = self.inv_inst.mod.inv_inst_list[0].mod.pmos_pos + vector(self.nand_inst.rx(), 0)
nmos_rightmost_nand = self.nand_inst.mod.nmos2_pos
nmos_leftmost_inv = self.inv_inst.mod.inv_inst_list[0].mod.nmos_pos + vector(self.nand_inst.rx(), 0)
pleft = pmos_rightmost_nand.x + self.nand_inst.mod.pmos_right.active_width + drc("implant_enclose_active")
pright = pmos_leftmost_inv.x - drc("implant_enclose_active")
ptop = pmos_rightmost_nand.y + self.nand_inst.mod.pmos_right.active_height + \
max(drc("implant_enclose_active"), drc("implant_to_channel"))
pbottom = pmos_rightmost_nand.y - max(drc("implant_enclose_active"), drc("implant_to_channel"))
self.add_rect(layer="pimplant",
offset=vector(pleft, pbottom),
width=pright - pleft,
height=ptop - pbottom)
nleft = nmos_rightmost_nand.x + self.nand_inst.mod.nmos_right.active_width + drc("implant_enclose_active")
nright = nmos_leftmost_inv.x - drc("implant_enclose_active")
ntop = nmos_rightmost_nand.y + self.nand_inst.mod.nmos_right.active_height + \
max(drc("implant_enclose_active"), drc("implant_to_channel"))
nbottom = nmos_rightmost_nand.y - max(drc("implant_enclose_active"), drc("implant_to_channel"))
self.add_rect(layer="nimplant",
offset=vector(nleft, nbottom),
width=nright - nleft,
height=ntop - nbottom)

def route_supply_rails(self):
""" Add vdd/gnd rails to the top, (middle), and bottom. """
self.add_layout_pin_rect_center(text="gnd",
Expand Down
Loading