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
|
To debug, you will need a layout viewer. I prefer to use Glade
|
||||||
on my Mac, but you can also use Calibre, Magic, etc.
|
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:
|
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.
|
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 view errors in [Glade](http://www.peardrop.co.uk/glade/) as well.
|
||||||
You can get it from: http://www.peardrop.co.uk/glade/
|
|
||||||
|
|
||||||
To remote display over X windows, you need to disable OpenGL acceleration or use vnc
|
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:
|
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
|
To load the errors, you simply do Verify->Import Calibre Errors select
|
||||||
the .results file from Calibre.
|
the .results file from Calibre.
|
||||||
|
|
||||||
3. Magic
|
4. Magic
|
||||||
|
|
||||||
Magic is only supported in SCMOS. You will need to install the MOSIS SCMOS rules
|
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
|
When running DRC or extraction, OpenRAM will load the GDS file, save
|
||||||
the .ext/.mag files, and export an extracted netlist (.spice).
|
the .ext/.mag files, and export an extracted netlist (.spice).
|
||||||
|
|
||||||
4. It is possible to use other viewers as well, such as:
|
5. It is possible to use other viewers as well, such as:
|
||||||
* LayoutEditor http://www.layouteditor.net/
|
* [LayoutEditor](http://www.layouteditor.net/)
|
||||||
|
|
||||||
|
|
||||||
# Example to output/input .gds layout files from/to Cadence
|
# 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
|
# 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
|
## Dependencies
|
||||||
|
|
||||||
The OpenRAM compiler has very few 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].
|
If you are using [SCMOS], you should install [Magic] and [Netgen].
|
||||||
We have included the most recent SCN4M_SUBM design rules from [Qflow].
|
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
|
# Basic Usage
|
||||||
|
|
||||||
Once you have defined the environment, you can run OpenRAM from the command line
|
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
|
# Technology to use in $OPENRAM_TECH
|
||||||
tech_name = "scn4m_subm"
|
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 to characterize
|
||||||
process_corners = ["TT"]
|
# process_corners = ["SS", "TT", "FF"]
|
||||||
# Voltage corners to characterize
|
# Voltage corners to characterize
|
||||||
supply_voltages = [ 3.3 ]
|
# supply_voltages = [ 3.0, 3.3, 3.5 ]
|
||||||
# Temperature corners to characterize
|
# Temperature corners to characterize
|
||||||
temperatures = [ 25 ]
|
# temperatures = [ 0, 25 100]
|
||||||
|
|
||||||
# Output directory for the results
|
# Output directory for the results
|
||||||
output_path = "temp"
|
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!)
|
# Disable analytical models for full characterization (WARNING: slow!)
|
||||||
# analytical_delay = False
|
# 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:
|
You can then run OpenRAM by executing:
|
||||||
|
|
|
||||||
|
|
@ -71,15 +71,15 @@ class contact(hierarchy_design.hierarchy_design):
|
||||||
|
|
||||||
(first_layer, via_layer, second_layer) = self.layer_stack
|
(first_layer, via_layer, second_layer) = self.layer_stack
|
||||||
self.first_layer_name = first_layer
|
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
|
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):
|
def setup_layout_constants(self):
|
||||||
""" Determine the design rules for the enclosure layers """
|
""" 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]):
|
for i in range(self.dimensions[1]):
|
||||||
offset = self.via_layer_position + vector(0, self.contact_pitch * i)
|
offset = self.via_layer_position + vector(0, self.contact_pitch * i)
|
||||||
for j in range(self.dimensions[0]):
|
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,
|
offset=offset,
|
||||||
width=self.contact_width,
|
width=self.contact_width,
|
||||||
height=self.contact_width)
|
height=self.contact_width)
|
||||||
|
|
|
||||||
|
|
@ -48,12 +48,12 @@ class design(hierarchy_design):
|
||||||
self.m4_space = drc("metal4_to_metal4")
|
self.m4_space = drc("metal4_to_metal4")
|
||||||
self.active_width = drc("minwidth_active")
|
self.active_width = drc("minwidth_active")
|
||||||
self.active_space = drc("active_to_body_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_to_active = drc("poly_to_active")
|
||||||
self.poly_extend_active = drc("poly_extend_active")
|
self.poly_extend_active = drc("poly_extend_active")
|
||||||
self.poly_to_polycontact = drc("poly_to_polycontact")
|
self.poly_to_poly_contact = drc("poly_to_poly_contact")
|
||||||
self.contact_to_gate = drc("contact_to_gate")
|
self.active_contact_to_gate = drc("active_contact_to_gate")
|
||||||
self.well_enclose_active = drc("well_enclosure_active")
|
self.well_enclose_active = drc("well_enclosure_active")
|
||||||
self.implant_enclose_active = drc("implant_enclosure_active")
|
self.implant_enclose_active = drc("implant_enclosure_active")
|
||||||
self.implant_space = drc("implant_to_implant")
|
self.implant_space = drc("implant_to_implant")
|
||||||
|
|
|
||||||
|
|
@ -327,7 +327,6 @@ class label(geometry):
|
||||||
debug.info(4, "writing label (" + str(self.layerNumber) + "): " + self.text)
|
debug.info(4, "writing label (" + str(self.layerNumber) + "): " + self.text)
|
||||||
new_layout.addText(text=self.text,
|
new_layout.addText(text=self.text,
|
||||||
layerNumber=self.layerNumber,
|
layerNumber=self.layerNumber,
|
||||||
purposeNumber=self.layerPurpose,
|
|
||||||
offsetInMicrons=self.offset,
|
offsetInMicrons=self.offset,
|
||||||
magnification=self.zoom,
|
magnification=self.zoom,
|
||||||
rotate=None)
|
rotate=None)
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ class layout():
|
||||||
self.name = name
|
self.name = name
|
||||||
self.width = None
|
self.width = None
|
||||||
self.height = None
|
self.height = None
|
||||||
|
self.boundary = None
|
||||||
self.insts = [] # Holds module/cell layout instances
|
self.insts = [] # Holds module/cell layout instances
|
||||||
self.objs = [] # Holds all other objects (labels, geometries, etc)
|
self.objs = [] # Holds all other objects (labels, geometries, etc)
|
||||||
self.pin_map = {} # Holds name->pin_layout map for all pins
|
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)
|
lowesty2 = min(inst.by() for inst in self.insts)
|
||||||
else:
|
else:
|
||||||
lowestx2=lowesty2=None
|
lowestx2=lowesty2=None
|
||||||
if lowestx1==None:
|
|
||||||
|
if lowestx1==None and lowestx2==None:
|
||||||
|
return None
|
||||||
|
elif lowestx1==None:
|
||||||
return vector(lowestx2,lowesty2)
|
return vector(lowestx2,lowesty2)
|
||||||
elif lowestx2==None:
|
elif lowestx2==None:
|
||||||
return vector(lowestx1,lowesty1)
|
return vector(lowestx1,lowesty1)
|
||||||
|
|
@ -101,7 +105,9 @@ class layout():
|
||||||
highesty2 = max(inst.uy() for inst in self.insts)
|
highesty2 = max(inst.uy() for inst in self.insts)
|
||||||
else:
|
else:
|
||||||
highestx2=highesty2=None
|
highestx2=highesty2=None
|
||||||
if highestx1==None:
|
if highestx1==None and highestx2==None:
|
||||||
|
return None
|
||||||
|
elif highestx1==None:
|
||||||
return vector(highestx2,highesty2)
|
return vector(highestx2,highesty2)
|
||||||
elif highestx2==None:
|
elif highestx2==None:
|
||||||
return vector(highestx1,highesty1)
|
return vector(highestx1,highesty1)
|
||||||
|
|
@ -500,6 +506,27 @@ class layout():
|
||||||
for pin_name in self.pin_map.keys():
|
for pin_name in self.pin_map.keys():
|
||||||
for pin in self.pin_map[pin_name]:
|
for pin in self.pin_map[pin_name]:
|
||||||
pin.gds_write_file(gds_layout)
|
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)
|
self.visited.append(self.name)
|
||||||
|
|
||||||
def gds_write(self, gds_name):
|
def gds_write(self, gds_name):
|
||||||
|
|
@ -937,12 +964,22 @@ class layout():
|
||||||
"""
|
"""
|
||||||
self.create_channel_route(netlist, offset, layer_stack, vertical=False)
|
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 """
|
""" Add boundary for debugging dimensions """
|
||||||
self.add_rect(layer="boundary",
|
if "stdc" in techlayer.keys():
|
||||||
offset=offset,
|
boundary_layer = "stdc"
|
||||||
|
else:
|
||||||
|
boundary_layer = "boundary"
|
||||||
|
if ur == None:
|
||||||
|
self.boundary = self.add_rect(layer=boundary_layer,
|
||||||
|
offset=ll,
|
||||||
height=self.height,
|
height=self.height,
|
||||||
width=self.width)
|
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"):
|
def add_enclosure(self, insts, layer="nwell"):
|
||||||
""" Add a layer that surrounds the given instances. Useful
|
""" 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 it is required to be a lpp
|
||||||
else:
|
else:
|
||||||
for (layer_name, lpp) in layer.items():
|
for (layer_name, lpp) in layer.items():
|
||||||
|
if not lpp:
|
||||||
|
continue
|
||||||
if self.same_lpp(layer_name_pp, lpp):
|
if self.same_lpp(layer_name_pp, lpp):
|
||||||
self.layer = layer_name
|
self.layer = layer_name
|
||||||
break
|
break
|
||||||
|
|
@ -342,7 +344,6 @@ class pin_layout:
|
||||||
# imported into Magic.
|
# imported into Magic.
|
||||||
newLayout.addText(text=self.name,
|
newLayout.addText(text=self.name,
|
||||||
layerNumber=layer_num,
|
layerNumber=layer_num,
|
||||||
purposeNumber=purpose,
|
|
||||||
offsetInMicrons=self.center(),
|
offsetInMicrons=self.center(),
|
||||||
magnification=GDS["zoom"],
|
magnification=GDS["zoom"],
|
||||||
rotate=None)
|
rotate=None)
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ class dummy_pbitcell(design.design):
|
||||||
|
|
||||||
self.create_netlist()
|
self.create_netlist()
|
||||||
self.create_layout()
|
self.create_layout()
|
||||||
|
self.add_boundary()
|
||||||
|
|
||||||
def create_netlist(self):
|
def create_netlist(self):
|
||||||
self.add_pins()
|
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_nmos.active_contact.height - self.inverter_nmos.active_height)
|
||||||
self.inverter_gap = max(self.poly_to_active,
|
self.inverter_gap = max(self.poly_to_active,
|
||||||
self.m1_space + inverter_nmos_contact_extension) \
|
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.m1_space + inverter_pmos_contact_extension
|
||||||
self.cross_couple_lower_ypos = self.inverter_nmos_ypos \
|
self.cross_couple_lower_ypos = self.inverter_nmos_ypos \
|
||||||
+ self.inverter_nmos.active_height \
|
+ self.inverter_nmos.active_height \
|
||||||
|
|
@ -254,7 +254,7 @@ class pbitcell(bitcell_base.bitcell_base):
|
||||||
+ self.inverter_nmos.active_height \
|
+ self.inverter_nmos.active_height \
|
||||||
+ max(self.poly_to_active,
|
+ max(self.poly_to_active,
|
||||||
self.m1_space + inverter_nmos_contact_extension) \
|
self.m1_space + inverter_nmos_contact_extension) \
|
||||||
+ self.poly_to_polycontact \
|
+ self.poly_to_poly_contact \
|
||||||
+ 1.5 * contact.poly.width
|
+ 1.5 * contact.poly.width
|
||||||
|
|
||||||
# spacing between wordlines (and gnd)
|
# 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
|
# add poly to metal1 contacts for gates of the inverters
|
||||||
left_storage_contact = vector(self.inverter_nmos_left.get_pin("G").lc().x \
|
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.cross_couple_upper_ypos)
|
||||||
self.add_via_center(layers=("poly", "contact", "metal1"),
|
self.add_via_center(layers=("poly", "contact", "metal1"),
|
||||||
offset=left_storage_contact,
|
offset=left_storage_contact,
|
||||||
directions=("H", "H"))
|
directions=("H", "H"))
|
||||||
|
|
||||||
right_storage_contact = vector(self.inverter_nmos_right.get_pin("G").rc().x \
|
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.cross_couple_upper_ypos)
|
||||||
self.add_via_center(layers=("poly", "contact", "metal1"),
|
self.add_via_center(layers=("poly", "contact", "metal1"),
|
||||||
offset=right_storage_contact,
|
offset=right_storage_contact,
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ class replica_pbitcell(design.design):
|
||||||
|
|
||||||
self.create_netlist()
|
self.create_netlist()
|
||||||
self.create_layout()
|
self.create_layout()
|
||||||
|
self.add_boundary()
|
||||||
|
|
||||||
def create_netlist(self):
|
def create_netlist(self):
|
||||||
self.add_pins()
|
self.add_pins()
|
||||||
|
|
|
||||||
|
|
@ -66,12 +66,34 @@ class lib:
|
||||||
self.supply_voltages = OPTS.supply_voltages
|
self.supply_voltages = OPTS.supply_voltages
|
||||||
self.process_corners = OPTS.process_corners
|
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.corners = []
|
||||||
self.lib_files = []
|
self.lib_files = []
|
||||||
for proc in self.process_corners:
|
|
||||||
for temp in self.temperatures:
|
# Nominal corner
|
||||||
for volt in self.supply_voltages:
|
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,
|
self.corner_name = "{0}_{1}_{2}V_{3}C".format(self.sram.name,
|
||||||
proc,
|
proc,
|
||||||
volt,
|
volt,
|
||||||
|
|
@ -83,8 +105,10 @@ class lib:
|
||||||
self.corners.append((proc, volt, temp))
|
self.corners.append((proc, volt, temp))
|
||||||
self.lib_files.append(lib_name)
|
self.lib_files.append(lib_name)
|
||||||
|
|
||||||
|
|
||||||
def characterize_corners(self):
|
def characterize_corners(self):
|
||||||
""" Characterize the list of corners. """
|
""" 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):
|
for (self.corner,lib_name) in zip(self.corners,self.lib_files):
|
||||||
debug.info(1,"Corner: " + str(self.corner))
|
debug.info(1,"Corner: " + str(self.corner))
|
||||||
(self.process, self.voltage, self.temperature) = self.corner
|
(self.process, self.voltage, self.temperature) = self.corner
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ word_size = 32
|
||||||
num_words = 128
|
num_words = 128
|
||||||
|
|
||||||
tech_name = "scn4m_subm"
|
tech_name = "scn4m_subm"
|
||||||
|
nominal_corners_only = False
|
||||||
process_corners = ["TT"]
|
process_corners = ["TT"]
|
||||||
supply_voltages = [5.0]
|
supply_voltages = [5.0]
|
||||||
temperatures = [25]
|
temperatures = [25]
|
||||||
|
|
@ -9,6 +10,3 @@ temperatures = [25]
|
||||||
output_path = "temp"
|
output_path = "temp"
|
||||||
output_name = "sram_{0}_{1}_{2}".format(word_size, num_words, tech_name)
|
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
|
num_w_ports = 0
|
||||||
|
|
||||||
tech_name = "scn4m_subm"
|
tech_name = "scn4m_subm"
|
||||||
|
nominal_corners_only = False
|
||||||
process_corners = ["TT"]
|
process_corners = ["TT"]
|
||||||
supply_voltages = [5.0]
|
supply_voltages = [5.0]
|
||||||
temperatures = [25]
|
temperatures = [25]
|
||||||
|
|
@ -17,7 +18,3 @@ output_path = "temp"
|
||||||
output_name = "sram_1rw_1r_{0}_{1}_{2}".format(word_size,
|
output_name = "sram_1rw_1r_{0}_{1}_{2}".format(word_size,
|
||||||
num_words,
|
num_words,
|
||||||
tech_name)
|
tech_name)
|
||||||
|
|
||||||
drc_name = "magic"
|
|
||||||
lvs_name = "netgen"
|
|
||||||
pex_name = "magic"
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ num_r_ports = 1
|
||||||
num_w_ports = 0
|
num_w_ports = 0
|
||||||
|
|
||||||
tech_name = "scn4m_subm"
|
tech_name = "scn4m_subm"
|
||||||
|
nominal_corners_only = False
|
||||||
process_corners = ["TT"]
|
process_corners = ["TT"]
|
||||||
supply_voltages = [5.0]
|
supply_voltages = [5.0]
|
||||||
temperatures = [25]
|
temperatures = [25]
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ word_size = 2
|
||||||
num_words = 16
|
num_words = 16
|
||||||
|
|
||||||
tech_name = "freepdk45"
|
tech_name = "freepdk45"
|
||||||
|
nominal_corners_only = False
|
||||||
process_corners = ["TT"]
|
process_corners = ["TT"]
|
||||||
supply_voltages = [1.0]
|
supply_voltages = [1.0]
|
||||||
temperatures = [25]
|
temperatures = [25]
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ word_size = 2
|
||||||
num_words = 16
|
num_words = 16
|
||||||
|
|
||||||
tech_name = "scn4m_subm"
|
tech_name = "scn4m_subm"
|
||||||
|
nominal_corners_only = False
|
||||||
process_corners = ["TT"]
|
process_corners = ["TT"]
|
||||||
supply_voltages = [5.0]
|
supply_voltages = [5.0]
|
||||||
temperatures = [25]
|
temperatures = [25]
|
||||||
|
|
@ -14,6 +15,3 @@ output_name = "sram_{0}_{1}_{2}".format(word_size,
|
||||||
num_words,
|
num_words,
|
||||||
tech_name)
|
tech_name)
|
||||||
|
|
||||||
drc_name = "magic"
|
|
||||||
lvs_name = "netgen"
|
|
||||||
pex_name = "magic"
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ word_size = 64
|
||||||
num_words = 1024
|
num_words = 1024
|
||||||
|
|
||||||
tech_name = "scn4m_subm"
|
tech_name = "scn4m_subm"
|
||||||
|
nominal_corners_only = False
|
||||||
process_corners = ["TT"]
|
process_corners = ["TT"]
|
||||||
supply_voltages = [ 5.0 ]
|
supply_voltages = [ 5.0 ]
|
||||||
temperatures = [ 25 ]
|
temperatures = [ 25 ]
|
||||||
|
|
@ -10,7 +11,3 @@ output_path = "temp"
|
||||||
output_name = "sram_{0}_{1}_{2}".format(word_size,
|
output_name = "sram_{0}_{1}_{2}".format(word_size,
|
||||||
num_words,
|
num_words,
|
||||||
tech_name)
|
tech_name)
|
||||||
|
|
||||||
drc_name = "magic"
|
|
||||||
lvs_name = "netgen"
|
|
||||||
pex_name = "magic"
|
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,9 @@ word_size = 16
|
||||||
num_words = 256
|
num_words = 256
|
||||||
|
|
||||||
tech_name = "scn4m_subm"
|
tech_name = "scn4m_subm"
|
||||||
|
nominal_corners_only = False
|
||||||
process_corners = ["TT"]
|
process_corners = ["TT"]
|
||||||
supply_voltages = [3.3]
|
supply_voltages = [5.0]
|
||||||
temperatures = [25]
|
temperatures = [25]
|
||||||
|
|
||||||
output_path = "temp"
|
output_path = "temp"
|
||||||
|
|
@ -11,6 +12,3 @@ output_name = "sram_{0}_{1}_{2}".format(word_size,
|
||||||
num_words,
|
num_words,
|
||||||
tech_name)
|
tech_name)
|
||||||
|
|
||||||
drc_name = "magic"
|
|
||||||
lvs_name = "netgen"
|
|
||||||
pex_name = "magic"
|
|
||||||
|
|
|
||||||
|
|
@ -164,7 +164,7 @@ class Gds2reader:
|
||||||
print("Mask: "+mask)
|
print("Mask: "+mask)
|
||||||
elif(idBits==b'\x03\x05'): #this is also wrong b/c python doesn't natively have an 8 byte float
|
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])
|
userUnits=self.ieeeDoubleFromIbmData(record[2:10])
|
||||||
dbUnits=self.ieeeDoubleFromIbmData
|
dbUnits=self.ieeeDoubleFromIbmData(record[10:18])
|
||||||
self.layoutObject.info["units"] = (userUnits,dbUnits)
|
self.layoutObject.info["units"] = (userUnits,dbUnits)
|
||||||
if(self.debugToTerminal==1):
|
if(self.debugToTerminal==1):
|
||||||
print("Units: 1 user unit="+str(userUnits)+" database units, 1 database unit="+str(dbUnits)+" meters.")
|
print("Units: 1 user unit="+str(userUnits)+" database units, 1 database unit="+str(dbUnits)+" meters.")
|
||||||
|
|
@ -175,6 +175,8 @@ class Gds2reader:
|
||||||
|
|
||||||
def readBoundary(self):
|
def readBoundary(self):
|
||||||
##reads in a boundary type structure = a filled polygon
|
##reads in a boundary type structure = a filled polygon
|
||||||
|
if(self.debugToTerminal==1):
|
||||||
|
print("\t\t\tBeginBoundary")
|
||||||
thisBoundary=GdsBoundary()
|
thisBoundary=GdsBoundary()
|
||||||
while 1:
|
while 1:
|
||||||
record = self.readNextRecord()
|
record = self.readNextRecord()
|
||||||
|
|
@ -201,11 +203,6 @@ class Gds2reader:
|
||||||
thisBoundary.purposeLayer=purposeLayer
|
thisBoundary.purposeLayer=purposeLayer
|
||||||
if(self.debugToTerminal==1):
|
if(self.debugToTerminal==1):
|
||||||
print("\t\tPurpose Layer: "+str(purposeLayer))
|
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
|
elif(idBits==b'\x10\x03'): #XY Data Points
|
||||||
numDataPoints = len(record)-2 #packed as XY coordinates 4 bytes each
|
numDataPoints = len(record)-2 #packed as XY coordinates 4 bytes each
|
||||||
thisBoundary.coordinates=[]
|
thisBoundary.coordinates=[]
|
||||||
|
|
@ -216,10 +213,15 @@ class Gds2reader:
|
||||||
if(self.debugToTerminal==1):
|
if(self.debugToTerminal==1):
|
||||||
print("\t\t\tXY Point: "+str(x)+","+str(y))
|
print("\t\t\tXY Point: "+str(x)+","+str(y))
|
||||||
elif(idBits==b'\x11\x00'): #End Of Element
|
elif(idBits==b'\x11\x00'): #End Of Element
|
||||||
|
if(self.debugToTerminal==1):
|
||||||
|
print("\t\t\tEndBoundary")
|
||||||
break;
|
break;
|
||||||
return thisBoundary
|
return thisBoundary
|
||||||
|
|
||||||
def readPath(self): #reads in a path structure
|
def readPath(self): #reads in a path structure
|
||||||
|
if(self.debugToTerminal==1):
|
||||||
|
print("\t\t\tBeginPath")
|
||||||
|
|
||||||
thisPath=GdsPath()
|
thisPath=GdsPath()
|
||||||
while 1:
|
while 1:
|
||||||
record = self.readNextRecord()
|
record = self.readNextRecord()
|
||||||
|
|
@ -266,10 +268,15 @@ class Gds2reader:
|
||||||
if(self.debugToTerminal==1):
|
if(self.debugToTerminal==1):
|
||||||
print("\t\t\tXY Point: "+str(x)+","+str(y))
|
print("\t\t\tXY Point: "+str(x)+","+str(y))
|
||||||
elif(idBits==b'\x11\x00'): #End Of Element
|
elif(idBits==b'\x11\x00'): #End Of Element
|
||||||
|
if(self.debugToTerminal==1):
|
||||||
|
print("\t\t\tEndPath")
|
||||||
break;
|
break;
|
||||||
return thisPath
|
return thisPath
|
||||||
|
|
||||||
def readSref(self): #reads in a reference to another structure
|
def readSref(self): #reads in a reference to another structure
|
||||||
|
if(self.debugToTerminal==1):
|
||||||
|
print("\t\t\tBeginSref")
|
||||||
|
|
||||||
thisSref=GdsSref()
|
thisSref=GdsSref()
|
||||||
while 1:
|
while 1:
|
||||||
record = self.readNextRecord()
|
record = self.readNextRecord()
|
||||||
|
|
@ -317,10 +324,15 @@ class Gds2reader:
|
||||||
if(self.debugToTerminal==1):
|
if(self.debugToTerminal==1):
|
||||||
print("\t\t\tXY Point: "+str(x)+","+str(y))
|
print("\t\t\tXY Point: "+str(x)+","+str(y))
|
||||||
elif(idBits==b'\x11\x00'): #End Of Element
|
elif(idBits==b'\x11\x00'): #End Of Element
|
||||||
|
if(self.debugToTerminal==1):
|
||||||
|
print("\t\t\tEndSref")
|
||||||
break;
|
break;
|
||||||
return thisSref
|
return thisSref
|
||||||
|
|
||||||
def readAref(self): #an array of references
|
def readAref(self): #an array of references
|
||||||
|
if(self.debugToTerminal==1):
|
||||||
|
print("\t\t\tBeginAref")
|
||||||
|
|
||||||
thisAref = GdsAref()
|
thisAref = GdsAref()
|
||||||
while 1:
|
while 1:
|
||||||
record = self.readNextRecord()
|
record = self.readNextRecord()
|
||||||
|
|
@ -372,11 +384,15 @@ class Gds2reader:
|
||||||
print("\t\t\t\tArray Width: "+str(rightMostX-topLeftX))
|
print("\t\t\t\tArray Width: "+str(rightMostX-topLeftX))
|
||||||
print("\t\t\t\tArray Height: "+str(topLeftY-bottomMostY))
|
print("\t\t\t\tArray Height: "+str(topLeftY-bottomMostY))
|
||||||
elif(idBits==b'\x11\x00'): #End Of Element
|
elif(idBits==b'\x11\x00'): #End Of Element
|
||||||
|
if(self.debugToTerminal==1):
|
||||||
|
print("\t\t\tEndAref")
|
||||||
break;
|
break;
|
||||||
return thisAref
|
return thisAref
|
||||||
|
|
||||||
def readText(self):
|
def readText(self):
|
||||||
##reads in a text structure
|
if(self.debugToTerminal==1):
|
||||||
|
print("\t\t\tBeginText")
|
||||||
|
|
||||||
thisText=GdsText()
|
thisText=GdsText()
|
||||||
while 1:
|
while 1:
|
||||||
record = self.readNextRecord()
|
record = self.readNextRecord()
|
||||||
|
|
@ -472,10 +488,15 @@ class Gds2reader:
|
||||||
if(self.debugToTerminal==1):
|
if(self.debugToTerminal==1):
|
||||||
print("\t\t\tText String: "+textString)
|
print("\t\t\tText String: "+textString)
|
||||||
elif(idBits==b'\x11\x00'): #End Of Element
|
elif(idBits==b'\x11\x00'): #End Of Element
|
||||||
|
if(self.debugToTerminal==1):
|
||||||
|
print("\t\t\tEndText")
|
||||||
break;
|
break;
|
||||||
return thisText
|
return thisText
|
||||||
|
|
||||||
def readNode(self):
|
def readNode(self):
|
||||||
|
if(self.debugToTerminal==1):
|
||||||
|
print("\t\t\tBeginNode")
|
||||||
|
|
||||||
##reads in a node type structure = an electrical net
|
##reads in a node type structure = an electrical net
|
||||||
thisNode = GdsNode()
|
thisNode = GdsNode()
|
||||||
while 1:
|
while 1:
|
||||||
|
|
@ -513,10 +534,15 @@ class Gds2reader:
|
||||||
if(self.debugToTerminal==1):
|
if(self.debugToTerminal==1):
|
||||||
print("\t\t\tXY Point: "+str(x)+","+str(y))
|
print("\t\t\tXY Point: "+str(x)+","+str(y))
|
||||||
elif(idBits==b'\x11\x00'): #End Of Element
|
elif(idBits==b'\x11\x00'): #End Of Element
|
||||||
|
if(self.debugToTerminal==1):
|
||||||
|
print("\t\t\tEndNode")
|
||||||
break;
|
break;
|
||||||
return thisNode
|
return thisNode
|
||||||
|
|
||||||
def readBox(self):
|
def readBox(self):
|
||||||
|
if(self.debugToTerminal==1):
|
||||||
|
print("\t\t\tBeginBox")
|
||||||
|
|
||||||
##reads in a gds BOX structure
|
##reads in a gds BOX structure
|
||||||
thisBox = GdsBox()
|
thisBox = GdsBox()
|
||||||
while 1:
|
while 1:
|
||||||
|
|
@ -559,6 +585,8 @@ class Gds2reader:
|
||||||
if(self.debugToTerminal==1):
|
if(self.debugToTerminal==1):
|
||||||
print("\t\t\tXY Point: "+str(x)+","+str(y))
|
print("\t\t\tXY Point: "+str(x)+","+str(y))
|
||||||
elif(idBits==b'\x11\x00'): #End Of Element
|
elif(idBits==b'\x11\x00'): #End Of Element
|
||||||
|
if(self.debugToTerminal==1):
|
||||||
|
print("\t\t\tEndBox")
|
||||||
break;
|
break;
|
||||||
return thisBox
|
return thisBox
|
||||||
|
|
||||||
|
|
@ -566,6 +594,7 @@ class Gds2reader:
|
||||||
thisStructure = GdsStructure()
|
thisStructure = GdsStructure()
|
||||||
record = self.readNextRecord()
|
record = self.readNextRecord()
|
||||||
idBits = record[0:2]
|
idBits = record[0:2]
|
||||||
|
# Begin structure
|
||||||
if(idBits==b'\x05\x02' and len(record)==26):
|
if(idBits==b'\x05\x02' and len(record)==26):
|
||||||
createYear = struct.unpack(">h",record[2:4])[0]
|
createYear = struct.unpack(">h",record[2:4])[0]
|
||||||
createMonth = struct.unpack(">h",record[4:6])[0]
|
createMonth = struct.unpack(">h",record[4:6])[0]
|
||||||
|
|
@ -581,6 +610,10 @@ class Gds2reader:
|
||||||
modSecond = struct.unpack(">h",record[24:26])[0]
|
modSecond = struct.unpack(">h",record[24:26])[0]
|
||||||
thisStructure.createDate=(createYear,createMonth,createDay,createHour,createMinute,createSecond)
|
thisStructure.createDate=(createYear,createMonth,createDay,createHour,createMinute,createSecond)
|
||||||
thisStructure.modDate=(modYear,modMonth,modDay,modHour,modMinute,modSecond)
|
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:
|
else:
|
||||||
#means we have hit the last structure, so return the record
|
#means we have hit the last structure, so return the record
|
||||||
#to whoever called us to do something with it
|
#to whoever called us to do something with it
|
||||||
|
|
|
||||||
|
|
@ -195,16 +195,14 @@ class Gds2writer:
|
||||||
plex = struct.pack(">i",thisBoundary.plex)
|
plex = struct.pack(">i",thisBoundary.plex)
|
||||||
self.writeRecord(idBits+plex)
|
self.writeRecord(idBits+plex)
|
||||||
if(thisBoundary.drawingLayer!=""):
|
if(thisBoundary.drawingLayer!=""):
|
||||||
idBits=b'\x0D\x02' #drawig layer
|
idBits=b'\x0D\x02' # drawing layer
|
||||||
drawingLayer = struct.pack(">h",thisBoundary.drawingLayer)
|
drawingLayer = struct.pack(">h",thisBoundary.drawingLayer)
|
||||||
self.writeRecord(idBits+drawingLayer)
|
self.writeRecord(idBits+drawingLayer)
|
||||||
if(thisBoundary.purposeLayer):
|
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
|
idBits=b'\x0E\x02' # DataType
|
||||||
dataType = struct.pack(">h",thisBoundary.dataType)
|
if type(thisBoundary.purposeLayer)!=int:
|
||||||
|
import pdb; pdb.set_trace()
|
||||||
|
dataType = struct.pack(">h",thisBoundary.purposeLayer)
|
||||||
self.writeRecord(idBits+dataType)
|
self.writeRecord(idBits+dataType)
|
||||||
if(thisBoundary.coordinates!=""):
|
if(thisBoundary.coordinates!=""):
|
||||||
idBits=b'\x10\x03' # XY Data Points
|
idBits=b'\x10\x03' # XY Data Points
|
||||||
|
|
@ -377,9 +375,9 @@ class Gds2writer:
|
||||||
idBits=b'\x0D\x02' #drawing layer
|
idBits=b'\x0D\x02' #drawing layer
|
||||||
drawingLayer = struct.pack(">h",thisText.drawingLayer)
|
drawingLayer = struct.pack(">h",thisText.drawingLayer)
|
||||||
self.writeRecord(idBits+drawingLayer)
|
self.writeRecord(idBits+drawingLayer)
|
||||||
#if(thisText.purposeLayer):
|
# TextType is always a 0 per GDS specification
|
||||||
idBits=b'\x16\x02' #purpose layer
|
idBits=b'\x16\x02' #purpose layer
|
||||||
purposeLayer = struct.pack(">h",thisText.purposeLayer)
|
purposeLayer = struct.pack(">h",0)
|
||||||
self.writeRecord(idBits+purposeLayer)
|
self.writeRecord(idBits+purposeLayer)
|
||||||
if(thisText.transFlags != ""):
|
if(thisText.transFlags != ""):
|
||||||
idBits=b'\x1A\x01'
|
idBits=b'\x1A\x01'
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,7 @@ class GdsBoundary:
|
||||||
self.elementFlags=""
|
self.elementFlags=""
|
||||||
self.plex=""
|
self.plex=""
|
||||||
self.drawingLayer=""
|
self.drawingLayer=""
|
||||||
self.purposeLayer = None
|
self.purposeLayer=0
|
||||||
self.dataType=""
|
|
||||||
self.coordinates=""
|
self.coordinates=""
|
||||||
|
|
||||||
class GdsPath:
|
class GdsPath:
|
||||||
|
|
@ -31,7 +30,7 @@ class GdsPath:
|
||||||
self.elementFlags=""
|
self.elementFlags=""
|
||||||
self.plex=""
|
self.plex=""
|
||||||
self.drawingLayer=""
|
self.drawingLayer=""
|
||||||
self.purposeLayer = None
|
self.purposeLayer=0
|
||||||
self.pathType=""
|
self.pathType=""
|
||||||
self.pathWidth=""
|
self.pathWidth=""
|
||||||
self.coordinates=""
|
self.coordinates=""
|
||||||
|
|
@ -140,7 +139,7 @@ class GdsText:
|
||||||
self.elementFlags=""
|
self.elementFlags=""
|
||||||
self.plex=""
|
self.plex=""
|
||||||
self.drawingLayer=""
|
self.drawingLayer=""
|
||||||
self.purposeLayer = None
|
self.purposeLayer=0
|
||||||
self.transFlags=[0,0,0]
|
self.transFlags=[0,0,0]
|
||||||
self.magFactor=""
|
self.magFactor=""
|
||||||
self.rotateAngle=""
|
self.rotateAngle=""
|
||||||
|
|
@ -165,6 +164,6 @@ class GdsBox:
|
||||||
self.elementFlags=""
|
self.elementFlags=""
|
||||||
self.plex=""
|
self.plex=""
|
||||||
self.drawingLayer=""
|
self.drawingLayer=""
|
||||||
self.purposeLayer = None
|
self.purposeLayer=0
|
||||||
self.boxValue=""
|
self.boxValue=""
|
||||||
self.coordinates=""
|
self.coordinates=""
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ from .gdsPrimitives import *
|
||||||
from datetime import *
|
from datetime import *
|
||||||
#from mpmath import matrix
|
#from mpmath import matrix
|
||||||
#from numpy import matrix
|
#from numpy import matrix
|
||||||
from vector import vector
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
#import gdsPrimitives
|
#import gdsPrimitives
|
||||||
import debug
|
import debug
|
||||||
|
|
@ -358,7 +357,7 @@ class VlsiLayout:
|
||||||
#add the sref to the root structure
|
#add the sref to the root structure
|
||||||
self.structures[self.rootStructureName].srefs.append(layoutToAddSref)
|
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
|
Method to add a box to a layout
|
||||||
"""
|
"""
|
||||||
|
|
@ -383,13 +382,12 @@ class VlsiLayout:
|
||||||
|
|
||||||
boundaryToAdd = GdsBoundary()
|
boundaryToAdd = GdsBoundary()
|
||||||
boundaryToAdd.drawingLayer = layerNumber
|
boundaryToAdd.drawingLayer = layerNumber
|
||||||
boundaryToAdd.dataType = 0
|
|
||||||
boundaryToAdd.coordinates = coordinates
|
boundaryToAdd.coordinates = coordinates
|
||||||
boundaryToAdd.purposeLayer = purposeNumber
|
boundaryToAdd.purposeLayer = purposeNumber
|
||||||
#add the sref to the root structure
|
#add the sref to the root structure
|
||||||
self.structures[self.rootStructureName].boundaries.append(boundaryToAdd)
|
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
|
Method to add a path to a layout
|
||||||
"""
|
"""
|
||||||
|
|
@ -408,12 +406,10 @@ class VlsiLayout:
|
||||||
#add the sref to the root structure
|
#add the sref to the root structure
|
||||||
self.structures[self.rootStructureName].paths.append(pathToAdd)
|
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]))
|
offsetInLayoutUnits = (self.userUnits(offsetInMicrons[0]),self.userUnits(offsetInMicrons[1]))
|
||||||
textToAdd = GdsText()
|
textToAdd = GdsText()
|
||||||
textToAdd.drawingLayer = layerNumber
|
textToAdd.drawingLayer = layerNumber
|
||||||
textToAdd.purposeLayer = purposeNumber
|
|
||||||
textToAdd.dataType = 0
|
|
||||||
textToAdd.coordinates = [offsetInLayoutUnits]
|
textToAdd.coordinates = [offsetInLayoutUnits]
|
||||||
textToAdd.transFlags = [0,0,0]
|
textToAdd.transFlags = [0,0,0]
|
||||||
textToAdd.textString = self.padText(text)
|
textToAdd.textString = self.padText(text)
|
||||||
|
|
@ -757,7 +753,7 @@ class VlsiLayout:
|
||||||
for boundary in shapes:
|
for boundary in shapes:
|
||||||
vectors = []
|
vectors = []
|
||||||
for i in range(0, len(boundary), 2):
|
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)
|
blockages.append(vectors)
|
||||||
|
|
||||||
return blockages
|
return blockages
|
||||||
|
|
|
||||||
|
|
@ -168,8 +168,6 @@ def init_openram(config_file, is_unit_test=True):
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
factory.reset()
|
factory.reset()
|
||||||
|
|
||||||
setup_bitcell()
|
|
||||||
|
|
||||||
global OPTS
|
global OPTS
|
||||||
global CHECKPOINT_OPTS
|
global CHECKPOINT_OPTS
|
||||||
|
|
||||||
|
|
@ -398,6 +396,7 @@ def setup_paths():
|
||||||
full_path = "{0}/{1}".format(OPENRAM_HOME, subdir)
|
full_path = "{0}/{1}".format(OPENRAM_HOME, subdir)
|
||||||
debug.check(os.path.isdir(full_path),
|
debug.check(os.path.isdir(full_path),
|
||||||
"$OPENRAM_HOME/{0} does not exist: {1}".format(subdir, full_path))
|
"$OPENRAM_HOME/{0} does not exist: {1}".format(subdir, full_path))
|
||||||
|
if "__pycache__" not in full_path:
|
||||||
sys.path.append("{0}".format(full_path))
|
sys.path.append("{0}".format(full_path))
|
||||||
|
|
||||||
if not OPTS.openram_temp.endswith('/'):
|
if not OPTS.openram_temp.endswith('/'):
|
||||||
|
|
@ -450,12 +449,22 @@ def init_paths():
|
||||||
def set_default_corner():
|
def set_default_corner():
|
||||||
""" Set the default corner. """
|
""" Set the default corner. """
|
||||||
|
|
||||||
|
import tech
|
||||||
# Set some default options now based on the technology...
|
# Set some default options now based on the technology...
|
||||||
if (OPTS.process_corners == ""):
|
if (OPTS.process_corners == ""):
|
||||||
|
if OPTS.nominal_corner_only:
|
||||||
|
OPTS.process_corners = ["TT"]
|
||||||
|
else:
|
||||||
OPTS.process_corners = tech.spice["fet_models"].keys()
|
OPTS.process_corners = tech.spice["fet_models"].keys()
|
||||||
if (OPTS.supply_voltages == ""):
|
if (OPTS.supply_voltages == ""):
|
||||||
|
if OPTS.nominal_corner_only:
|
||||||
|
OPTS.supply_voltages = [tech.spice["supply_voltages"][1]]
|
||||||
|
else:
|
||||||
OPTS.supply_voltages = tech.spice["supply_voltages"]
|
OPTS.supply_voltages = tech.spice["supply_voltages"]
|
||||||
if (OPTS.temperatures == ""):
|
if (OPTS.temperatures == ""):
|
||||||
|
if OPTS.nominal_corner_only:
|
||||||
|
OPTS.temperatures = [tech.spice["temperatures"][1]]
|
||||||
|
else:
|
||||||
OPTS.temperatures = tech.spice["temperatures"]
|
OPTS.temperatures = tech.spice["temperatures"]
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -483,7 +492,7 @@ def import_tech():
|
||||||
try:
|
try:
|
||||||
tech_mod = __import__(OPTS.tech_name)
|
tech_mod = __import__(OPTS.tech_name)
|
||||||
except ImportError:
|
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__) + "/"
|
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))
|
debug.print_raw("Performing simulation-based characterization with {}".format(OPTS.spice_name))
|
||||||
if OPTS.trim_netlist:
|
if OPTS.trim_netlist:
|
||||||
debug.print_raw("Trimming netlist to speed up characterization (trim_netlist=False to disable).")
|
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.
|
# These depend on arguments, so don't load them until now.
|
||||||
import debug
|
import debug
|
||||||
|
|
||||||
|
# Parse config file and set up all the options
|
||||||
g.init_openram(config_file=args[0], is_unit_test=False)
|
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
|
# Only print banner here so it's not in unit tests
|
||||||
g.print_banner()
|
g.print_banner()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ class options(optparse.Values):
|
||||||
write_size = None
|
write_size = None
|
||||||
|
|
||||||
# These will get initialized by the user or the tech file
|
# These will get initialized by the user or the tech file
|
||||||
|
nominal_corner_only = False
|
||||||
supply_voltages = ""
|
supply_voltages = ""
|
||||||
temperatures = ""
|
temperatures = ""
|
||||||
process_corners = ""
|
process_corners = ""
|
||||||
|
|
@ -110,8 +111,7 @@ class options(optparse.Values):
|
||||||
|
|
||||||
# Should we print out the banner at startup
|
# Should we print out the banner at startup
|
||||||
print_banner = True
|
print_banner = True
|
||||||
# Use detailed LEF blockages
|
|
||||||
detailed_blockages = True
|
|
||||||
# Define the output file paths
|
# Define the output file paths
|
||||||
output_path = "."
|
output_path = "."
|
||||||
# Define the output file base name
|
# Define the output file base name
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
import contact
|
import contact
|
||||||
import design
|
import design
|
||||||
import debug
|
import debug
|
||||||
from tech import drc
|
from tech import layer, drc
|
||||||
from vector import vector
|
from vector import vector
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
|
|
@ -141,11 +141,12 @@ class pgate(design.design):
|
||||||
max_y_offset = self.height + 0.5 * self.m1_width
|
max_y_offset = self.height + 0.5 * self.m1_width
|
||||||
self.nwell_position = middle_position
|
self.nwell_position = middle_position
|
||||||
nwell_height = max_y_offset - middle_position.y
|
nwell_height = max_y_offset - middle_position.y
|
||||||
if drc("has_nwell"):
|
if layer["nwell"]:
|
||||||
self.add_rect(layer="nwell",
|
self.add_rect(layer="nwell",
|
||||||
offset=middle_position,
|
offset=middle_position,
|
||||||
width=self.well_width,
|
width=self.well_width,
|
||||||
height=nwell_height)
|
height=nwell_height)
|
||||||
|
if layer["vtg"]:
|
||||||
self.add_rect(layer="vtg",
|
self.add_rect(layer="vtg",
|
||||||
offset=self.nwell_position,
|
offset=self.nwell_position,
|
||||||
width=self.well_width,
|
width=self.well_width,
|
||||||
|
|
@ -153,11 +154,12 @@ class pgate(design.design):
|
||||||
|
|
||||||
pwell_position = vector(0, -0.5 * self.m1_width)
|
pwell_position = vector(0, -0.5 * self.m1_width)
|
||||||
pwell_height = middle_position.y - pwell_position.y
|
pwell_height = middle_position.y - pwell_position.y
|
||||||
if drc("has_pwell"):
|
if layer["pwell"]:
|
||||||
self.add_rect(layer="pwell",
|
self.add_rect(layer="pwell",
|
||||||
offset=pwell_position,
|
offset=pwell_position,
|
||||||
width=self.well_width,
|
width=self.well_width,
|
||||||
height=pwell_height)
|
height=pwell_height)
|
||||||
|
if layer["vtg"]:
|
||||||
self.add_rect(layer="vtg",
|
self.add_rect(layer="vtg",
|
||||||
offset=pwell_position,
|
offset=pwell_position,
|
||||||
width=self.well_width,
|
width=self.well_width,
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
#
|
#
|
||||||
import design
|
import design
|
||||||
import debug
|
import debug
|
||||||
from tech import drc, spice
|
from tech import layer, drc, spice
|
||||||
from vector import vector
|
from vector import vector
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
|
|
||||||
|
|
@ -59,6 +59,13 @@ class ptx(design.design):
|
||||||
# some transistor sizes in other netlist depend on pbitcell
|
# some transistor sizes in other netlist depend on pbitcell
|
||||||
self.create_layout()
|
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):
|
def create_layout(self):
|
||||||
"""Calls all functions related to the generation of the layout"""
|
"""Calls all functions related to the generation of the layout"""
|
||||||
self.setup_layout_constants()
|
self.setup_layout_constants()
|
||||||
|
|
@ -66,7 +73,6 @@ class ptx(design.design):
|
||||||
self.add_well_implant()
|
self.add_well_implant()
|
||||||
self.add_poly()
|
self.add_poly()
|
||||||
self.add_active_contacts()
|
self.add_active_contacts()
|
||||||
self.translate_all(self.active_offset)
|
|
||||||
|
|
||||||
# for run-time, we won't check every transitor DRC independently
|
# for run-time, we won't check every transitor DRC independently
|
||||||
# but this may be uncommented for debug purposes
|
# 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)
|
# 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)
|
self.poly_space)
|
||||||
|
|
||||||
# The contacted poly pitch (or uncontacted in an odd technology)
|
# 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.
|
# 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)
|
(self.active_width - self.contact_width) / 2)
|
||||||
|
|
||||||
# This is the distance from the edge of poly to the contacted end of active
|
# 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,
|
# 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)
|
self.active_offset = vector([self.well_enclose_active] * 2)
|
||||||
|
|
||||||
# Well enclosure of active, ensure minwidth as well
|
# 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.cell_well_width = max(self.active_width + 2 * self.well_enclose_active,
|
||||||
self.well_width)
|
self.well_width)
|
||||||
self.cell_well_height = max(self.tx_width + 2 * self.well_enclose_active,
|
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.
|
Add an (optional) well and implant for the type of transistor.
|
||||||
"""
|
"""
|
||||||
if drc("has_{}well".format(self.well_type)):
|
well_name = "{}well".format(self.well_type)
|
||||||
self.add_rect(layer="{}well".format(self.well_type),
|
if layer[well_name]:
|
||||||
|
self.add_rect(layer=well_name,
|
||||||
offset=(0,0),
|
offset=(0,0),
|
||||||
width=self.cell_well_width,
|
width=self.cell_well_width,
|
||||||
height=self.cell_well_height)
|
height=self.cell_well_height)
|
||||||
|
if layer["vtg"]:
|
||||||
self.add_rect(layer="vtg",
|
self.add_rect(layer="vtg",
|
||||||
offset=(0,0),
|
offset=(0,0),
|
||||||
width=self.cell_well_width,
|
width=self.cell_well_width,
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,11 @@ def setup_files():
|
||||||
files = os.listdir(gds_dir)
|
files = os.listdir(gds_dir)
|
||||||
nametest = re.compile("\.gds$", re.IGNORECASE)
|
nametest = re.compile("\.gds$", re.IGNORECASE)
|
||||||
gds_files = list(filter(nametest.search, files))
|
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)
|
return (gds_dir, gds_files)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ class wire_test(openram_test):
|
||||||
|
|
||||||
min_space = 2 * (tech.drc["minwidth_poly"] +
|
min_space = 2 * (tech.drc["minwidth_poly"] +
|
||||||
tech.drc["minwidth_metal1"])
|
tech.drc["minwidth_metal1"])
|
||||||
layer_stack = ("metal1", "contact", "poly")
|
layer_stack = ("poly", "contact", "metal1")
|
||||||
old_position_list = [[0, 0],
|
old_position_list = [[0, 0],
|
||||||
[0, 3 * min_space],
|
[0, 3 * min_space],
|
||||||
[1 * min_space, 3 * min_space],
|
[1 * min_space, 3 * min_space],
|
||||||
|
|
|
||||||
|
|
@ -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):
|
def runTest(self):
|
||||||
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
globals.init_openram(config_file)
|
globals.init_openram(config_file)
|
||||||
|
OPTS.nominal_corner_only = False
|
||||||
OPTS.netlist_only = True
|
OPTS.netlist_only = True
|
||||||
|
|
||||||
from characterizer import lib
|
from characterizer import lib
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ class lib_sram_model_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"))
|
||||||
globals.init_openram(config_file)
|
globals.init_openram(config_file)
|
||||||
|
OPTS.nominal_corner_only = False
|
||||||
OPTS.netlist_only = True
|
OPTS.netlist_only = True
|
||||||
|
|
||||||
from characterizer import lib
|
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"))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
globals.init_openram(config_file)
|
globals.init_openram(config_file)
|
||||||
OPTS.analytical_delay = False
|
OPTS.analytical_delay = False
|
||||||
|
OPTS.netlist_only = True
|
||||||
OPTS.trim_netlist = True
|
OPTS.trim_netlist = True
|
||||||
|
|
||||||
# This is a hack to reload the characterizer __init__ with the spice version
|
# 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"))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
globals.init_openram(config_file)
|
globals.init_openram(config_file)
|
||||||
OPTS.analytical_delay = False
|
OPTS.analytical_delay = False
|
||||||
|
OPTS.netlist_only = True
|
||||||
OPTS.trim_netlist = False
|
OPTS.trim_netlist = False
|
||||||
|
|
||||||
# This is a hack to reload the characterizer __init__ with the spice version
|
# 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
|
tech_name = OPTS.tech_name
|
||||||
|
|
||||||
process_corners = ["TT"]
|
nominal_corner_only = True
|
||||||
supply_voltages = [5.0]
|
|
||||||
temperatures = [25]
|
|
||||||
|
|
||||||
route_supplies = True
|
route_supplies = True
|
||||||
check_lvsdrc = 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
|
num_words = 16
|
||||||
|
|
||||||
tech_name = OPTS.tech_name
|
tech_name = OPTS.tech_name
|
||||||
process_corners = ["TT"]
|
|
||||||
supply_voltages = [5.0]
|
|
||||||
temperatures = [25]
|
|
||||||
|
|
||||||
|
nominal_corner_only = True
|
||||||
route_supplies = True
|
route_supplies = True
|
||||||
check_lvsdrc = True
|
check_lvsdrc = True
|
||||||
inline_lvsdrc = True
|
inline_lvsdrc = True
|
||||||
analytical_delay = False
|
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
|
num_words = 16
|
||||||
|
|
||||||
tech_name = OPTS.tech_name
|
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 os
|
||||||
import debug
|
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
|
import sys
|
||||||
|
|
||||||
debug.info(1,"Initializing verify...")
|
debug.info(1,"Initializing verify...")
|
||||||
|
|
@ -29,9 +34,9 @@ if not OPTS.check_lvsdrc:
|
||||||
OPTS.pex_exe = None
|
OPTS.pex_exe = None
|
||||||
else:
|
else:
|
||||||
debug.info(1, "Finding DRC/LVS/PEX tools.")
|
debug.info(1, "Finding DRC/LVS/PEX tools.")
|
||||||
OPTS.drc_exe = get_tool("DRC", ["calibre","assura","magic"], OPTS.drc_name)
|
OPTS.drc_exe = get_tool("DRC", ["calibre","assura","magic"], drc_name)
|
||||||
OPTS.lvs_exe = get_tool("LVS", ["calibre","assura","netgen"], OPTS.lvs_name)
|
OPTS.lvs_exe = get_tool("LVS", ["calibre","assura","netgen"], lvs_name)
|
||||||
OPTS.pex_exe = get_tool("PEX", ["calibre","magic"], OPTS.pex_name)
|
OPTS.pex_exe = get_tool("PEX", ["calibre","magic"], pex_name)
|
||||||
|
|
||||||
if OPTS.drc_exe == None:
|
if OPTS.drc_exe == None:
|
||||||
from .none import run_drc, print_drc_stats
|
from .none import run_drc, print_drc_stats
|
||||||
|
|
|
||||||
|
|
@ -44,8 +44,8 @@ layer["vtg"] = (6, 0)
|
||||||
layer["vth"] = (7, 0)
|
layer["vth"] = (7, 0)
|
||||||
layer["thkox"] = (8, 0)
|
layer["thkox"] = (8, 0)
|
||||||
layer["poly"] = (9, 0)
|
layer["poly"] = (9, 0)
|
||||||
layer["contact"] = (10, 0)
|
|
||||||
layer["active_contact"] = (10, 0)
|
layer["active_contact"] = (10, 0)
|
||||||
|
layer["poly_contact"] = (10, 0)
|
||||||
layer["metal1"] = (11, 0)
|
layer["metal1"] = (11, 0)
|
||||||
layer["via1"] = (12, 0)
|
layer["via1"] = (12, 0)
|
||||||
layer["metal2"] = (13, 0)
|
layer["metal2"] = (13, 0)
|
||||||
|
|
@ -89,10 +89,6 @@ drclvs_home=os.environ.get("DRCLVS_HOME")
|
||||||
|
|
||||||
drc = design_rules("freepdk45")
|
drc = design_rules("freepdk45")
|
||||||
|
|
||||||
drc["body_tie_down"] = 0
|
|
||||||
drc["has_pwell"] = True
|
|
||||||
drc["has_nwell"] = True
|
|
||||||
|
|
||||||
#grid size
|
#grid size
|
||||||
drc["grid"] = 0.0025
|
drc["grid"] = 0.0025
|
||||||
|
|
||||||
|
|
@ -120,7 +116,7 @@ drc["poly_to_poly"] = 0.14
|
||||||
# POLY.3 Minimum poly extension beyond active
|
# POLY.3 Minimum poly extension beyond active
|
||||||
drc["poly_extend_active"] = 0.055
|
drc["poly_extend_active"] = 0.055
|
||||||
# Not a rule
|
# Not a rule
|
||||||
drc["poly_to_polycontact"] = 0.075
|
drc["poly_to_poly_contact"] = 0.075
|
||||||
# POLY.4 Minimum enclosure of active around gate
|
# POLY.4 Minimum enclosure of active around gate
|
||||||
drc["active_enclosure_gate"] = 0.07
|
drc["active_enclosure_gate"] = 0.07
|
||||||
# POLY.5 Minimum spacing of field poly to active
|
# POLY.5 Minimum spacing of field poly to active
|
||||||
|
|
@ -157,30 +153,45 @@ drc["implant_to_implant"] = 0.045
|
||||||
drc["minwidth_implant"] = 0.045
|
drc["minwidth_implant"] = 0.045
|
||||||
|
|
||||||
# CONTACT.1 Minimum width of contact
|
# CONTACT.1 Minimum width of contact
|
||||||
drc["minwidth_contact"] = 0.065
|
drc["minwidth_active_contact"] = 0.065
|
||||||
# CONTACT.2 Minimum spacing of contact
|
# 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
|
# 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
|
# Reserved for asymmetric enclosures
|
||||||
drc["active_extend_contact"] = 0.005
|
drc["active_extend_active_contact"] = 0.005
|
||||||
# CONTACT.5 Minimum enclosure of poly around contact
|
# CONTACT.6 Minimum spacing of contact and gate
|
||||||
drc["poly_enclosure_contact"] = 0.005
|
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
|
# Reserved for asymmetric enclosures
|
||||||
drc["poly_extend_contact"] = 0.005
|
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
|
# 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
|
# 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
|
# METAL1.1 Minimum width of metal1
|
||||||
drc["minwidth_metal1"] = 0.065
|
drc["minwidth_metal1"] = 0.065
|
||||||
# METAL1.2 Minimum spacing of metal1
|
# METAL1.2 Minimum spacing of metal1
|
||||||
drc["metal1_to_metal1"] = 0.065
|
drc["metal1_to_metal1"] = 0.065
|
||||||
# METAL1.3 Minimum enclosure around contact on two opposite sides
|
# 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
|
# 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
|
# METAL1.4 inimum enclosure around via1 on two opposite sides
|
||||||
drc["metal1_extend_via1"] = 0.035
|
drc["metal1_extend_via1"] = 0.035
|
||||||
# Reserved for asymmetric enclosures
|
# Reserved for asymmetric enclosures
|
||||||
|
|
@ -339,3 +350,16 @@ parameter["bitcell_drain_cap"] = 0.1 #In Femto-Farad, approximation of dr
|
||||||
##END Spice Simulation Parameters
|
##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"
|
DRCLVS_HOME=OPENRAM_TECH+"/scn3me_subm/tech"
|
||||||
os.environ["DRCLVS_HOME"] = DRCLVS_HOME
|
os.environ["DRCLVS_HOME"] = DRCLVS_HOME
|
||||||
|
|
||||||
# try:
|
os.environ["SPICE_MODEL_DIR"] = "{0}/models".format(os.path.dirname(__file__))
|
||||||
# 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)
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -277,3 +277,15 @@ parameter["bitcell_drain_cap"] = 0.2 #In Femto-Farad, approximation of dr
|
||||||
###################################################
|
###################################################
|
||||||
##END Spice Simulation Parameters
|
##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"
|
DRCLVS_HOME=OPENRAM_TECH+"/scn4m_subm/tech"
|
||||||
os.environ["DRCLVS_HOME"] = DRCLVS_HOME
|
os.environ["DRCLVS_HOME"] = DRCLVS_HOME
|
||||||
|
|
||||||
# try:
|
os.environ["SPICE_MODEL_DIR"] = "{0}/models".format(os.path.dirname(__file__))
|
||||||
# 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)
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,9 +35,8 @@ GDS["zoom"] = 0.5
|
||||||
|
|
||||||
# create the GDS layer map
|
# create the GDS layer map
|
||||||
layer={}
|
layer={}
|
||||||
layer["vtg"] = (-1, 0)
|
layer["vtg"] = None
|
||||||
layer["vth"] = (-1, 0)
|
layer["vth"] = None
|
||||||
layer["contact"] = (47, 0)
|
|
||||||
layer["pwell"] = (41, 0)
|
layer["pwell"] = (41, 0)
|
||||||
layer["nwell"] = (42, 0)
|
layer["nwell"] = (42, 0)
|
||||||
layer["active"] = (43, 0)
|
layer["active"] = (43, 0)
|
||||||
|
|
@ -45,6 +44,7 @@ layer["pimplant"] = (44, 0)
|
||||||
layer["nimplant"] = (45, 0)
|
layer["nimplant"] = (45, 0)
|
||||||
layer["poly"] = (46, 0)
|
layer["poly"] = (46, 0)
|
||||||
layer["active_contact"] = (48, 0)
|
layer["active_contact"] = (48, 0)
|
||||||
|
layer["poly_contact"] = (47, 0)
|
||||||
layer["metal1"] = (49, 0)
|
layer["metal1"] = (49, 0)
|
||||||
layer["via1"] = (50, 0)
|
layer["via1"] = (50, 0)
|
||||||
layer["metal2"] = (51, 0)
|
layer["metal2"] = (51, 0)
|
||||||
|
|
@ -78,10 +78,6 @@ drclvs_home=os.environ.get("DRCLVS_HOME")
|
||||||
|
|
||||||
drc = design_rules("scn4me_sub")
|
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
|
#grid size is 1/2 a lambda
|
||||||
drc["grid"]=0.5*_lambda_
|
drc["grid"]=0.5*_lambda_
|
||||||
|
|
||||||
|
|
@ -108,7 +104,7 @@ drc["poly_to_poly"] = 3*_lambda_
|
||||||
# 3.3 Minimum gate extension of active
|
# 3.3 Minimum gate extension of active
|
||||||
drc["poly_extend_active"] = 2*_lambda_
|
drc["poly_extend_active"] = 2*_lambda_
|
||||||
# 5.5.b Minimum spacing between poly contact and other poly (alternative rules)
|
# 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
|
drc["active_enclosure_gate"] = 0.0
|
||||||
# 3.5 Minimum field poly to active
|
# 3.5 Minimum field poly to active
|
||||||
|
|
@ -145,30 +141,43 @@ drc["implant_to_implant"] = 0
|
||||||
drc["minwidth_implant"] = 0
|
drc["minwidth_implant"] = 0
|
||||||
|
|
||||||
# 6.1 Exact contact size
|
# 6.1 Exact contact size
|
||||||
drc["minwidth_contact"] = 2*_lambda_
|
drc["minwidth_active_contact"] = 2*_lambda_
|
||||||
# 5.3 Minimum contact spacing
|
# 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
|
# 6.2.b Minimum active overlap
|
||||||
drc["active_enclosure_contact"] = _lambda_
|
drc["active_enclosure_active_contact"] = _lambda_
|
||||||
# Reserved for asymmetric enclosure
|
# Reserved for asymmetric enclosure
|
||||||
drc["active_extend_contact"] = _lambda_
|
drc["active_extend_active_contact"] = _lambda_
|
||||||
# 5.2.b Minimum poly overlap
|
|
||||||
drc["poly_enclosure_contact"] = _lambda_
|
|
||||||
# Reserved for asymmetric enclosures
|
|
||||||
drc["poly_extend_contact"] = _lambda_
|
|
||||||
# Reserved for other technologies
|
# 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
|
# 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
|
# 7.1 Minimum width
|
||||||
drc["minwidth_metal1"] = 3*_lambda_
|
drc["minwidth_metal1"] = 3*_lambda_
|
||||||
# 7.2 Minimum spacing
|
# 7.2 Minimum spacing
|
||||||
drc["metal1_to_metal1"] = 3*_lambda_
|
drc["metal1_to_metal1"] = 3*_lambda_
|
||||||
# 7.3 Minimum overlap of any contact
|
# 7.3 Minimum overlap of any contact
|
||||||
drc["metal1_enclosure_contact"] = _lambda_
|
drc["metal1_enclosure_active_contact"] = _lambda_
|
||||||
# Reserved for asymmetric enclosure
|
# 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
|
# 8.3 Minimum overlap by metal1
|
||||||
drc["metal1_enclosure_via1"] = _lambda_
|
drc["metal1_enclosure_via1"] = _lambda_
|
||||||
# Reserve for asymmetric enclosures
|
# Reserve for asymmetric enclosures
|
||||||
|
|
@ -304,3 +313,17 @@ parameter["bitcell_drain_cap"] = 0.2 #In Femto-Farad, approximation of dr
|
||||||
###################################################
|
###################################################
|
||||||
##END Spice Simulation Parameters
|
##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