Merge remote-tracking branch 'private/dev' into dev

This commit is contained in:
Matt Guthaus 2019-12-07 15:15:43 -08:00
commit 978693eb2a
47 changed files with 431 additions and 315 deletions

View File

@ -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

View File

@ -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:

View File

@ -48,7 +48,7 @@ class contact(hierarchy_design.hierarchy_design):
# Module does not have pins, but has empty pin list. # Module does not have pins, but has empty pin list.
self.pins = [] self.pins = []
self.create_layout() self.create_layout()
def create_layout(self): def create_layout(self):
self.setup_layers() self.setup_layers()
@ -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)

View File

@ -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")

View File

@ -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)

View File

@ -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"
height=self.height, else:
width=self.width) 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"): 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

View File

@ -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)

View File

@ -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()

View File

@ -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,

View File

@ -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()
@ -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, "wl{}".format(port))
self.copy_layout_pin(self.prbc_inst, "vdd") self.copy_layout_pin(self.prbc_inst, "vdd")
self.copy_layout_pin(self.prbc_inst, "gnd") self.copy_layout_pin(self.prbc_inst, "gnd")

View File

@ -66,25 +66,49 @@ 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)
self.corner_name = "{0}_{1}_{2}V_{3}C".format(self.sram.name, if not OPTS.nominal_corner_only:
proc, # Temperature corners
volt, self.add_corner(nom_process, nom_supply, min_temperature)
temp) self.add_corner(nom_process, nom_supply, max_temperature)
self.corner_name = self.corner_name.replace(".","p") # Remove decimals # Supply corners
lib_name = self.out_dir+"{}.lib".format(self.corner_name) 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): 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

View File

@ -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"

View File

@ -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"

View File

@ -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]

View File

@ -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]

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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

View File

@ -187,27 +187,25 @@ class Gds2writer:
idBits=b'\x08\x00' #record Type idBits=b'\x08\x00' #record Type
self.writeRecord(idBits) self.writeRecord(idBits)
if(thisBoundary.elementFlags!=""): if(thisBoundary.elementFlags!=""):
idBits=b'\x26\x01' #ELFLAGS idBits=b'\x26\x01' # ELFLAGS
elementFlags = struct.pack(">h",thisBoundary.elementFlags) elementFlags = struct.pack(">h",thisBoundary.elementFlags)
self.writeRecord(idBits+elementFlags) self.writeRecord(idBits+elementFlags)
if(thisBoundary.plex!=""): if(thisBoundary.plex!=""):
idBits=b'\x2F\x03' #PLEX idBits=b'\x2F\x03' # PLEX
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 idBits=b'\x0E\x02' # DataType
purposeLayer = struct.pack(">h",thisBoundary.purposeLayer) if type(thisBoundary.purposeLayer)!=int:
self.writeRecord(idBits+purposeLayer) import pdb; pdb.set_trace()
if(thisBoundary.dataType!=""): dataType = struct.pack(">h",thisBoundary.purposeLayer)
idBits=b'\x0E\x02'#DataType
dataType = struct.pack(">h",thisBoundary.dataType)
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
coordinateRecord = idBits coordinateRecord = idBits
for coordinate in thisBoundary.coordinates: for coordinate in thisBoundary.coordinates:
x=struct.pack(">i",int(coordinate[0])) x=struct.pack(">i",int(coordinate[0]))
@ -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'

View File

@ -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=""

View File

@ -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

View File

@ -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,7 +396,8 @@ 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))
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('/'): if not OPTS.openram_temp.endswith('/'):
OPTS.openram_temp += "/" OPTS.openram_temp += "/"
@ -449,14 +448,24 @@ 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 == ""):
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 == ""): 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 == ""): 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(): def import_tech():
@ -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.")

View File

@ -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()

View File

@ -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

View File

@ -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,27 +141,29 @@ 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)
self.add_rect(layer="vtg", if layer["vtg"]:
offset=self.nwell_position, self.add_rect(layer="vtg",
width=self.well_width, offset=self.nwell_position,
height=nwell_height) width=self.well_width,
height=nwell_height)
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)
self.add_rect(layer="vtg", if layer["vtg"]:
offset=pwell_position, self.add_rect(layer="vtg",
width=self.well_width, offset=pwell_position,
height=pwell_height) width=self.well_width,
height=pwell_height)
def add_nwell_contact(self, pmos, pmos_pos): def add_nwell_contact(self, pmos, pmos_pos):
""" Add an nwell contact next to the given pmos device. """ """ Add an nwell contact next to the given pmos device. """

View File

@ -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
@ -58,7 +58,14 @@ class ptx(design.design):
# We must always create ptx layout for pbitcell # We must always create ptx layout for pbitcell
# 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,

View File

@ -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)

View File

@ -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
compiler/tests/04_pwrite_driver_test.py Normal file → Executable file
View File

View File

@ -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())

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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,29 +34,29 @@ 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
elif "calibre"==OPTS.drc_exe[0]: 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]: 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]: elif "magic"==OPTS.drc_exe[0]:
from .magic import run_drc,print_drc_stats from .magic import run_drc, print_drc_stats
else: else:
debug.warning("Did not find a supported DRC tool.") debug.warning("Did not find a supported DRC tool.")
if OPTS.lvs_exe == None: 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]: 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]: 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]: elif "netgen"==OPTS.lvs_exe[0]:
from .magic import run_lvs,print_lvs_stats from .magic import run_lvs, print_lvs_stats
else: else:
debug.warning("Did not find a supported LVS tool.") debug.warning("Did not find a supported LVS tool.")

View File

@ -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
###################################################

View File

@ -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)

View File

@ -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
###################################################

View File

@ -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)

View File

@ -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
###################################################