mirror of https://github.com/VLSIDA/OpenRAM.git
Merge remote-tracking branch 'private/dev' into dev
This commit is contained in:
commit
978693eb2a
23
HINTS.md
23
HINTS.md
|
|
@ -37,7 +37,15 @@ to run Calibre or Magic+Netgen.
|
|||
To debug, you will need a layout viewer. I prefer to use Glade
|
||||
on my Mac, but you can also use Calibre, Magic, etc.
|
||||
|
||||
1. Calibre
|
||||
1. Klayout
|
||||
|
||||
You can view the designs in [Klayout](https://www.klayout.de/) with the configuration
|
||||
file provided in the tech directories. For example,
|
||||
```
|
||||
klayout temp.gds -l /home/vagrant/openram/technology/freepdk45/tf/FreePDK45.lyp
|
||||
```
|
||||
|
||||
2. Calibre
|
||||
|
||||
Start the Calibre DESIGNrev viewer in the temp directory and load your GDS file:
|
||||
```
|
||||
|
|
@ -52,10 +60,9 @@ on my Mac, but you can also use Calibre, Magic, etc.
|
|||
|
||||
In the viewer ">" opens the layout down a level.
|
||||
|
||||
2. Glade
|
||||
3. Glade
|
||||
|
||||
You can view errors in Glade as well. I like this because it is on my laptop.
|
||||
You can get it from: http://www.peardrop.co.uk/glade/
|
||||
You can view errors in [Glade](http://www.peardrop.co.uk/glade/) as well.
|
||||
|
||||
To remote display over X windows, you need to disable OpenGL acceleration or use vnc
|
||||
or something. You can disable by adding this to your .bashrc in bash:
|
||||
|
|
@ -82,16 +89,16 @@ ui().importCds("default",
|
|||
To load the errors, you simply do Verify->Import Calibre Errors select
|
||||
the .results file from Calibre.
|
||||
|
||||
3. Magic
|
||||
4. Magic
|
||||
|
||||
Magic is only supported in SCMOS. You will need to install the MOSIS SCMOS rules
|
||||
and Magic from: http://opencircuitdesign.com/
|
||||
and [Magic](http://opencircuitdesign.com/)
|
||||
|
||||
When running DRC or extraction, OpenRAM will load the GDS file, save
|
||||
the .ext/.mag files, and export an extracted netlist (.spice).
|
||||
|
||||
4. It is possible to use other viewers as well, such as:
|
||||
* LayoutEditor http://www.layouteditor.net/
|
||||
5. It is possible to use other viewers as well, such as:
|
||||
* [LayoutEditor](http://www.layouteditor.net/)
|
||||
|
||||
|
||||
# Example to output/input .gds layout files from/to Cadence
|
||||
|
|
|
|||
41
README.md
41
README.md
|
|
@ -33,15 +33,6 @@ things that need to be fixed.
|
|||
|
||||
# Basic Setup
|
||||
|
||||
## Docker Image
|
||||
|
||||
We have a pre-configured Ubuntu [Docker](https://www.docker.com/) image
|
||||
available that has all tools installed for the [SCMOS] process. It is
|
||||
available at [docker hub](https://hub.docker.com/r/vlsida/openram-ubuntu).
|
||||
Please see
|
||||
[our README.md](https://github.com/VLSIDA/openram-docker-images/blob/master/README.md)
|
||||
for information on how to use this docker image.
|
||||
|
||||
## Dependencies
|
||||
|
||||
The OpenRAM compiler has very few dependencies:
|
||||
|
|
@ -88,6 +79,23 @@ You may get the entire [FreePDK45 PDK here][FreePDK45].
|
|||
If you are using [SCMOS], you should install [Magic] and [Netgen].
|
||||
We have included the most recent SCN4M_SUBM design rules from [Qflow].
|
||||
|
||||
## Docker Image
|
||||
|
||||
We have a pre-configured Ubuntu [Docker](https://www.docker.com/) image
|
||||
available that has all tools installed for the [SCMOS] process. It is
|
||||
available at [docker hub](https://hub.docker.com/r/vlsida/openram-ubuntu).
|
||||
Please see
|
||||
[our README.md](https://github.com/VLSIDA/openram-docker-images/blob/master/README.md)
|
||||
for information on how to use this docker image.
|
||||
|
||||
## Vagrant Image
|
||||
|
||||
We have a pre-configured Ubuntu [Vagrant](https://www.vagrantup.com/) image
|
||||
available that has all tools installed for the [SCMOS] process.
|
||||
Please see
|
||||
[our README.md](https://github.com/VLSIDA/openram-vagrant-image/blob/master/README.md)
|
||||
for information on how to use this image.
|
||||
|
||||
# Basic Usage
|
||||
|
||||
Once you have defined the environment, you can run OpenRAM from the command line
|
||||
|
|
@ -104,12 +112,16 @@ num_words = 16
|
|||
|
||||
# Technology to use in $OPENRAM_TECH
|
||||
tech_name = "scn4m_subm"
|
||||
|
||||
# You can use the technology nominal corner only
|
||||
nominal_corner_only = True
|
||||
# Or you can specify particular corners
|
||||
# Process corners to characterize
|
||||
process_corners = ["TT"]
|
||||
# process_corners = ["SS", "TT", "FF"]
|
||||
# Voltage corners to characterize
|
||||
supply_voltages = [ 3.3 ]
|
||||
# supply_voltages = [ 3.0, 3.3, 3.5 ]
|
||||
# Temperature corners to characterize
|
||||
temperatures = [ 25 ]
|
||||
# temperatures = [ 0, 25 100]
|
||||
|
||||
# Output directory for the results
|
||||
output_path = "temp"
|
||||
|
|
@ -119,11 +131,6 @@ output_name = "sram_{0}_{1}_{2}".format(word_size,num_words,tech_name)
|
|||
# Disable analytical models for full characterization (WARNING: slow!)
|
||||
# analytical_delay = False
|
||||
|
||||
# To force this to use magic and netgen for DRC/LVS/PEX
|
||||
# Could be calibre for FreePDK45
|
||||
drc_name = "magic"
|
||||
lvs_name = "netgen"
|
||||
pex_name = "magic"
|
||||
```
|
||||
|
||||
You can then run OpenRAM by executing:
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ class contact(hierarchy_design.hierarchy_design):
|
|||
# Module does not have pins, but has empty pin list.
|
||||
self.pins = []
|
||||
self.create_layout()
|
||||
|
||||
|
||||
def create_layout(self):
|
||||
|
||||
self.setup_layers()
|
||||
|
|
@ -71,15 +71,15 @@ class contact(hierarchy_design.hierarchy_design):
|
|||
|
||||
(first_layer, via_layer, second_layer) = self.layer_stack
|
||||
self.first_layer_name = first_layer
|
||||
self.via_layer_name = via_layer
|
||||
# Some technologies have a separate active
|
||||
# contact from the poly contact
|
||||
# We will use contact for DRC, but active_contact for output
|
||||
if first_layer == "active" or second_layer == "active":
|
||||
self.via_layer_name_expanded = "active_" + via_layer
|
||||
else:
|
||||
self.via_layer_name_expanded = via_layer
|
||||
self.second_layer_name = second_layer
|
||||
# Contacts will have unique per first layer
|
||||
if via_layer == "contact":
|
||||
if first_layer in ("active", "poly"):
|
||||
self.via_layer_name = first_layer + "_" + via_layer
|
||||
else:
|
||||
self.via_layer_name = second_layer + "_" + via_layer
|
||||
else:
|
||||
self.via_layer_name = via_layer
|
||||
|
||||
def setup_layout_constants(self):
|
||||
""" Determine the design rules for the enclosure layers """
|
||||
|
|
@ -144,7 +144,7 @@ class contact(hierarchy_design.hierarchy_design):
|
|||
for i in range(self.dimensions[1]):
|
||||
offset = self.via_layer_position + vector(0, self.contact_pitch * i)
|
||||
for j in range(self.dimensions[0]):
|
||||
self.add_rect(layer=self.via_layer_name_expanded,
|
||||
self.add_rect(layer=self.via_layer_name,
|
||||
offset=offset,
|
||||
width=self.contact_width,
|
||||
height=self.contact_width)
|
||||
|
|
|
|||
|
|
@ -48,12 +48,12 @@ class design(hierarchy_design):
|
|||
self.m4_space = drc("metal4_to_metal4")
|
||||
self.active_width = drc("minwidth_active")
|
||||
self.active_space = drc("active_to_body_active")
|
||||
self.contact_width = drc("minwidth_contact")
|
||||
self.contact_width = drc("minwidth_active_contact")
|
||||
|
||||
self.poly_to_active = drc("poly_to_active")
|
||||
self.poly_extend_active = drc("poly_extend_active")
|
||||
self.poly_to_polycontact = drc("poly_to_polycontact")
|
||||
self.contact_to_gate = drc("contact_to_gate")
|
||||
self.poly_to_poly_contact = drc("poly_to_poly_contact")
|
||||
self.active_contact_to_gate = drc("active_contact_to_gate")
|
||||
self.well_enclose_active = drc("well_enclosure_active")
|
||||
self.implant_enclose_active = drc("implant_enclosure_active")
|
||||
self.implant_space = drc("implant_to_implant")
|
||||
|
|
|
|||
|
|
@ -327,7 +327,6 @@ class label(geometry):
|
|||
debug.info(4, "writing label (" + str(self.layerNumber) + "): " + self.text)
|
||||
new_layout.addText(text=self.text,
|
||||
layerNumber=self.layerNumber,
|
||||
purposeNumber=self.layerPurpose,
|
||||
offsetInMicrons=self.offset,
|
||||
magnification=self.zoom,
|
||||
rotate=None)
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ class layout():
|
|||
self.name = name
|
||||
self.width = None
|
||||
self.height = None
|
||||
self.boundary = None
|
||||
self.insts = [] # Holds module/cell layout instances
|
||||
self.objs = [] # Holds all other objects (labels, geometries, etc)
|
||||
self.pin_map = {} # Holds name->pin_layout map for all pins
|
||||
|
|
@ -80,7 +81,10 @@ class layout():
|
|||
lowesty2 = min(inst.by() for inst in self.insts)
|
||||
else:
|
||||
lowestx2=lowesty2=None
|
||||
if lowestx1==None:
|
||||
|
||||
if lowestx1==None and lowestx2==None:
|
||||
return None
|
||||
elif lowestx1==None:
|
||||
return vector(lowestx2,lowesty2)
|
||||
elif lowestx2==None:
|
||||
return vector(lowestx1,lowesty1)
|
||||
|
|
@ -101,7 +105,9 @@ class layout():
|
|||
highesty2 = max(inst.uy() for inst in self.insts)
|
||||
else:
|
||||
highestx2=highesty2=None
|
||||
if highestx1==None:
|
||||
if highestx1==None and highestx2==None:
|
||||
return None
|
||||
elif highestx1==None:
|
||||
return vector(highestx2,highesty2)
|
||||
elif highestx2==None:
|
||||
return vector(highestx1,highesty1)
|
||||
|
|
@ -500,6 +506,27 @@ class layout():
|
|||
for pin_name in self.pin_map.keys():
|
||||
for pin in self.pin_map[pin_name]:
|
||||
pin.gds_write_file(gds_layout)
|
||||
|
||||
# If it's not a premade cell
|
||||
# and we didn't add our own boundary,
|
||||
# we should add a boundary just for DRC in some technologies
|
||||
if not self.is_library_cell and not self.boundary:
|
||||
# If there is a boundary layer, and we didn't create one, add one.
|
||||
if "stdc" in techlayer.keys():
|
||||
boundary_layer = "stdc"
|
||||
boundary = [self.find_lowest_coords(), self.find_highest_coords()]
|
||||
height = boundary[1][1] - boundary[0][1]
|
||||
width = boundary[1][0] - boundary[0][0]
|
||||
(layer_number, layer_purpose) = techlayer[boundary_layer]
|
||||
gds_layout.addBox(layerNumber=layer_number,
|
||||
purposeNumber=layer_purpose,
|
||||
offsetInMicrons=boundary[0],
|
||||
width=width,
|
||||
height=height,
|
||||
center=False)
|
||||
debug.info(2, "Adding {0} boundary {1}".format(self.name, boundary))
|
||||
|
||||
|
||||
self.visited.append(self.name)
|
||||
|
||||
def gds_write(self, gds_name):
|
||||
|
|
@ -937,12 +964,22 @@ class layout():
|
|||
"""
|
||||
self.create_channel_route(netlist, offset, layer_stack, vertical=False)
|
||||
|
||||
def add_boundary(self, offset=vector(0,0)):
|
||||
def add_boundary(self, ll=vector(0,0), ur=None):
|
||||
""" Add boundary for debugging dimensions """
|
||||
self.add_rect(layer="boundary",
|
||||
offset=offset,
|
||||
height=self.height,
|
||||
width=self.width)
|
||||
if "stdc" in techlayer.keys():
|
||||
boundary_layer = "stdc"
|
||||
else:
|
||||
boundary_layer = "boundary"
|
||||
if ur == None:
|
||||
self.boundary = self.add_rect(layer=boundary_layer,
|
||||
offset=ll,
|
||||
height=self.height,
|
||||
width=self.width)
|
||||
else:
|
||||
self.boundary = self.add_rect(layer=boundary_layer,
|
||||
offset=ll,
|
||||
height=ur.y-ll.y,
|
||||
width=ur.x-ll.x)
|
||||
|
||||
def add_enclosure(self, insts, layer="nwell"):
|
||||
""" Add a layer that surrounds the given instances. Useful
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ class pin_layout:
|
|||
# else it is required to be a lpp
|
||||
else:
|
||||
for (layer_name, lpp) in layer.items():
|
||||
if not lpp:
|
||||
continue
|
||||
if self.same_lpp(layer_name_pp, lpp):
|
||||
self.layer = layer_name
|
||||
break
|
||||
|
|
@ -342,7 +344,6 @@ class pin_layout:
|
|||
# imported into Magic.
|
||||
newLayout.addText(text=self.name,
|
||||
layerNumber=layer_num,
|
||||
purposeNumber=purpose,
|
||||
offsetInMicrons=self.center(),
|
||||
magnification=GDS["zoom"],
|
||||
rotate=None)
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ class dummy_pbitcell(design.design):
|
|||
|
||||
self.create_netlist()
|
||||
self.create_layout()
|
||||
self.add_boundary()
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
|
|
|
|||
|
|
@ -243,7 +243,7 @@ class pbitcell(bitcell_base.bitcell_base):
|
|||
(self.inverter_nmos.active_contact.height - self.inverter_nmos.active_height)
|
||||
self.inverter_gap = max(self.poly_to_active,
|
||||
self.m1_space + inverter_nmos_contact_extension) \
|
||||
+ self.poly_to_polycontact + 2 * contact.poly.width \
|
||||
+ self.poly_to_poly_contact + 2 * contact.poly.width \
|
||||
+ self.m1_space + inverter_pmos_contact_extension
|
||||
self.cross_couple_lower_ypos = self.inverter_nmos_ypos \
|
||||
+ self.inverter_nmos.active_height \
|
||||
|
|
@ -254,7 +254,7 @@ class pbitcell(bitcell_base.bitcell_base):
|
|||
+ self.inverter_nmos.active_height \
|
||||
+ max(self.poly_to_active,
|
||||
self.m1_space + inverter_nmos_contact_extension) \
|
||||
+ self.poly_to_polycontact \
|
||||
+ self.poly_to_poly_contact \
|
||||
+ 1.5 * contact.poly.width
|
||||
|
||||
# spacing between wordlines (and gnd)
|
||||
|
|
@ -926,14 +926,14 @@ class pbitcell(bitcell_base.bitcell_base):
|
|||
"""
|
||||
# add poly to metal1 contacts for gates of the inverters
|
||||
left_storage_contact = vector(self.inverter_nmos_left.get_pin("G").lc().x \
|
||||
- self.poly_to_polycontact - 0.5*contact.poly.width,
|
||||
- self.poly_to_poly_contact - 0.5*contact.poly.width,
|
||||
self.cross_couple_upper_ypos)
|
||||
self.add_via_center(layers=("poly", "contact", "metal1"),
|
||||
offset=left_storage_contact,
|
||||
directions=("H", "H"))
|
||||
|
||||
right_storage_contact = vector(self.inverter_nmos_right.get_pin("G").rc().x \
|
||||
+ self.poly_to_polycontact + 0.5*contact.poly.width,
|
||||
+ self.poly_to_poly_contact + 0.5*contact.poly.width,
|
||||
self.cross_couple_upper_ypos)
|
||||
self.add_via_center(layers=("poly", "contact", "metal1"),
|
||||
offset=right_storage_contact,
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ class replica_pbitcell(design.design):
|
|||
|
||||
self.create_netlist()
|
||||
self.create_layout()
|
||||
self.add_boundary()
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
|
|
@ -84,4 +85,4 @@ class replica_pbitcell(design.design):
|
|||
self.copy_layout_pin(self.prbc_inst, "wl{}".format(port))
|
||||
self.copy_layout_pin(self.prbc_inst, "vdd")
|
||||
self.copy_layout_pin(self.prbc_inst, "gnd")
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -66,25 +66,49 @@ class lib:
|
|||
self.supply_voltages = OPTS.supply_voltages
|
||||
self.process_corners = OPTS.process_corners
|
||||
|
||||
# Enumerate all possible corners
|
||||
# Corner values
|
||||
min_temperature = min(self.temperatures)
|
||||
nom_temperature = tech.spice["nom_temperature"]
|
||||
max_temperature = max(self.temperatures)
|
||||
min_supply = min(self.supply_voltages)
|
||||
nom_supply = tech.spice["nom_supply_voltage"]
|
||||
max_supply = max(self.supply_voltages)
|
||||
min_process = "FF"
|
||||
nom_process = "TT"
|
||||
max_process = "SS"
|
||||
|
||||
self.corners = []
|
||||
self.lib_files = []
|
||||
for proc in self.process_corners:
|
||||
for temp in self.temperatures:
|
||||
for volt in self.supply_voltages:
|
||||
self.corner_name = "{0}_{1}_{2}V_{3}C".format(self.sram.name,
|
||||
proc,
|
||||
volt,
|
||||
temp)
|
||||
self.corner_name = self.corner_name.replace(".","p") # Remove decimals
|
||||
lib_name = self.out_dir+"{}.lib".format(self.corner_name)
|
||||
|
||||
# Nominal corner
|
||||
self.add_corner(nom_process, nom_supply, nom_temperature)
|
||||
if not OPTS.nominal_corner_only:
|
||||
# Temperature corners
|
||||
self.add_corner(nom_process, nom_supply, min_temperature)
|
||||
self.add_corner(nom_process, nom_supply, max_temperature)
|
||||
# Supply corners
|
||||
self.add_corner(nom_process, min_supply, nom_temperature)
|
||||
self.add_corner(nom_process, max_supply, nom_temperature)
|
||||
# Process corners
|
||||
self.add_corner(min_process, nom_supply, nom_temperature)
|
||||
self.add_corner(max_process, nom_supply, nom_temperature)
|
||||
|
||||
def add_corner(self, proc, volt, temp):
|
||||
self.corner_name = "{0}_{1}_{2}V_{3}C".format(self.sram.name,
|
||||
proc,
|
||||
volt,
|
||||
temp)
|
||||
self.corner_name = self.corner_name.replace(".","p") # Remove decimals
|
||||
lib_name = self.out_dir+"{}.lib".format(self.corner_name)
|
||||
|
||||
# A corner is a tuple of PVT
|
||||
self.corners.append((proc, volt, temp))
|
||||
self.lib_files.append(lib_name)
|
||||
|
||||
# A corner is a tuple of PVT
|
||||
self.corners.append((proc, volt, temp))
|
||||
self.lib_files.append(lib_name)
|
||||
|
||||
def characterize_corners(self):
|
||||
""" Characterize the list of corners. """
|
||||
debug.info(1,"Characterizing corners: " + str(self.corners))
|
||||
for (self.corner,lib_name) in zip(self.corners,self.lib_files):
|
||||
debug.info(1,"Corner: " + str(self.corner))
|
||||
(self.process, self.voltage, self.temperature) = self.corner
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ word_size = 32
|
|||
num_words = 128
|
||||
|
||||
tech_name = "scn4m_subm"
|
||||
nominal_corners_only = False
|
||||
process_corners = ["TT"]
|
||||
supply_voltages = [5.0]
|
||||
temperatures = [25]
|
||||
|
|
@ -9,6 +10,3 @@ temperatures = [25]
|
|||
output_path = "temp"
|
||||
output_name = "sram_{0}_{1}_{2}".format(word_size, num_words, tech_name)
|
||||
|
||||
drc_name = "magic"
|
||||
lvs_name = "netgen"
|
||||
pex_name = "magic"
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ num_r_ports = 1
|
|||
num_w_ports = 0
|
||||
|
||||
tech_name = "scn4m_subm"
|
||||
nominal_corners_only = False
|
||||
process_corners = ["TT"]
|
||||
supply_voltages = [5.0]
|
||||
temperatures = [25]
|
||||
|
|
@ -17,7 +18,3 @@ output_path = "temp"
|
|||
output_name = "sram_1rw_1r_{0}_{1}_{2}".format(word_size,
|
||||
num_words,
|
||||
tech_name)
|
||||
|
||||
drc_name = "magic"
|
||||
lvs_name = "netgen"
|
||||
pex_name = "magic"
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ num_r_ports = 1
|
|||
num_w_ports = 0
|
||||
|
||||
tech_name = "scn4m_subm"
|
||||
nominal_corners_only = False
|
||||
process_corners = ["TT"]
|
||||
supply_voltages = [5.0]
|
||||
temperatures = [25]
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ word_size = 2
|
|||
num_words = 16
|
||||
|
||||
tech_name = "freepdk45"
|
||||
nominal_corners_only = False
|
||||
process_corners = ["TT"]
|
||||
supply_voltages = [1.0]
|
||||
temperatures = [25]
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ word_size = 2
|
|||
num_words = 16
|
||||
|
||||
tech_name = "scn4m_subm"
|
||||
nominal_corners_only = False
|
||||
process_corners = ["TT"]
|
||||
supply_voltages = [5.0]
|
||||
temperatures = [25]
|
||||
|
|
@ -14,6 +15,3 @@ output_name = "sram_{0}_{1}_{2}".format(word_size,
|
|||
num_words,
|
||||
tech_name)
|
||||
|
||||
drc_name = "magic"
|
||||
lvs_name = "netgen"
|
||||
pex_name = "magic"
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ word_size = 64
|
|||
num_words = 1024
|
||||
|
||||
tech_name = "scn4m_subm"
|
||||
nominal_corners_only = False
|
||||
process_corners = ["TT"]
|
||||
supply_voltages = [ 5.0 ]
|
||||
temperatures = [ 25 ]
|
||||
|
|
@ -10,7 +11,3 @@ output_path = "temp"
|
|||
output_name = "sram_{0}_{1}_{2}".format(word_size,
|
||||
num_words,
|
||||
tech_name)
|
||||
|
||||
drc_name = "magic"
|
||||
lvs_name = "netgen"
|
||||
pex_name = "magic"
|
||||
|
|
|
|||
|
|
@ -2,8 +2,9 @@ word_size = 16
|
|||
num_words = 256
|
||||
|
||||
tech_name = "scn4m_subm"
|
||||
nominal_corners_only = False
|
||||
process_corners = ["TT"]
|
||||
supply_voltages = [3.3]
|
||||
supply_voltages = [5.0]
|
||||
temperatures = [25]
|
||||
|
||||
output_path = "temp"
|
||||
|
|
@ -11,6 +12,3 @@ output_name = "sram_{0}_{1}_{2}".format(word_size,
|
|||
num_words,
|
||||
tech_name)
|
||||
|
||||
drc_name = "magic"
|
||||
lvs_name = "netgen"
|
||||
pex_name = "magic"
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ class Gds2reader:
|
|||
print("Mask: "+mask)
|
||||
elif(idBits==b'\x03\x05'): #this is also wrong b/c python doesn't natively have an 8 byte float
|
||||
userUnits=self.ieeeDoubleFromIbmData(record[2:10])
|
||||
dbUnits=self.ieeeDoubleFromIbmData
|
||||
dbUnits=self.ieeeDoubleFromIbmData(record[10:18])
|
||||
self.layoutObject.info["units"] = (userUnits,dbUnits)
|
||||
if(self.debugToTerminal==1):
|
||||
print("Units: 1 user unit="+str(userUnits)+" database units, 1 database unit="+str(dbUnits)+" meters.")
|
||||
|
|
@ -175,6 +175,8 @@ class Gds2reader:
|
|||
|
||||
def readBoundary(self):
|
||||
##reads in a boundary type structure = a filled polygon
|
||||
if(self.debugToTerminal==1):
|
||||
print("\t\t\tBeginBoundary")
|
||||
thisBoundary=GdsBoundary()
|
||||
while 1:
|
||||
record = self.readNextRecord()
|
||||
|
|
@ -201,11 +203,6 @@ class Gds2reader:
|
|||
thisBoundary.purposeLayer=purposeLayer
|
||||
if(self.debugToTerminal==1):
|
||||
print("\t\tPurpose Layer: "+str(purposeLayer))
|
||||
elif(idBits==b'\x0E\x02'): #DataType
|
||||
dataType = struct.unpack(">h",record[2:4])[0]
|
||||
thisBoundary.dataType=dataType
|
||||
if(self.debugToTerminal==1):
|
||||
print("\t\t\tData Type: "+str(dataType))
|
||||
elif(idBits==b'\x10\x03'): #XY Data Points
|
||||
numDataPoints = len(record)-2 #packed as XY coordinates 4 bytes each
|
||||
thisBoundary.coordinates=[]
|
||||
|
|
@ -216,10 +213,15 @@ class Gds2reader:
|
|||
if(self.debugToTerminal==1):
|
||||
print("\t\t\tXY Point: "+str(x)+","+str(y))
|
||||
elif(idBits==b'\x11\x00'): #End Of Element
|
||||
if(self.debugToTerminal==1):
|
||||
print("\t\t\tEndBoundary")
|
||||
break;
|
||||
return thisBoundary
|
||||
|
||||
def readPath(self): #reads in a path structure
|
||||
if(self.debugToTerminal==1):
|
||||
print("\t\t\tBeginPath")
|
||||
|
||||
thisPath=GdsPath()
|
||||
while 1:
|
||||
record = self.readNextRecord()
|
||||
|
|
@ -266,10 +268,15 @@ class Gds2reader:
|
|||
if(self.debugToTerminal==1):
|
||||
print("\t\t\tXY Point: "+str(x)+","+str(y))
|
||||
elif(idBits==b'\x11\x00'): #End Of Element
|
||||
if(self.debugToTerminal==1):
|
||||
print("\t\t\tEndPath")
|
||||
break;
|
||||
return thisPath
|
||||
|
||||
def readSref(self): #reads in a reference to another structure
|
||||
if(self.debugToTerminal==1):
|
||||
print("\t\t\tBeginSref")
|
||||
|
||||
thisSref=GdsSref()
|
||||
while 1:
|
||||
record = self.readNextRecord()
|
||||
|
|
@ -317,10 +324,15 @@ class Gds2reader:
|
|||
if(self.debugToTerminal==1):
|
||||
print("\t\t\tXY Point: "+str(x)+","+str(y))
|
||||
elif(idBits==b'\x11\x00'): #End Of Element
|
||||
if(self.debugToTerminal==1):
|
||||
print("\t\t\tEndSref")
|
||||
break;
|
||||
return thisSref
|
||||
|
||||
def readAref(self): #an array of references
|
||||
if(self.debugToTerminal==1):
|
||||
print("\t\t\tBeginAref")
|
||||
|
||||
thisAref = GdsAref()
|
||||
while 1:
|
||||
record = self.readNextRecord()
|
||||
|
|
@ -372,11 +384,15 @@ class Gds2reader:
|
|||
print("\t\t\t\tArray Width: "+str(rightMostX-topLeftX))
|
||||
print("\t\t\t\tArray Height: "+str(topLeftY-bottomMostY))
|
||||
elif(idBits==b'\x11\x00'): #End Of Element
|
||||
if(self.debugToTerminal==1):
|
||||
print("\t\t\tEndAref")
|
||||
break;
|
||||
return thisAref
|
||||
|
||||
def readText(self):
|
||||
##reads in a text structure
|
||||
if(self.debugToTerminal==1):
|
||||
print("\t\t\tBeginText")
|
||||
|
||||
thisText=GdsText()
|
||||
while 1:
|
||||
record = self.readNextRecord()
|
||||
|
|
@ -472,10 +488,15 @@ class Gds2reader:
|
|||
if(self.debugToTerminal==1):
|
||||
print("\t\t\tText String: "+textString)
|
||||
elif(idBits==b'\x11\x00'): #End Of Element
|
||||
if(self.debugToTerminal==1):
|
||||
print("\t\t\tEndText")
|
||||
break;
|
||||
return thisText
|
||||
|
||||
def readNode(self):
|
||||
if(self.debugToTerminal==1):
|
||||
print("\t\t\tBeginNode")
|
||||
|
||||
##reads in a node type structure = an electrical net
|
||||
thisNode = GdsNode()
|
||||
while 1:
|
||||
|
|
@ -513,10 +534,15 @@ class Gds2reader:
|
|||
if(self.debugToTerminal==1):
|
||||
print("\t\t\tXY Point: "+str(x)+","+str(y))
|
||||
elif(idBits==b'\x11\x00'): #End Of Element
|
||||
if(self.debugToTerminal==1):
|
||||
print("\t\t\tEndNode")
|
||||
break;
|
||||
return thisNode
|
||||
|
||||
def readBox(self):
|
||||
if(self.debugToTerminal==1):
|
||||
print("\t\t\tBeginBox")
|
||||
|
||||
##reads in a gds BOX structure
|
||||
thisBox = GdsBox()
|
||||
while 1:
|
||||
|
|
@ -559,6 +585,8 @@ class Gds2reader:
|
|||
if(self.debugToTerminal==1):
|
||||
print("\t\t\tXY Point: "+str(x)+","+str(y))
|
||||
elif(idBits==b'\x11\x00'): #End Of Element
|
||||
if(self.debugToTerminal==1):
|
||||
print("\t\t\tEndBox")
|
||||
break;
|
||||
return thisBox
|
||||
|
||||
|
|
@ -566,6 +594,7 @@ class Gds2reader:
|
|||
thisStructure = GdsStructure()
|
||||
record = self.readNextRecord()
|
||||
idBits = record[0:2]
|
||||
# Begin structure
|
||||
if(idBits==b'\x05\x02' and len(record)==26):
|
||||
createYear = struct.unpack(">h",record[2:4])[0]
|
||||
createMonth = struct.unpack(">h",record[4:6])[0]
|
||||
|
|
@ -581,6 +610,10 @@ class Gds2reader:
|
|||
modSecond = struct.unpack(">h",record[24:26])[0]
|
||||
thisStructure.createDate=(createYear,createMonth,createDay,createHour,createMinute,createSecond)
|
||||
thisStructure.modDate=(modYear,modMonth,modDay,modHour,modMinute,modSecond)
|
||||
if(self.debugToTerminal==1):
|
||||
print("Date Created:"+str(createYear)+","+str(createMonth)+","+str(createDay)+\
|
||||
","+str(createHour)+","+str(createMinute)+","+str(createSecond))
|
||||
print("Date Modified:"+str(modYear)+","+str(modMonth)+","+str(modDay)+","+str(modHour)+","+str(modMinute)+","+str(modSecond))
|
||||
else:
|
||||
#means we have hit the last structure, so return the record
|
||||
#to whoever called us to do something with it
|
||||
|
|
|
|||
|
|
@ -187,27 +187,25 @@ class Gds2writer:
|
|||
idBits=b'\x08\x00' #record Type
|
||||
self.writeRecord(idBits)
|
||||
if(thisBoundary.elementFlags!=""):
|
||||
idBits=b'\x26\x01' #ELFLAGS
|
||||
idBits=b'\x26\x01' # ELFLAGS
|
||||
elementFlags = struct.pack(">h",thisBoundary.elementFlags)
|
||||
self.writeRecord(idBits+elementFlags)
|
||||
if(thisBoundary.plex!=""):
|
||||
idBits=b'\x2F\x03' #PLEX
|
||||
idBits=b'\x2F\x03' # PLEX
|
||||
plex = struct.pack(">i",thisBoundary.plex)
|
||||
self.writeRecord(idBits+plex)
|
||||
if(thisBoundary.drawingLayer!=""):
|
||||
idBits=b'\x0D\x02' #drawig layer
|
||||
idBits=b'\x0D\x02' # drawing layer
|
||||
drawingLayer = struct.pack(">h",thisBoundary.drawingLayer)
|
||||
self.writeRecord(idBits+drawingLayer)
|
||||
if(thisBoundary.purposeLayer):
|
||||
idBits=b'\x16\x02' #purpose layer
|
||||
purposeLayer = struct.pack(">h",thisBoundary.purposeLayer)
|
||||
self.writeRecord(idBits+purposeLayer)
|
||||
if(thisBoundary.dataType!=""):
|
||||
idBits=b'\x0E\x02'#DataType
|
||||
dataType = struct.pack(">h",thisBoundary.dataType)
|
||||
if(thisBoundary.purposeLayer!=""):
|
||||
idBits=b'\x0E\x02' # DataType
|
||||
if type(thisBoundary.purposeLayer)!=int:
|
||||
import pdb; pdb.set_trace()
|
||||
dataType = struct.pack(">h",thisBoundary.purposeLayer)
|
||||
self.writeRecord(idBits+dataType)
|
||||
if(thisBoundary.coordinates!=""):
|
||||
idBits=b'\x10\x03' #XY Data Points
|
||||
idBits=b'\x10\x03' # XY Data Points
|
||||
coordinateRecord = idBits
|
||||
for coordinate in thisBoundary.coordinates:
|
||||
x=struct.pack(">i",int(coordinate[0]))
|
||||
|
|
@ -377,9 +375,9 @@ class Gds2writer:
|
|||
idBits=b'\x0D\x02' #drawing layer
|
||||
drawingLayer = struct.pack(">h",thisText.drawingLayer)
|
||||
self.writeRecord(idBits+drawingLayer)
|
||||
#if(thisText.purposeLayer):
|
||||
# TextType is always a 0 per GDS specification
|
||||
idBits=b'\x16\x02' #purpose layer
|
||||
purposeLayer = struct.pack(">h",thisText.purposeLayer)
|
||||
purposeLayer = struct.pack(">h",0)
|
||||
self.writeRecord(idBits+purposeLayer)
|
||||
if(thisText.transFlags != ""):
|
||||
idBits=b'\x1A\x01'
|
||||
|
|
|
|||
|
|
@ -21,8 +21,7 @@ class GdsBoundary:
|
|||
self.elementFlags=""
|
||||
self.plex=""
|
||||
self.drawingLayer=""
|
||||
self.purposeLayer = None
|
||||
self.dataType=""
|
||||
self.purposeLayer=0
|
||||
self.coordinates=""
|
||||
|
||||
class GdsPath:
|
||||
|
|
@ -31,7 +30,7 @@ class GdsPath:
|
|||
self.elementFlags=""
|
||||
self.plex=""
|
||||
self.drawingLayer=""
|
||||
self.purposeLayer = None
|
||||
self.purposeLayer=0
|
||||
self.pathType=""
|
||||
self.pathWidth=""
|
||||
self.coordinates=""
|
||||
|
|
@ -140,7 +139,7 @@ class GdsText:
|
|||
self.elementFlags=""
|
||||
self.plex=""
|
||||
self.drawingLayer=""
|
||||
self.purposeLayer = None
|
||||
self.purposeLayer=0
|
||||
self.transFlags=[0,0,0]
|
||||
self.magFactor=""
|
||||
self.rotateAngle=""
|
||||
|
|
@ -165,6 +164,6 @@ class GdsBox:
|
|||
self.elementFlags=""
|
||||
self.plex=""
|
||||
self.drawingLayer=""
|
||||
self.purposeLayer = None
|
||||
self.purposeLayer=0
|
||||
self.boxValue=""
|
||||
self.coordinates=""
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ from .gdsPrimitives import *
|
|||
from datetime import *
|
||||
#from mpmath import matrix
|
||||
#from numpy import matrix
|
||||
from vector import vector
|
||||
import numpy as np
|
||||
#import gdsPrimitives
|
||||
import debug
|
||||
|
|
@ -358,7 +357,7 @@ class VlsiLayout:
|
|||
#add the sref to the root structure
|
||||
self.structures[self.rootStructureName].srefs.append(layoutToAddSref)
|
||||
|
||||
def addBox(self,layerNumber=0, purposeNumber=None, offsetInMicrons=(0,0), width=1.0, height=1.0,center=False):
|
||||
def addBox(self,layerNumber=0, purposeNumber=0, offsetInMicrons=(0,0), width=1.0, height=1.0,center=False):
|
||||
"""
|
||||
Method to add a box to a layout
|
||||
"""
|
||||
|
|
@ -383,13 +382,12 @@ class VlsiLayout:
|
|||
|
||||
boundaryToAdd = GdsBoundary()
|
||||
boundaryToAdd.drawingLayer = layerNumber
|
||||
boundaryToAdd.dataType = 0
|
||||
boundaryToAdd.coordinates = coordinates
|
||||
boundaryToAdd.purposeLayer = purposeNumber
|
||||
#add the sref to the root structure
|
||||
self.structures[self.rootStructureName].boundaries.append(boundaryToAdd)
|
||||
|
||||
def addPath(self, layerNumber=0, purposeNumber=None, coordinates=[(0,0)], width=1.0):
|
||||
def addPath(self, layerNumber=0, purposeNumber=0, coordinates=[(0,0)], width=1.0):
|
||||
"""
|
||||
Method to add a path to a layout
|
||||
"""
|
||||
|
|
@ -408,12 +406,10 @@ class VlsiLayout:
|
|||
#add the sref to the root structure
|
||||
self.structures[self.rootStructureName].paths.append(pathToAdd)
|
||||
|
||||
def addText(self, text, layerNumber=0, purposeNumber=None, offsetInMicrons=(0,0), magnification=0.1, rotate = None):
|
||||
def addText(self, text, layerNumber=0, offsetInMicrons=(0,0), magnification=0.1, rotate = None):
|
||||
offsetInLayoutUnits = (self.userUnits(offsetInMicrons[0]),self.userUnits(offsetInMicrons[1]))
|
||||
textToAdd = GdsText()
|
||||
textToAdd.drawingLayer = layerNumber
|
||||
textToAdd.purposeLayer = purposeNumber
|
||||
textToAdd.dataType = 0
|
||||
textToAdd.coordinates = [offsetInLayoutUnits]
|
||||
textToAdd.transFlags = [0,0,0]
|
||||
textToAdd.textString = self.padText(text)
|
||||
|
|
@ -757,7 +753,7 @@ class VlsiLayout:
|
|||
for boundary in shapes:
|
||||
vectors = []
|
||||
for i in range(0, len(boundary), 2):
|
||||
vectors.append(vector(boundary[i], boundary[i+1]))
|
||||
vectors.append((boundary[i], boundary[i+1]))
|
||||
blockages.append(vectors)
|
||||
|
||||
return blockages
|
||||
|
|
|
|||
|
|
@ -168,8 +168,6 @@ def init_openram(config_file, is_unit_test=True):
|
|||
from sram_factory import factory
|
||||
factory.reset()
|
||||
|
||||
setup_bitcell()
|
||||
|
||||
global OPTS
|
||||
global CHECKPOINT_OPTS
|
||||
|
||||
|
|
@ -398,7 +396,8 @@ def setup_paths():
|
|||
full_path = "{0}/{1}".format(OPENRAM_HOME, subdir)
|
||||
debug.check(os.path.isdir(full_path),
|
||||
"$OPENRAM_HOME/{0} does not exist: {1}".format(subdir, full_path))
|
||||
sys.path.append("{0}".format(full_path))
|
||||
if "__pycache__" not in full_path:
|
||||
sys.path.append("{0}".format(full_path))
|
||||
|
||||
if not OPTS.openram_temp.endswith('/'):
|
||||
OPTS.openram_temp += "/"
|
||||
|
|
@ -449,14 +448,24 @@ def init_paths():
|
|||
|
||||
def set_default_corner():
|
||||
""" Set the default corner. """
|
||||
|
||||
|
||||
import tech
|
||||
# Set some default options now based on the technology...
|
||||
if (OPTS.process_corners == ""):
|
||||
OPTS.process_corners = tech.spice["fet_models"].keys()
|
||||
if OPTS.nominal_corner_only:
|
||||
OPTS.process_corners = ["TT"]
|
||||
else:
|
||||
OPTS.process_corners = tech.spice["fet_models"].keys()
|
||||
if (OPTS.supply_voltages == ""):
|
||||
OPTS.supply_voltages = tech.spice["supply_voltages"]
|
||||
if OPTS.nominal_corner_only:
|
||||
OPTS.supply_voltages = [tech.spice["supply_voltages"][1]]
|
||||
else:
|
||||
OPTS.supply_voltages = tech.spice["supply_voltages"]
|
||||
if (OPTS.temperatures == ""):
|
||||
OPTS.temperatures = tech.spice["temperatures"]
|
||||
if OPTS.nominal_corner_only:
|
||||
OPTS.temperatures = [tech.spice["temperatures"][1]]
|
||||
else:
|
||||
OPTS.temperatures = tech.spice["temperatures"]
|
||||
|
||||
|
||||
def import_tech():
|
||||
|
|
@ -483,7 +492,7 @@ def import_tech():
|
|||
try:
|
||||
tech_mod = __import__(OPTS.tech_name)
|
||||
except ImportError:
|
||||
debug.error("Nonexistent technology_setup_file: {0}.py".format(filename), -1)
|
||||
debug.error("Nonexistent technology module: {0}".format(OPTS.tech_name), -1)
|
||||
|
||||
OPTS.openram_tech = os.path.dirname(tech_mod.__file__) + "/"
|
||||
|
||||
|
|
@ -572,5 +581,5 @@ def report_status():
|
|||
debug.print_raw("Performing simulation-based characterization with {}".format(OPTS.spice_name))
|
||||
if OPTS.trim_netlist:
|
||||
debug.print_raw("Trimming netlist to speed up characterization (trim_netlist=False to disable).")
|
||||
|
||||
|
||||
if OPTS.nominal_corner_only:
|
||||
debug.print_raw("Only characterizing nominal corner.")
|
||||
|
|
|
|||
|
|
@ -31,8 +31,12 @@ if len(args) != 1:
|
|||
# These depend on arguments, so don't load them until now.
|
||||
import debug
|
||||
|
||||
# Parse config file and set up all the options
|
||||
g.init_openram(config_file=args[0], is_unit_test=False)
|
||||
|
||||
# Ensure that the right bitcell exists or use the parameterised one
|
||||
g.setup_bitcell()
|
||||
|
||||
# Only print banner here so it's not in unit tests
|
||||
g.print_banner()
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ class options(optparse.Values):
|
|||
write_size = None
|
||||
|
||||
# These will get initialized by the user or the tech file
|
||||
nominal_corner_only = False
|
||||
supply_voltages = ""
|
||||
temperatures = ""
|
||||
process_corners = ""
|
||||
|
|
@ -110,8 +111,7 @@ class options(optparse.Values):
|
|||
|
||||
# Should we print out the banner at startup
|
||||
print_banner = True
|
||||
# Use detailed LEF blockages
|
||||
detailed_blockages = True
|
||||
|
||||
# Define the output file paths
|
||||
output_path = "."
|
||||
# Define the output file base name
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
import contact
|
||||
import design
|
||||
import debug
|
||||
from tech import drc
|
||||
from tech import layer, drc
|
||||
from vector import vector
|
||||
from globals import OPTS
|
||||
from sram_factory import factory
|
||||
|
|
@ -141,27 +141,29 @@ class pgate(design.design):
|
|||
max_y_offset = self.height + 0.5 * self.m1_width
|
||||
self.nwell_position = middle_position
|
||||
nwell_height = max_y_offset - middle_position.y
|
||||
if drc("has_nwell"):
|
||||
if layer["nwell"]:
|
||||
self.add_rect(layer="nwell",
|
||||
offset=middle_position,
|
||||
width=self.well_width,
|
||||
height=nwell_height)
|
||||
self.add_rect(layer="vtg",
|
||||
offset=self.nwell_position,
|
||||
width=self.well_width,
|
||||
height=nwell_height)
|
||||
if layer["vtg"]:
|
||||
self.add_rect(layer="vtg",
|
||||
offset=self.nwell_position,
|
||||
width=self.well_width,
|
||||
height=nwell_height)
|
||||
|
||||
pwell_position = vector(0, -0.5 * self.m1_width)
|
||||
pwell_height = middle_position.y - pwell_position.y
|
||||
if drc("has_pwell"):
|
||||
if layer["pwell"]:
|
||||
self.add_rect(layer="pwell",
|
||||
offset=pwell_position,
|
||||
width=self.well_width,
|
||||
height=pwell_height)
|
||||
self.add_rect(layer="vtg",
|
||||
offset=pwell_position,
|
||||
width=self.well_width,
|
||||
height=pwell_height)
|
||||
if layer["vtg"]:
|
||||
self.add_rect(layer="vtg",
|
||||
offset=pwell_position,
|
||||
width=self.well_width,
|
||||
height=pwell_height)
|
||||
|
||||
def add_nwell_contact(self, pmos, pmos_pos):
|
||||
""" Add an nwell contact next to the given pmos device. """
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
#
|
||||
import design
|
||||
import debug
|
||||
from tech import drc, spice
|
||||
from tech import layer, drc, spice
|
||||
from vector import vector
|
||||
from sram_factory import factory
|
||||
|
||||
|
|
@ -58,7 +58,14 @@ class ptx(design.design):
|
|||
# We must always create ptx layout for pbitcell
|
||||
# some transistor sizes in other netlist depend on pbitcell
|
||||
self.create_layout()
|
||||
|
||||
|
||||
#ll = self.find_lowest_coords()
|
||||
#ur = self.find_highest_coords()
|
||||
#self.add_boundary(ll, ur)
|
||||
|
||||
# (0,0) will be the corner ofthe active area (not the larger well)
|
||||
self.translate_all(self.active_offset)
|
||||
|
||||
def create_layout(self):
|
||||
"""Calls all functions related to the generation of the layout"""
|
||||
self.setup_layout_constants()
|
||||
|
|
@ -66,7 +73,6 @@ class ptx(design.design):
|
|||
self.add_well_implant()
|
||||
self.add_poly()
|
||||
self.add_active_contacts()
|
||||
self.translate_all(self.active_offset)
|
||||
|
||||
# for run-time, we won't check every transitor DRC independently
|
||||
# but this may be uncommented for debug purposes
|
||||
|
|
@ -124,18 +130,18 @@ class ptx(design.design):
|
|||
|
||||
|
||||
# The contacted poly pitch (or uncontacted in an odd technology)
|
||||
self.poly_pitch = max(2 * self.contact_to_gate + self.contact_width + self.poly_width,
|
||||
self.poly_pitch = max(2 * self.active_contact_to_gate + self.contact_width + self.poly_width,
|
||||
self.poly_space)
|
||||
|
||||
# The contacted poly pitch (or uncontacted in an odd technology)
|
||||
self.contact_pitch = 2 * self.contact_to_gate + self.contact_width + self.poly_width
|
||||
self.contact_pitch = 2 * self.active_contact_to_gate + self.contact_width + self.poly_width
|
||||
|
||||
# The enclosure of an active contact. Not sure about second term.
|
||||
active_enclose_contact = max(drc("active_enclosure_contact"),
|
||||
active_enclose_contact = max(drc("active_enclosure_active_contact"),
|
||||
(self.active_width - self.contact_width) / 2)
|
||||
|
||||
# This is the distance from the edge of poly to the contacted end of active
|
||||
self.end_to_poly = active_enclose_contact + self.contact_width + self.contact_to_gate
|
||||
self.end_to_poly = active_enclose_contact + self.contact_width + self.active_contact_to_gate
|
||||
|
||||
|
||||
# Active width is determined by enclosure on both ends and contacted pitch,
|
||||
|
|
@ -152,7 +158,8 @@ class ptx(design.design):
|
|||
self.active_offset = vector([self.well_enclose_active] * 2)
|
||||
|
||||
# Well enclosure of active, ensure minwidth as well
|
||||
if drc("has_{}well".format(self.well_type)):
|
||||
well_name = "{}well".format(self.well_type)
|
||||
if layer[well_name]:
|
||||
self.cell_well_width = max(self.active_width + 2 * self.well_enclose_active,
|
||||
self.well_width)
|
||||
self.cell_well_height = max(self.tx_width + 2 * self.well_enclose_active,
|
||||
|
|
@ -318,11 +325,13 @@ class ptx(design.design):
|
|||
"""
|
||||
Add an (optional) well and implant for the type of transistor.
|
||||
"""
|
||||
if drc("has_{}well".format(self.well_type)):
|
||||
self.add_rect(layer="{}well".format(self.well_type),
|
||||
well_name = "{}well".format(self.well_type)
|
||||
if layer[well_name]:
|
||||
self.add_rect(layer=well_name,
|
||||
offset=(0,0),
|
||||
width=self.cell_well_width,
|
||||
height=self.cell_well_height)
|
||||
if layer["vtg"]:
|
||||
self.add_rect(layer="vtg",
|
||||
offset=(0,0),
|
||||
width=self.cell_well_width,
|
||||
|
|
|
|||
|
|
@ -42,6 +42,11 @@ def setup_files():
|
|||
files = os.listdir(gds_dir)
|
||||
nametest = re.compile("\.gds$", re.IGNORECASE)
|
||||
gds_files = list(filter(nametest.search, files))
|
||||
import tech
|
||||
if tech.blackbox_bitcell:
|
||||
# Ignore DRC of all bitcells
|
||||
nametest = re.compile("cell", re.IGNORECASE)
|
||||
gds_files = list(filter(lambda v: not nametest.search(v), gds_files))
|
||||
return (gds_dir, gds_files)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ class wire_test(openram_test):
|
|||
|
||||
min_space = 2 * (tech.drc["minwidth_poly"] +
|
||||
tech.drc["minwidth_metal1"])
|
||||
layer_stack = ("metal1", "contact", "poly")
|
||||
layer_stack = ("poly", "contact", "metal1")
|
||||
old_position_list = [[0, 0],
|
||||
[0, 3 * min_space],
|
||||
[1 * min_space, 3 * min_space],
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
#!/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_bitcell_array_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 = 0
|
||||
OPTS.num_w_ports = 0
|
||||
|
||||
factory.reset()
|
||||
debug.info(2, "Testing 4x4 array for bitcell")
|
||||
a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, left_rbl=1, right_rbl=0, bitcell_ports=[0])
|
||||
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())
|
||||
|
|
@ -20,6 +20,7 @@ class lib_model_corners_lib_test(openram_test):
|
|||
def runTest(self):
|
||||
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||
globals.init_openram(config_file)
|
||||
OPTS.nominal_corner_only = False
|
||||
OPTS.netlist_only = True
|
||||
|
||||
from characterizer import lib
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ class lib_sram_model_test(openram_test):
|
|||
def runTest(self):
|
||||
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||
globals.init_openram(config_file)
|
||||
OPTS.nominal_corner_only = False
|
||||
OPTS.netlist_only = True
|
||||
|
||||
from characterizer import lib
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ class lib_sram_prune_test(openram_test):
|
|||
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||
globals.init_openram(config_file)
|
||||
OPTS.analytical_delay = False
|
||||
OPTS.netlist_only = True
|
||||
OPTS.trim_netlist = True
|
||||
|
||||
# This is a hack to reload the characterizer __init__ with the spice version
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ class lib_test(openram_test):
|
|||
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||
globals.init_openram(config_file)
|
||||
OPTS.analytical_delay = False
|
||||
OPTS.netlist_only = True
|
||||
OPTS.trim_netlist = False
|
||||
|
||||
# This is a hack to reload the characterizer __init__ with the spice version
|
||||
|
|
|
|||
|
|
@ -11,20 +11,7 @@ num_words = 16
|
|||
|
||||
tech_name = OPTS.tech_name
|
||||
|
||||
process_corners = ["TT"]
|
||||
supply_voltages = [5.0]
|
||||
temperatures = [25]
|
||||
|
||||
nominal_corner_only = True
|
||||
route_supplies = True
|
||||
check_lvsdrc = True
|
||||
|
||||
if tech_name == "freepdk45":
|
||||
supply_voltages = [1.0]
|
||||
drc_name = "calibre"
|
||||
lvs_name = "calibre"
|
||||
pex_name = "calibre"
|
||||
else:
|
||||
drc_name = "magic"
|
||||
lvs_name = "netgen"
|
||||
pex_name = "magic"
|
||||
|
||||
|
|
|
|||
|
|
@ -10,22 +10,11 @@ word_size = 1
|
|||
num_words = 16
|
||||
|
||||
tech_name = OPTS.tech_name
|
||||
process_corners = ["TT"]
|
||||
supply_voltages = [5.0]
|
||||
temperatures = [25]
|
||||
|
||||
nominal_corner_only = True
|
||||
route_supplies = True
|
||||
check_lvsdrc = True
|
||||
inline_lvsdrc = True
|
||||
analytical_delay = False
|
||||
|
||||
if tech_name == "freepdk45":
|
||||
supply_voltages = [1.0]
|
||||
drc_name = "calibre"
|
||||
lvs_name = "calibre"
|
||||
pex_name = "calibre"
|
||||
else:
|
||||
drc_name = "magic"
|
||||
lvs_name = "netgen"
|
||||
pex_name = "magic"
|
||||
|
||||
|
|
|
|||
|
|
@ -10,18 +10,4 @@ word_size = 1
|
|||
num_words = 16
|
||||
|
||||
tech_name = OPTS.tech_name
|
||||
process_corners = ["TT"]
|
||||
supply_voltages = [5.0]
|
||||
temperatures = [25]
|
||||
|
||||
if tech_name == "freepdk45":
|
||||
supply_voltages = [1.0]
|
||||
drc_name = "calibre"
|
||||
lvs_name = "calibre"
|
||||
pex_name = "calibre"
|
||||
else:
|
||||
drc_name = "magic"
|
||||
lvs_name = "netgen"
|
||||
pex_name = "magic"
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
# 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.
|
||||
#
|
||||
word_size = 1
|
||||
num_words = 16
|
||||
|
||||
tech_name = "scn3me_subm"
|
||||
process_corners = ["TT"]
|
||||
supply_voltages = [5.0]
|
||||
temperatures = [25]
|
||||
|
||||
route_supplies = True
|
||||
check_lvsdrc = True
|
||||
|
||||
drc_name = "magic"
|
||||
lvs_name = "netgen"
|
||||
pex_name = "magic"
|
||||
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
# 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.
|
||||
#
|
||||
word_size = 1
|
||||
num_words = 16
|
||||
|
||||
tech_name = "scn3me_subm"
|
||||
process_corners = ["TT"]
|
||||
supply_voltages = [5.0]
|
||||
temperatures = [25]
|
||||
|
||||
route_supplies = True
|
||||
check_lvsdrc = True
|
||||
inline_lvsdrc = True
|
||||
analytical_delay = False
|
||||
|
||||
drc_name = "magic"
|
||||
lvs_name = "netgen"
|
||||
pex_name = "magic"
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
# 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.
|
||||
#
|
||||
word_size = 1
|
||||
num_words = 16
|
||||
|
||||
tech_name = "scn3me_subm"
|
||||
process_corners = ["TT"]
|
||||
supply_voltages = [5.0]
|
||||
temperatures = [25]
|
||||
|
||||
analytical_delay = False
|
||||
|
||||
drc_name = "magic"
|
||||
lvs_name = "netgen"
|
||||
pex_name = "magic"
|
||||
|
||||
|
|
@ -17,7 +17,12 @@ If not, OpenRAM will continue as if nothing happened!
|
|||
|
||||
import os
|
||||
import debug
|
||||
from globals import OPTS,find_exe,get_tool
|
||||
from globals import OPTS
|
||||
from globals import find_exe
|
||||
from globals import get_tool
|
||||
from tech import drc_name
|
||||
from tech import lvs_name
|
||||
from tech import pex_name
|
||||
import sys
|
||||
|
||||
debug.info(1,"Initializing verify...")
|
||||
|
|
@ -29,29 +34,29 @@ if not OPTS.check_lvsdrc:
|
|||
OPTS.pex_exe = None
|
||||
else:
|
||||
debug.info(1, "Finding DRC/LVS/PEX tools.")
|
||||
OPTS.drc_exe = get_tool("DRC", ["calibre","assura","magic"], OPTS.drc_name)
|
||||
OPTS.lvs_exe = get_tool("LVS", ["calibre","assura","netgen"], OPTS.lvs_name)
|
||||
OPTS.pex_exe = get_tool("PEX", ["calibre","magic"], OPTS.pex_name)
|
||||
OPTS.drc_exe = get_tool("DRC", ["calibre","assura","magic"], drc_name)
|
||||
OPTS.lvs_exe = get_tool("LVS", ["calibre","assura","netgen"], lvs_name)
|
||||
OPTS.pex_exe = get_tool("PEX", ["calibre","magic"], pex_name)
|
||||
|
||||
if OPTS.drc_exe == None:
|
||||
from .none import run_drc,print_drc_stats
|
||||
from .none import run_drc, print_drc_stats
|
||||
elif "calibre"==OPTS.drc_exe[0]:
|
||||
from .calibre import run_drc,print_drc_stats
|
||||
from .calibre import run_drc, print_drc_stats
|
||||
elif "assura"==OPTS.drc_exe[0]:
|
||||
from .assura import run_drc,print_drc_stats
|
||||
from .assura import run_drc, print_drc_stats
|
||||
elif "magic"==OPTS.drc_exe[0]:
|
||||
from .magic import run_drc,print_drc_stats
|
||||
from .magic import run_drc, print_drc_stats
|
||||
else:
|
||||
debug.warning("Did not find a supported DRC tool.")
|
||||
|
||||
if OPTS.lvs_exe == None:
|
||||
from .none import run_lvs,print_lvs_stats
|
||||
from .none import run_lvs, print_lvs_stats
|
||||
elif "calibre"==OPTS.lvs_exe[0]:
|
||||
from .calibre import run_lvs,print_lvs_stats
|
||||
from .calibre import run_lvs, print_lvs_stats
|
||||
elif "assura"==OPTS.lvs_exe[0]:
|
||||
from .assura import run_lvs,print_lvs_stats
|
||||
from .assura import run_lvs, print_lvs_stats
|
||||
elif "netgen"==OPTS.lvs_exe[0]:
|
||||
from .magic import run_lvs,print_lvs_stats
|
||||
from .magic import run_lvs, print_lvs_stats
|
||||
else:
|
||||
debug.warning("Did not find a supported LVS tool.")
|
||||
|
||||
|
|
|
|||
|
|
@ -44,8 +44,8 @@ layer["vtg"] = (6, 0)
|
|||
layer["vth"] = (7, 0)
|
||||
layer["thkox"] = (8, 0)
|
||||
layer["poly"] = (9, 0)
|
||||
layer["contact"] = (10, 0)
|
||||
layer["active_contact"] = (10, 0)
|
||||
layer["poly_contact"] = (10, 0)
|
||||
layer["metal1"] = (11, 0)
|
||||
layer["via1"] = (12, 0)
|
||||
layer["metal2"] = (13, 0)
|
||||
|
|
@ -89,10 +89,6 @@ drclvs_home=os.environ.get("DRCLVS_HOME")
|
|||
|
||||
drc = design_rules("freepdk45")
|
||||
|
||||
drc["body_tie_down"] = 0
|
||||
drc["has_pwell"] = True
|
||||
drc["has_nwell"] = True
|
||||
|
||||
#grid size
|
||||
drc["grid"] = 0.0025
|
||||
|
||||
|
|
@ -120,7 +116,7 @@ drc["poly_to_poly"] = 0.14
|
|||
# POLY.3 Minimum poly extension beyond active
|
||||
drc["poly_extend_active"] = 0.055
|
||||
# Not a rule
|
||||
drc["poly_to_polycontact"] = 0.075
|
||||
drc["poly_to_poly_contact"] = 0.075
|
||||
# POLY.4 Minimum enclosure of active around gate
|
||||
drc["active_enclosure_gate"] = 0.07
|
||||
# POLY.5 Minimum spacing of field poly to active
|
||||
|
|
@ -157,30 +153,45 @@ drc["implant_to_implant"] = 0.045
|
|||
drc["minwidth_implant"] = 0.045
|
||||
|
||||
# CONTACT.1 Minimum width of contact
|
||||
drc["minwidth_contact"] = 0.065
|
||||
drc["minwidth_active_contact"] = 0.065
|
||||
# CONTACT.2 Minimum spacing of contact
|
||||
drc["contact_to_contact"] = 0.075
|
||||
drc["active_contact_to_active_contact"] = 0.075
|
||||
# CONTACT.4 Minimum enclosure of active around contact
|
||||
drc["active_enclosure_contact"] = 0.005
|
||||
drc["active_enclosure_active_contact"] = 0.005
|
||||
# Reserved for asymmetric enclosures
|
||||
drc["active_extend_contact"] = 0.005
|
||||
# CONTACT.5 Minimum enclosure of poly around contact
|
||||
drc["poly_enclosure_contact"] = 0.005
|
||||
drc["active_extend_active_contact"] = 0.005
|
||||
# CONTACT.6 Minimum spacing of contact and gate
|
||||
drc["active_contact_to_gate"] = 0.0375 #changed from 0.035
|
||||
# CONTACT.7 Minimum spacing of contact and poly
|
||||
drc["active_contact_to_poly"] = 0.090
|
||||
|
||||
# CONTACT.1 Minimum width of contact
|
||||
drc["minwidth_poly_contact"] = 0.065
|
||||
# CONTACT.2 Minimum spacing of contact
|
||||
drc["poly_contact_to_poly_contact"] = 0.075
|
||||
# Reserved for asymmetric enclosures
|
||||
drc["poly_extend_contact"] = 0.005
|
||||
# CONTACT.5 Minimum enclosure of poly around contact
|
||||
drc["poly_enclosure_poly_contact"] = 0.005
|
||||
# Reserved for asymmetric enclosures
|
||||
drc["poly_extend_poly_contact"] = 0.005
|
||||
# CONTACT.6 Minimum spacing of contact and gate
|
||||
drc["contact_to_gate"] = 0.0375 #changed from 0.035
|
||||
drc["poly_contact_to_gate"] = 0.0375 #changed from 0.035
|
||||
# CONTACT.7 Minimum spacing of contact and poly
|
||||
drc["contact_to_poly"] = 0.090
|
||||
drc["poly_contact_to_poly"] = 0.090
|
||||
|
||||
# METAL1.1 Minimum width of metal1
|
||||
drc["minwidth_metal1"] = 0.065
|
||||
# METAL1.2 Minimum spacing of metal1
|
||||
drc["metal1_to_metal1"] = 0.065
|
||||
# METAL1.3 Minimum enclosure around contact on two opposite sides
|
||||
drc["metal1_enclosure_contact"] = 0
|
||||
drc["metal1_enclosure_active_contact"] = 0
|
||||
# Reserved for asymmetric enclosures
|
||||
drc["metal1_extend_contact"] = 0.035
|
||||
drc["metal1_extend_active_contact"] = 0.035
|
||||
# METAL1.3 Minimum enclosure around contact on two opposite sides
|
||||
drc["metal1_enclosure_poly_contact"] = 0
|
||||
# Reserved for asymmetric enclosures
|
||||
drc["metal1_extend_poly_contact"] = 0.035
|
||||
# METAL1.4 inimum enclosure around via1 on two opposite sides
|
||||
drc["metal1_extend_via1"] = 0.035
|
||||
# Reserved for asymmetric enclosures
|
||||
|
|
@ -339,3 +350,16 @@ parameter["bitcell_drain_cap"] = 0.1 #In Femto-Farad, approximation of dr
|
|||
##END Spice Simulation Parameters
|
||||
###################################################
|
||||
|
||||
###################################################
|
||||
##BEGIN Technology Tool Preferences
|
||||
###################################################
|
||||
|
||||
drc_name = "calibre"
|
||||
lvs_name = "calibre"
|
||||
pex_name = "calibre"
|
||||
|
||||
blackbox_bitcell = False
|
||||
|
||||
###################################################
|
||||
##END Technology Tool Preferences
|
||||
###################################################
|
||||
|
|
|
|||
|
|
@ -35,9 +35,5 @@ except:
|
|||
DRCLVS_HOME=OPENRAM_TECH+"/scn3me_subm/tech"
|
||||
os.environ["DRCLVS_HOME"] = DRCLVS_HOME
|
||||
|
||||
# try:
|
||||
# SPICE_MODEL_DIR = os.path.abspath(os.environ.get("SPICE_MODEL_DIR"))
|
||||
# except:
|
||||
OPENRAM_TECH=os.path.abspath(os.environ.get("OPENRAM_TECH"))
|
||||
os.environ["SPICE_MODEL_DIR"] = "{0}/{1}/models".format(OPENRAM_TECH, TECHNOLOGY)
|
||||
os.environ["SPICE_MODEL_DIR"] = "{0}/models".format(os.path.dirname(__file__))
|
||||
|
||||
|
|
|
|||
|
|
@ -277,3 +277,15 @@ parameter["bitcell_drain_cap"] = 0.2 #In Femto-Farad, approximation of dr
|
|||
###################################################
|
||||
##END Spice Simulation Parameters
|
||||
###################################################
|
||||
|
||||
###################################################
|
||||
##BEGIN Technology Tool Preferences
|
||||
###################################################
|
||||
|
||||
drc_name = "magic"
|
||||
lvs_name = "netgen"
|
||||
pex_name = "magic"
|
||||
|
||||
###################################################
|
||||
##END Technology Tool Preferences
|
||||
###################################################
|
||||
|
|
|
|||
|
|
@ -35,9 +35,5 @@ except:
|
|||
DRCLVS_HOME=OPENRAM_TECH+"/scn4m_subm/tech"
|
||||
os.environ["DRCLVS_HOME"] = DRCLVS_HOME
|
||||
|
||||
# try:
|
||||
# SPICE_MODEL_DIR = os.path.abspath(os.environ.get("SPICE_MODEL_DIR"))
|
||||
# except:
|
||||
OPENRAM_TECH=os.path.abspath(os.environ.get("OPENRAM_TECH"))
|
||||
os.environ["SPICE_MODEL_DIR"] = "{0}/{1}/models".format(OPENRAM_TECH, TECHNOLOGY)
|
||||
os.environ["SPICE_MODEL_DIR"] = "{0}/models".format(os.path.dirname(__file__))
|
||||
|
||||
|
|
|
|||
|
|
@ -35,9 +35,8 @@ GDS["zoom"] = 0.5
|
|||
|
||||
# create the GDS layer map
|
||||
layer={}
|
||||
layer["vtg"] = (-1, 0)
|
||||
layer["vth"] = (-1, 0)
|
||||
layer["contact"] = (47, 0)
|
||||
layer["vtg"] = None
|
||||
layer["vth"] = None
|
||||
layer["pwell"] = (41, 0)
|
||||
layer["nwell"] = (42, 0)
|
||||
layer["active"] = (43, 0)
|
||||
|
|
@ -45,6 +44,7 @@ layer["pimplant"] = (44, 0)
|
|||
layer["nimplant"] = (45, 0)
|
||||
layer["poly"] = (46, 0)
|
||||
layer["active_contact"] = (48, 0)
|
||||
layer["poly_contact"] = (47, 0)
|
||||
layer["metal1"] = (49, 0)
|
||||
layer["via1"] = (50, 0)
|
||||
layer["metal2"] = (51, 0)
|
||||
|
|
@ -78,10 +78,6 @@ drclvs_home=os.environ.get("DRCLVS_HOME")
|
|||
|
||||
drc = design_rules("scn4me_sub")
|
||||
|
||||
drc["body_tie_down"] = 0
|
||||
drc["has_pwell"] = True
|
||||
drc["has_nwell"] = True
|
||||
|
||||
#grid size is 1/2 a lambda
|
||||
drc["grid"]=0.5*_lambda_
|
||||
|
||||
|
|
@ -108,7 +104,7 @@ drc["poly_to_poly"] = 3*_lambda_
|
|||
# 3.3 Minimum gate extension of active
|
||||
drc["poly_extend_active"] = 2*_lambda_
|
||||
# 5.5.b Minimum spacing between poly contact and other poly (alternative rules)
|
||||
drc["poly_to_polycontact"] = 4*_lambda_
|
||||
drc["poly_to_poly_contact"] = 4*_lambda_
|
||||
# ??
|
||||
drc["active_enclosure_gate"] = 0.0
|
||||
# 3.5 Minimum field poly to active
|
||||
|
|
@ -145,30 +141,43 @@ drc["implant_to_implant"] = 0
|
|||
drc["minwidth_implant"] = 0
|
||||
|
||||
# 6.1 Exact contact size
|
||||
drc["minwidth_contact"] = 2*_lambda_
|
||||
drc["minwidth_active_contact"] = 2*_lambda_
|
||||
# 5.3 Minimum contact spacing
|
||||
drc["contact_to_contact"] = 3*_lambda_
|
||||
drc["active_contact_to_active_contact"] = 3*_lambda_
|
||||
# 6.2.b Minimum active overlap
|
||||
drc["active_enclosure_contact"] = _lambda_
|
||||
drc["active_enclosure_active_contact"] = _lambda_
|
||||
# Reserved for asymmetric enclosure
|
||||
drc["active_extend_contact"] = _lambda_
|
||||
# 5.2.b Minimum poly overlap
|
||||
drc["poly_enclosure_contact"] = _lambda_
|
||||
# Reserved for asymmetric enclosures
|
||||
drc["poly_extend_contact"] = _lambda_
|
||||
drc["active_extend_active_contact"] = _lambda_
|
||||
# Reserved for other technologies
|
||||
drc["contact_to_gate"] = 2*_lambda_
|
||||
drc["active_contact_to_gate"] = 2*_lambda_
|
||||
# 5.4 Minimum spacing to gate of transistor
|
||||
drc["contact_to_poly"] = 2*_lambda_
|
||||
|
||||
drc["active_contact_to_poly"] = 2*_lambda_
|
||||
|
||||
# 6.1 Exact contact size
|
||||
drc["minwidth_poly_contact"] = 2*_lambda_
|
||||
# 5.3 Minimum contact spacing
|
||||
drc["poly_contact_to_poly_contact"] = 3*_lambda_
|
||||
# 5.2.b Minimum poly overlap
|
||||
drc["poly_enclosure_poly_contact"] = _lambda_
|
||||
# Reserved for asymmetric enclosures
|
||||
drc["poly_extend_poly_contact"] = _lambda_
|
||||
# Reserved for other technologies
|
||||
drc["poly_contact_to_gate"] = 2*_lambda_
|
||||
# 5.4 Minimum spacing to gate of transistor
|
||||
drc["poly_contact_to_poly"] = 2*_lambda_
|
||||
|
||||
# 7.1 Minimum width
|
||||
drc["minwidth_metal1"] = 3*_lambda_
|
||||
# 7.2 Minimum spacing
|
||||
drc["metal1_to_metal1"] = 3*_lambda_
|
||||
# 7.3 Minimum overlap of any contact
|
||||
drc["metal1_enclosure_contact"] = _lambda_
|
||||
drc["metal1_enclosure_active_contact"] = _lambda_
|
||||
# Reserved for asymmetric enclosure
|
||||
drc["metal1_extend_contact"] = _lambda_
|
||||
drc["metal1_extend_active_contact"] = _lambda_
|
||||
# 7.3 Minimum overlap of any contact
|
||||
drc["metal1_enclosure_poly_contact"] = _lambda_
|
||||
# Reserved for asymmetric enclosure
|
||||
drc["metal1_extend_poly_contact"] = _lambda_
|
||||
# 8.3 Minimum overlap by metal1
|
||||
drc["metal1_enclosure_via1"] = _lambda_
|
||||
# Reserve for asymmetric enclosures
|
||||
|
|
@ -304,3 +313,17 @@ parameter["bitcell_drain_cap"] = 0.2 #In Femto-Farad, approximation of dr
|
|||
###################################################
|
||||
##END Spice Simulation Parameters
|
||||
###################################################
|
||||
|
||||
###################################################
|
||||
##BEGIN Technology Tool Preferences
|
||||
###################################################
|
||||
|
||||
drc_name = "magic"
|
||||
lvs_name = "netgen"
|
||||
pex_name = "magic"
|
||||
|
||||
blackbox_bitcell = False
|
||||
|
||||
###################################################
|
||||
##END Technology Tool Preferences
|
||||
###################################################
|
||||
|
|
|
|||
Loading…
Reference in New Issue