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
on my Mac, but you can also use Calibre, Magic, etc.
1. Calibre
1. Klayout
You can view the designs in [Klayout](https://www.klayout.de/) with the configuration
file provided in the tech directories. For example,
```
klayout temp.gds -l /home/vagrant/openram/technology/freepdk45/tf/FreePDK45.lyp
```
2. Calibre
Start the Calibre DESIGNrev viewer in the temp directory and load your GDS file:
```
@ -52,10 +60,9 @@ on my Mac, but you can also use Calibre, Magic, etc.
In the viewer ">" opens the layout down a level.
2. Glade
3. Glade
You can view errors in Glade as well. I like this because it is on my laptop.
You can get it from: http://www.peardrop.co.uk/glade/
You can view errors in [Glade](http://www.peardrop.co.uk/glade/) as well.
To remote display over X windows, you need to disable OpenGL acceleration or use vnc
or something. You can disable by adding this to your .bashrc in bash:
@ -82,16 +89,16 @@ ui().importCds("default",
To load the errors, you simply do Verify->Import Calibre Errors select
the .results file from Calibre.
3. Magic
4. Magic
Magic is only supported in SCMOS. You will need to install the MOSIS SCMOS rules
and Magic from: http://opencircuitdesign.com/
and [Magic](http://opencircuitdesign.com/)
When running DRC or extraction, OpenRAM will load the GDS file, save
the .ext/.mag files, and export an extracted netlist (.spice).
4. It is possible to use other viewers as well, such as:
* LayoutEditor http://www.layouteditor.net/
5. It is possible to use other viewers as well, such as:
* [LayoutEditor](http://www.layouteditor.net/)
# Example to output/input .gds layout files from/to Cadence

View File

@ -33,15 +33,6 @@ things that need to be fixed.
# Basic Setup
## Docker Image
We have a pre-configured Ubuntu [Docker](https://www.docker.com/) image
available that has all tools installed for the [SCMOS] process. It is
available at [docker hub](https://hub.docker.com/r/vlsida/openram-ubuntu).
Please see
[our README.md](https://github.com/VLSIDA/openram-docker-images/blob/master/README.md)
for information on how to use this docker image.
## Dependencies
The OpenRAM compiler has very few dependencies:
@ -88,6 +79,23 @@ You may get the entire [FreePDK45 PDK here][FreePDK45].
If you are using [SCMOS], you should install [Magic] and [Netgen].
We have included the most recent SCN4M_SUBM design rules from [Qflow].
## Docker Image
We have a pre-configured Ubuntu [Docker](https://www.docker.com/) image
available that has all tools installed for the [SCMOS] process. It is
available at [docker hub](https://hub.docker.com/r/vlsida/openram-ubuntu).
Please see
[our README.md](https://github.com/VLSIDA/openram-docker-images/blob/master/README.md)
for information on how to use this docker image.
## Vagrant Image
We have a pre-configured Ubuntu [Vagrant](https://www.vagrantup.com/) image
available that has all tools installed for the [SCMOS] process.
Please see
[our README.md](https://github.com/VLSIDA/openram-vagrant-image/blob/master/README.md)
for information on how to use this image.
# Basic Usage
Once you have defined the environment, you can run OpenRAM from the command line
@ -104,12 +112,16 @@ num_words = 16
# Technology to use in $OPENRAM_TECH
tech_name = "scn4m_subm"
# You can use the technology nominal corner only
nominal_corner_only = True
# Or you can specify particular corners
# Process corners to characterize
process_corners = ["TT"]
# process_corners = ["SS", "TT", "FF"]
# Voltage corners to characterize
supply_voltages = [ 3.3 ]
# supply_voltages = [ 3.0, 3.3, 3.5 ]
# Temperature corners to characterize
temperatures = [ 25 ]
# temperatures = [ 0, 25 100]
# Output directory for the results
output_path = "temp"
@ -119,11 +131,6 @@ output_name = "sram_{0}_{1}_{2}".format(word_size,num_words,tech_name)
# Disable analytical models for full characterization (WARNING: slow!)
# analytical_delay = False
# To force this to use magic and netgen for DRC/LVS/PEX
# Could be calibre for FreePDK45
drc_name = "magic"
lvs_name = "netgen"
pex_name = "magic"
```
You can then run OpenRAM by executing:

View File

@ -71,15 +71,15 @@ class contact(hierarchy_design.hierarchy_design):
(first_layer, via_layer, second_layer) = self.layer_stack
self.first_layer_name = first_layer
self.via_layer_name = via_layer
# Some technologies have a separate active
# contact from the poly contact
# We will use contact for DRC, but active_contact for output
if first_layer == "active" or second_layer == "active":
self.via_layer_name_expanded = "active_" + via_layer
else:
self.via_layer_name_expanded = via_layer
self.second_layer_name = second_layer
# Contacts will have unique per first layer
if via_layer == "contact":
if first_layer in ("active", "poly"):
self.via_layer_name = first_layer + "_" + via_layer
else:
self.via_layer_name = second_layer + "_" + via_layer
else:
self.via_layer_name = via_layer
def setup_layout_constants(self):
""" Determine the design rules for the enclosure layers """
@ -144,7 +144,7 @@ class contact(hierarchy_design.hierarchy_design):
for i in range(self.dimensions[1]):
offset = self.via_layer_position + vector(0, self.contact_pitch * i)
for j in range(self.dimensions[0]):
self.add_rect(layer=self.via_layer_name_expanded,
self.add_rect(layer=self.via_layer_name,
offset=offset,
width=self.contact_width,
height=self.contact_width)

View File

@ -48,12 +48,12 @@ class design(hierarchy_design):
self.m4_space = drc("metal4_to_metal4")
self.active_width = drc("minwidth_active")
self.active_space = drc("active_to_body_active")
self.contact_width = drc("minwidth_contact")
self.contact_width = drc("minwidth_active_contact")
self.poly_to_active = drc("poly_to_active")
self.poly_extend_active = drc("poly_extend_active")
self.poly_to_polycontact = drc("poly_to_polycontact")
self.contact_to_gate = drc("contact_to_gate")
self.poly_to_poly_contact = drc("poly_to_poly_contact")
self.active_contact_to_gate = drc("active_contact_to_gate")
self.well_enclose_active = drc("well_enclosure_active")
self.implant_enclose_active = drc("implant_enclosure_active")
self.implant_space = drc("implant_to_implant")

View File

@ -327,7 +327,6 @@ class label(geometry):
debug.info(4, "writing label (" + str(self.layerNumber) + "): " + self.text)
new_layout.addText(text=self.text,
layerNumber=self.layerNumber,
purposeNumber=self.layerPurpose,
offsetInMicrons=self.offset,
magnification=self.zoom,
rotate=None)

View File

@ -32,6 +32,7 @@ class layout():
self.name = name
self.width = None
self.height = None
self.boundary = None
self.insts = [] # Holds module/cell layout instances
self.objs = [] # Holds all other objects (labels, geometries, etc)
self.pin_map = {} # Holds name->pin_layout map for all pins
@ -80,7 +81,10 @@ class layout():
lowesty2 = min(inst.by() for inst in self.insts)
else:
lowestx2=lowesty2=None
if lowestx1==None:
if lowestx1==None and lowestx2==None:
return None
elif lowestx1==None:
return vector(lowestx2,lowesty2)
elif lowestx2==None:
return vector(lowestx1,lowesty1)
@ -101,7 +105,9 @@ class layout():
highesty2 = max(inst.uy() for inst in self.insts)
else:
highestx2=highesty2=None
if highestx1==None:
if highestx1==None and highestx2==None:
return None
elif highestx1==None:
return vector(highestx2,highesty2)
elif highestx2==None:
return vector(highestx1,highesty1)
@ -500,6 +506,27 @@ class layout():
for pin_name in self.pin_map.keys():
for pin in self.pin_map[pin_name]:
pin.gds_write_file(gds_layout)
# If it's not a premade cell
# and we didn't add our own boundary,
# we should add a boundary just for DRC in some technologies
if not self.is_library_cell and not self.boundary:
# If there is a boundary layer, and we didn't create one, add one.
if "stdc" in techlayer.keys():
boundary_layer = "stdc"
boundary = [self.find_lowest_coords(), self.find_highest_coords()]
height = boundary[1][1] - boundary[0][1]
width = boundary[1][0] - boundary[0][0]
(layer_number, layer_purpose) = techlayer[boundary_layer]
gds_layout.addBox(layerNumber=layer_number,
purposeNumber=layer_purpose,
offsetInMicrons=boundary[0],
width=width,
height=height,
center=False)
debug.info(2, "Adding {0} boundary {1}".format(self.name, boundary))
self.visited.append(self.name)
def gds_write(self, gds_name):
@ -937,12 +964,22 @@ class layout():
"""
self.create_channel_route(netlist, offset, layer_stack, vertical=False)
def add_boundary(self, offset=vector(0,0)):
def add_boundary(self, ll=vector(0,0), ur=None):
""" Add boundary for debugging dimensions """
self.add_rect(layer="boundary",
offset=offset,
height=self.height,
width=self.width)
if "stdc" in techlayer.keys():
boundary_layer = "stdc"
else:
boundary_layer = "boundary"
if ur == None:
self.boundary = self.add_rect(layer=boundary_layer,
offset=ll,
height=self.height,
width=self.width)
else:
self.boundary = self.add_rect(layer=boundary_layer,
offset=ll,
height=ur.y-ll.y,
width=ur.x-ll.x)
def add_enclosure(self, insts, layer="nwell"):
""" Add a layer that surrounds the given instances. Useful

View File

@ -37,6 +37,8 @@ class pin_layout:
# else it is required to be a lpp
else:
for (layer_name, lpp) in layer.items():
if not lpp:
continue
if self.same_lpp(layer_name_pp, lpp):
self.layer = layer_name
break
@ -342,7 +344,6 @@ class pin_layout:
# imported into Magic.
newLayout.addText(text=self.name,
layerNumber=layer_num,
purposeNumber=purpose,
offsetInMicrons=self.center(),
magnification=GDS["zoom"],
rotate=None)

View File

@ -30,6 +30,7 @@ class dummy_pbitcell(design.design):
self.create_netlist()
self.create_layout()
self.add_boundary()
def create_netlist(self):
self.add_pins()

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_gap = max(self.poly_to_active,
self.m1_space + inverter_nmos_contact_extension) \
+ self.poly_to_polycontact + 2 * contact.poly.width \
+ self.poly_to_poly_contact + 2 * contact.poly.width \
+ self.m1_space + inverter_pmos_contact_extension
self.cross_couple_lower_ypos = self.inverter_nmos_ypos \
+ self.inverter_nmos.active_height \
@ -254,7 +254,7 @@ class pbitcell(bitcell_base.bitcell_base):
+ self.inverter_nmos.active_height \
+ max(self.poly_to_active,
self.m1_space + inverter_nmos_contact_extension) \
+ self.poly_to_polycontact \
+ self.poly_to_poly_contact \
+ 1.5 * contact.poly.width
# spacing between wordlines (and gnd)
@ -926,14 +926,14 @@ class pbitcell(bitcell_base.bitcell_base):
"""
# add poly to metal1 contacts for gates of the inverters
left_storage_contact = vector(self.inverter_nmos_left.get_pin("G").lc().x \
- self.poly_to_polycontact - 0.5*contact.poly.width,
- self.poly_to_poly_contact - 0.5*contact.poly.width,
self.cross_couple_upper_ypos)
self.add_via_center(layers=("poly", "contact", "metal1"),
offset=left_storage_contact,
directions=("H", "H"))
right_storage_contact = vector(self.inverter_nmos_right.get_pin("G").rc().x \
+ self.poly_to_polycontact + 0.5*contact.poly.width,
+ self.poly_to_poly_contact + 0.5*contact.poly.width,
self.cross_couple_upper_ypos)
self.add_via_center(layers=("poly", "contact", "metal1"),
offset=right_storage_contact,

View File

@ -30,6 +30,7 @@ class replica_pbitcell(design.design):
self.create_netlist()
self.create_layout()
self.add_boundary()
def create_netlist(self):
self.add_pins()

View File

@ -66,25 +66,49 @@ class lib:
self.supply_voltages = OPTS.supply_voltages
self.process_corners = OPTS.process_corners
# Enumerate all possible corners
# Corner values
min_temperature = min(self.temperatures)
nom_temperature = tech.spice["nom_temperature"]
max_temperature = max(self.temperatures)
min_supply = min(self.supply_voltages)
nom_supply = tech.spice["nom_supply_voltage"]
max_supply = max(self.supply_voltages)
min_process = "FF"
nom_process = "TT"
max_process = "SS"
self.corners = []
self.lib_files = []
for proc in self.process_corners:
for temp in self.temperatures:
for volt in self.supply_voltages:
self.corner_name = "{0}_{1}_{2}V_{3}C".format(self.sram.name,
proc,
volt,
temp)
self.corner_name = self.corner_name.replace(".","p") # Remove decimals
lib_name = self.out_dir+"{}.lib".format(self.corner_name)
# A corner is a tuple of PVT
self.corners.append((proc, volt, temp))
self.lib_files.append(lib_name)
# Nominal corner
self.add_corner(nom_process, nom_supply, nom_temperature)
if not OPTS.nominal_corner_only:
# Temperature corners
self.add_corner(nom_process, nom_supply, min_temperature)
self.add_corner(nom_process, nom_supply, max_temperature)
# Supply corners
self.add_corner(nom_process, min_supply, nom_temperature)
self.add_corner(nom_process, max_supply, nom_temperature)
# Process corners
self.add_corner(min_process, nom_supply, nom_temperature)
self.add_corner(max_process, nom_supply, nom_temperature)
def add_corner(self, proc, volt, temp):
self.corner_name = "{0}_{1}_{2}V_{3}C".format(self.sram.name,
proc,
volt,
temp)
self.corner_name = self.corner_name.replace(".","p") # Remove decimals
lib_name = self.out_dir+"{}.lib".format(self.corner_name)
# A corner is a tuple of PVT
self.corners.append((proc, volt, temp))
self.lib_files.append(lib_name)
def characterize_corners(self):
""" Characterize the list of corners. """
debug.info(1,"Characterizing corners: " + str(self.corners))
for (self.corner,lib_name) in zip(self.corners,self.lib_files):
debug.info(1,"Corner: " + str(self.corner))
(self.process, self.voltage, self.temperature) = self.corner

View File

@ -2,6 +2,7 @@ word_size = 32
num_words = 128
tech_name = "scn4m_subm"
nominal_corners_only = False
process_corners = ["TT"]
supply_voltages = [5.0]
temperatures = [25]
@ -9,6 +10,3 @@ temperatures = [25]
output_path = "temp"
output_name = "sram_{0}_{1}_{2}".format(word_size, num_words, tech_name)
drc_name = "magic"
lvs_name = "netgen"
pex_name = "magic"

View File

@ -6,6 +6,7 @@ num_r_ports = 1
num_w_ports = 0
tech_name = "scn4m_subm"
nominal_corners_only = False
process_corners = ["TT"]
supply_voltages = [5.0]
temperatures = [25]
@ -17,7 +18,3 @@ output_path = "temp"
output_name = "sram_1rw_1r_{0}_{1}_{2}".format(word_size,
num_words,
tech_name)
drc_name = "magic"
lvs_name = "netgen"
pex_name = "magic"

View File

@ -6,6 +6,7 @@ num_r_ports = 1
num_w_ports = 0
tech_name = "scn4m_subm"
nominal_corners_only = False
process_corners = ["TT"]
supply_voltages = [5.0]
temperatures = [25]

View File

@ -2,6 +2,7 @@ word_size = 2
num_words = 16
tech_name = "freepdk45"
nominal_corners_only = False
process_corners = ["TT"]
supply_voltages = [1.0]
temperatures = [25]

View File

@ -2,6 +2,7 @@ word_size = 2
num_words = 16
tech_name = "scn4m_subm"
nominal_corners_only = False
process_corners = ["TT"]
supply_voltages = [5.0]
temperatures = [25]
@ -14,6 +15,3 @@ output_name = "sram_{0}_{1}_{2}".format(word_size,
num_words,
tech_name)
drc_name = "magic"
lvs_name = "netgen"
pex_name = "magic"

View File

@ -2,6 +2,7 @@ word_size = 64
num_words = 1024
tech_name = "scn4m_subm"
nominal_corners_only = False
process_corners = ["TT"]
supply_voltages = [ 5.0 ]
temperatures = [ 25 ]
@ -10,7 +11,3 @@ output_path = "temp"
output_name = "sram_{0}_{1}_{2}".format(word_size,
num_words,
tech_name)
drc_name = "magic"
lvs_name = "netgen"
pex_name = "magic"

View File

@ -2,8 +2,9 @@ word_size = 16
num_words = 256
tech_name = "scn4m_subm"
nominal_corners_only = False
process_corners = ["TT"]
supply_voltages = [3.3]
supply_voltages = [5.0]
temperatures = [25]
output_path = "temp"
@ -11,6 +12,3 @@ output_name = "sram_{0}_{1}_{2}".format(word_size,
num_words,
tech_name)
drc_name = "magic"
lvs_name = "netgen"
pex_name = "magic"

View File

@ -164,7 +164,7 @@ class Gds2reader:
print("Mask: "+mask)
elif(idBits==b'\x03\x05'): #this is also wrong b/c python doesn't natively have an 8 byte float
userUnits=self.ieeeDoubleFromIbmData(record[2:10])
dbUnits=self.ieeeDoubleFromIbmData
dbUnits=self.ieeeDoubleFromIbmData(record[10:18])
self.layoutObject.info["units"] = (userUnits,dbUnits)
if(self.debugToTerminal==1):
print("Units: 1 user unit="+str(userUnits)+" database units, 1 database unit="+str(dbUnits)+" meters.")
@ -175,6 +175,8 @@ class Gds2reader:
def readBoundary(self):
##reads in a boundary type structure = a filled polygon
if(self.debugToTerminal==1):
print("\t\t\tBeginBoundary")
thisBoundary=GdsBoundary()
while 1:
record = self.readNextRecord()
@ -201,11 +203,6 @@ class Gds2reader:
thisBoundary.purposeLayer=purposeLayer
if(self.debugToTerminal==1):
print("\t\tPurpose Layer: "+str(purposeLayer))
elif(idBits==b'\x0E\x02'): #DataType
dataType = struct.unpack(">h",record[2:4])[0]
thisBoundary.dataType=dataType
if(self.debugToTerminal==1):
print("\t\t\tData Type: "+str(dataType))
elif(idBits==b'\x10\x03'): #XY Data Points
numDataPoints = len(record)-2 #packed as XY coordinates 4 bytes each
thisBoundary.coordinates=[]
@ -216,10 +213,15 @@ class Gds2reader:
if(self.debugToTerminal==1):
print("\t\t\tXY Point: "+str(x)+","+str(y))
elif(idBits==b'\x11\x00'): #End Of Element
if(self.debugToTerminal==1):
print("\t\t\tEndBoundary")
break;
return thisBoundary
def readPath(self): #reads in a path structure
if(self.debugToTerminal==1):
print("\t\t\tBeginPath")
thisPath=GdsPath()
while 1:
record = self.readNextRecord()
@ -266,10 +268,15 @@ class Gds2reader:
if(self.debugToTerminal==1):
print("\t\t\tXY Point: "+str(x)+","+str(y))
elif(idBits==b'\x11\x00'): #End Of Element
if(self.debugToTerminal==1):
print("\t\t\tEndPath")
break;
return thisPath
def readSref(self): #reads in a reference to another structure
if(self.debugToTerminal==1):
print("\t\t\tBeginSref")
thisSref=GdsSref()
while 1:
record = self.readNextRecord()
@ -317,10 +324,15 @@ class Gds2reader:
if(self.debugToTerminal==1):
print("\t\t\tXY Point: "+str(x)+","+str(y))
elif(idBits==b'\x11\x00'): #End Of Element
if(self.debugToTerminal==1):
print("\t\t\tEndSref")
break;
return thisSref
def readAref(self): #an array of references
if(self.debugToTerminal==1):
print("\t\t\tBeginAref")
thisAref = GdsAref()
while 1:
record = self.readNextRecord()
@ -372,11 +384,15 @@ class Gds2reader:
print("\t\t\t\tArray Width: "+str(rightMostX-topLeftX))
print("\t\t\t\tArray Height: "+str(topLeftY-bottomMostY))
elif(idBits==b'\x11\x00'): #End Of Element
if(self.debugToTerminal==1):
print("\t\t\tEndAref")
break;
return thisAref
def readText(self):
##reads in a text structure
if(self.debugToTerminal==1):
print("\t\t\tBeginText")
thisText=GdsText()
while 1:
record = self.readNextRecord()
@ -472,10 +488,15 @@ class Gds2reader:
if(self.debugToTerminal==1):
print("\t\t\tText String: "+textString)
elif(idBits==b'\x11\x00'): #End Of Element
if(self.debugToTerminal==1):
print("\t\t\tEndText")
break;
return thisText
def readNode(self):
if(self.debugToTerminal==1):
print("\t\t\tBeginNode")
##reads in a node type structure = an electrical net
thisNode = GdsNode()
while 1:
@ -513,10 +534,15 @@ class Gds2reader:
if(self.debugToTerminal==1):
print("\t\t\tXY Point: "+str(x)+","+str(y))
elif(idBits==b'\x11\x00'): #End Of Element
if(self.debugToTerminal==1):
print("\t\t\tEndNode")
break;
return thisNode
def readBox(self):
if(self.debugToTerminal==1):
print("\t\t\tBeginBox")
##reads in a gds BOX structure
thisBox = GdsBox()
while 1:
@ -559,6 +585,8 @@ class Gds2reader:
if(self.debugToTerminal==1):
print("\t\t\tXY Point: "+str(x)+","+str(y))
elif(idBits==b'\x11\x00'): #End Of Element
if(self.debugToTerminal==1):
print("\t\t\tEndBox")
break;
return thisBox
@ -566,6 +594,7 @@ class Gds2reader:
thisStructure = GdsStructure()
record = self.readNextRecord()
idBits = record[0:2]
# Begin structure
if(idBits==b'\x05\x02' and len(record)==26):
createYear = struct.unpack(">h",record[2:4])[0]
createMonth = struct.unpack(">h",record[4:6])[0]
@ -581,6 +610,10 @@ class Gds2reader:
modSecond = struct.unpack(">h",record[24:26])[0]
thisStructure.createDate=(createYear,createMonth,createDay,createHour,createMinute,createSecond)
thisStructure.modDate=(modYear,modMonth,modDay,modHour,modMinute,modSecond)
if(self.debugToTerminal==1):
print("Date Created:"+str(createYear)+","+str(createMonth)+","+str(createDay)+\
","+str(createHour)+","+str(createMinute)+","+str(createSecond))
print("Date Modified:"+str(modYear)+","+str(modMonth)+","+str(modDay)+","+str(modHour)+","+str(modMinute)+","+str(modSecond))
else:
#means we have hit the last structure, so return the record
#to whoever called us to do something with it

View File

@ -187,27 +187,25 @@ class Gds2writer:
idBits=b'\x08\x00' #record Type
self.writeRecord(idBits)
if(thisBoundary.elementFlags!=""):
idBits=b'\x26\x01' #ELFLAGS
idBits=b'\x26\x01' # ELFLAGS
elementFlags = struct.pack(">h",thisBoundary.elementFlags)
self.writeRecord(idBits+elementFlags)
if(thisBoundary.plex!=""):
idBits=b'\x2F\x03' #PLEX
idBits=b'\x2F\x03' # PLEX
plex = struct.pack(">i",thisBoundary.plex)
self.writeRecord(idBits+plex)
if(thisBoundary.drawingLayer!=""):
idBits=b'\x0D\x02' #drawig layer
idBits=b'\x0D\x02' # drawing layer
drawingLayer = struct.pack(">h",thisBoundary.drawingLayer)
self.writeRecord(idBits+drawingLayer)
if(thisBoundary.purposeLayer):
idBits=b'\x16\x02' #purpose layer
purposeLayer = struct.pack(">h",thisBoundary.purposeLayer)
self.writeRecord(idBits+purposeLayer)
if(thisBoundary.dataType!=""):
idBits=b'\x0E\x02'#DataType
dataType = struct.pack(">h",thisBoundary.dataType)
if(thisBoundary.purposeLayer!=""):
idBits=b'\x0E\x02' # DataType
if type(thisBoundary.purposeLayer)!=int:
import pdb; pdb.set_trace()
dataType = struct.pack(">h",thisBoundary.purposeLayer)
self.writeRecord(idBits+dataType)
if(thisBoundary.coordinates!=""):
idBits=b'\x10\x03' #XY Data Points
idBits=b'\x10\x03' # XY Data Points
coordinateRecord = idBits
for coordinate in thisBoundary.coordinates:
x=struct.pack(">i",int(coordinate[0]))
@ -377,9 +375,9 @@ class Gds2writer:
idBits=b'\x0D\x02' #drawing layer
drawingLayer = struct.pack(">h",thisText.drawingLayer)
self.writeRecord(idBits+drawingLayer)
#if(thisText.purposeLayer):
# TextType is always a 0 per GDS specification
idBits=b'\x16\x02' #purpose layer
purposeLayer = struct.pack(">h",thisText.purposeLayer)
purposeLayer = struct.pack(">h",0)
self.writeRecord(idBits+purposeLayer)
if(thisText.transFlags != ""):
idBits=b'\x1A\x01'

View File

@ -21,8 +21,7 @@ class GdsBoundary:
self.elementFlags=""
self.plex=""
self.drawingLayer=""
self.purposeLayer = None
self.dataType=""
self.purposeLayer=0
self.coordinates=""
class GdsPath:
@ -31,7 +30,7 @@ class GdsPath:
self.elementFlags=""
self.plex=""
self.drawingLayer=""
self.purposeLayer = None
self.purposeLayer=0
self.pathType=""
self.pathWidth=""
self.coordinates=""
@ -140,7 +139,7 @@ class GdsText:
self.elementFlags=""
self.plex=""
self.drawingLayer=""
self.purposeLayer = None
self.purposeLayer=0
self.transFlags=[0,0,0]
self.magFactor=""
self.rotateAngle=""
@ -165,6 +164,6 @@ class GdsBox:
self.elementFlags=""
self.plex=""
self.drawingLayer=""
self.purposeLayer = None
self.purposeLayer=0
self.boxValue=""
self.coordinates=""

View File

@ -2,7 +2,6 @@ from .gdsPrimitives import *
from datetime import *
#from mpmath import matrix
#from numpy import matrix
from vector import vector
import numpy as np
#import gdsPrimitives
import debug
@ -358,7 +357,7 @@ class VlsiLayout:
#add the sref to the root structure
self.structures[self.rootStructureName].srefs.append(layoutToAddSref)
def addBox(self,layerNumber=0, purposeNumber=None, offsetInMicrons=(0,0), width=1.0, height=1.0,center=False):
def addBox(self,layerNumber=0, purposeNumber=0, offsetInMicrons=(0,0), width=1.0, height=1.0,center=False):
"""
Method to add a box to a layout
"""
@ -383,13 +382,12 @@ class VlsiLayout:
boundaryToAdd = GdsBoundary()
boundaryToAdd.drawingLayer = layerNumber
boundaryToAdd.dataType = 0
boundaryToAdd.coordinates = coordinates
boundaryToAdd.purposeLayer = purposeNumber
#add the sref to the root structure
self.structures[self.rootStructureName].boundaries.append(boundaryToAdd)
def addPath(self, layerNumber=0, purposeNumber=None, coordinates=[(0,0)], width=1.0):
def addPath(self, layerNumber=0, purposeNumber=0, coordinates=[(0,0)], width=1.0):
"""
Method to add a path to a layout
"""
@ -408,12 +406,10 @@ class VlsiLayout:
#add the sref to the root structure
self.structures[self.rootStructureName].paths.append(pathToAdd)
def addText(self, text, layerNumber=0, purposeNumber=None, offsetInMicrons=(0,0), magnification=0.1, rotate = None):
def addText(self, text, layerNumber=0, offsetInMicrons=(0,0), magnification=0.1, rotate = None):
offsetInLayoutUnits = (self.userUnits(offsetInMicrons[0]),self.userUnits(offsetInMicrons[1]))
textToAdd = GdsText()
textToAdd.drawingLayer = layerNumber
textToAdd.purposeLayer = purposeNumber
textToAdd.dataType = 0
textToAdd.coordinates = [offsetInLayoutUnits]
textToAdd.transFlags = [0,0,0]
textToAdd.textString = self.padText(text)
@ -757,7 +753,7 @@ class VlsiLayout:
for boundary in shapes:
vectors = []
for i in range(0, len(boundary), 2):
vectors.append(vector(boundary[i], boundary[i+1]))
vectors.append((boundary[i], boundary[i+1]))
blockages.append(vectors)
return blockages

View File

@ -168,8 +168,6 @@ def init_openram(config_file, is_unit_test=True):
from sram_factory import factory
factory.reset()
setup_bitcell()
global OPTS
global CHECKPOINT_OPTS
@ -398,7 +396,8 @@ def setup_paths():
full_path = "{0}/{1}".format(OPENRAM_HOME, subdir)
debug.check(os.path.isdir(full_path),
"$OPENRAM_HOME/{0} does not exist: {1}".format(subdir, full_path))
sys.path.append("{0}".format(full_path))
if "__pycache__" not in full_path:
sys.path.append("{0}".format(full_path))
if not OPTS.openram_temp.endswith('/'):
OPTS.openram_temp += "/"
@ -450,13 +449,23 @@ def init_paths():
def set_default_corner():
""" Set the default corner. """
import tech
# Set some default options now based on the technology...
if (OPTS.process_corners == ""):
OPTS.process_corners = tech.spice["fet_models"].keys()
if OPTS.nominal_corner_only:
OPTS.process_corners = ["TT"]
else:
OPTS.process_corners = tech.spice["fet_models"].keys()
if (OPTS.supply_voltages == ""):
OPTS.supply_voltages = tech.spice["supply_voltages"]
if OPTS.nominal_corner_only:
OPTS.supply_voltages = [tech.spice["supply_voltages"][1]]
else:
OPTS.supply_voltages = tech.spice["supply_voltages"]
if (OPTS.temperatures == ""):
OPTS.temperatures = tech.spice["temperatures"]
if OPTS.nominal_corner_only:
OPTS.temperatures = [tech.spice["temperatures"][1]]
else:
OPTS.temperatures = tech.spice["temperatures"]
def import_tech():
@ -483,7 +492,7 @@ def import_tech():
try:
tech_mod = __import__(OPTS.tech_name)
except ImportError:
debug.error("Nonexistent technology_setup_file: {0}.py".format(filename), -1)
debug.error("Nonexistent technology module: {0}".format(OPTS.tech_name), -1)
OPTS.openram_tech = os.path.dirname(tech_mod.__file__) + "/"
@ -572,5 +581,5 @@ def report_status():
debug.print_raw("Performing simulation-based characterization with {}".format(OPTS.spice_name))
if OPTS.trim_netlist:
debug.print_raw("Trimming netlist to speed up characterization (trim_netlist=False to disable).")
if OPTS.nominal_corner_only:
debug.print_raw("Only characterizing nominal corner.")

View File

@ -31,8 +31,12 @@ if len(args) != 1:
# These depend on arguments, so don't load them until now.
import debug
# Parse config file and set up all the options
g.init_openram(config_file=args[0], is_unit_test=False)
# Ensure that the right bitcell exists or use the parameterised one
g.setup_bitcell()
# Only print banner here so it's not in unit tests
g.print_banner()

View File

@ -34,6 +34,7 @@ class options(optparse.Values):
write_size = None
# These will get initialized by the user or the tech file
nominal_corner_only = False
supply_voltages = ""
temperatures = ""
process_corners = ""
@ -110,8 +111,7 @@ class options(optparse.Values):
# Should we print out the banner at startup
print_banner = True
# Use detailed LEF blockages
detailed_blockages = True
# Define the output file paths
output_path = "."
# Define the output file base name

View File

@ -8,7 +8,7 @@
import contact
import design
import debug
from tech import drc
from tech import layer, drc
from vector import vector
from globals import OPTS
from sram_factory import factory
@ -141,27 +141,29 @@ class pgate(design.design):
max_y_offset = self.height + 0.5 * self.m1_width
self.nwell_position = middle_position
nwell_height = max_y_offset - middle_position.y
if drc("has_nwell"):
if layer["nwell"]:
self.add_rect(layer="nwell",
offset=middle_position,
width=self.well_width,
height=nwell_height)
self.add_rect(layer="vtg",
offset=self.nwell_position,
width=self.well_width,
height=nwell_height)
if layer["vtg"]:
self.add_rect(layer="vtg",
offset=self.nwell_position,
width=self.well_width,
height=nwell_height)
pwell_position = vector(0, -0.5 * self.m1_width)
pwell_height = middle_position.y - pwell_position.y
if drc("has_pwell"):
if layer["pwell"]:
self.add_rect(layer="pwell",
offset=pwell_position,
width=self.well_width,
height=pwell_height)
self.add_rect(layer="vtg",
offset=pwell_position,
width=self.well_width,
height=pwell_height)
if layer["vtg"]:
self.add_rect(layer="vtg",
offset=pwell_position,
width=self.well_width,
height=pwell_height)
def add_nwell_contact(self, pmos, pmos_pos):
""" Add an nwell contact next to the given pmos device. """

View File

@ -7,7 +7,7 @@
#
import design
import debug
from tech import drc, spice
from tech import layer, drc, spice
from vector import vector
from sram_factory import factory
@ -59,6 +59,13 @@ class ptx(design.design):
# some transistor sizes in other netlist depend on pbitcell
self.create_layout()
#ll = self.find_lowest_coords()
#ur = self.find_highest_coords()
#self.add_boundary(ll, ur)
# (0,0) will be the corner ofthe active area (not the larger well)
self.translate_all(self.active_offset)
def create_layout(self):
"""Calls all functions related to the generation of the layout"""
self.setup_layout_constants()
@ -66,7 +73,6 @@ class ptx(design.design):
self.add_well_implant()
self.add_poly()
self.add_active_contacts()
self.translate_all(self.active_offset)
# for run-time, we won't check every transitor DRC independently
# but this may be uncommented for debug purposes
@ -124,18 +130,18 @@ class ptx(design.design):
# The contacted poly pitch (or uncontacted in an odd technology)
self.poly_pitch = max(2 * self.contact_to_gate + self.contact_width + self.poly_width,
self.poly_pitch = max(2 * self.active_contact_to_gate + self.contact_width + self.poly_width,
self.poly_space)
# The contacted poly pitch (or uncontacted in an odd technology)
self.contact_pitch = 2 * self.contact_to_gate + self.contact_width + self.poly_width
self.contact_pitch = 2 * self.active_contact_to_gate + self.contact_width + self.poly_width
# The enclosure of an active contact. Not sure about second term.
active_enclose_contact = max(drc("active_enclosure_contact"),
active_enclose_contact = max(drc("active_enclosure_active_contact"),
(self.active_width - self.contact_width) / 2)
# This is the distance from the edge of poly to the contacted end of active
self.end_to_poly = active_enclose_contact + self.contact_width + self.contact_to_gate
self.end_to_poly = active_enclose_contact + self.contact_width + self.active_contact_to_gate
# Active width is determined by enclosure on both ends and contacted pitch,
@ -152,7 +158,8 @@ class ptx(design.design):
self.active_offset = vector([self.well_enclose_active] * 2)
# Well enclosure of active, ensure minwidth as well
if drc("has_{}well".format(self.well_type)):
well_name = "{}well".format(self.well_type)
if layer[well_name]:
self.cell_well_width = max(self.active_width + 2 * self.well_enclose_active,
self.well_width)
self.cell_well_height = max(self.tx_width + 2 * self.well_enclose_active,
@ -318,11 +325,13 @@ class ptx(design.design):
"""
Add an (optional) well and implant for the type of transistor.
"""
if drc("has_{}well".format(self.well_type)):
self.add_rect(layer="{}well".format(self.well_type),
well_name = "{}well".format(self.well_type)
if layer[well_name]:
self.add_rect(layer=well_name,
offset=(0,0),
width=self.cell_well_width,
height=self.cell_well_height)
if layer["vtg"]:
self.add_rect(layer="vtg",
offset=(0,0),
width=self.cell_well_width,

View File

@ -42,6 +42,11 @@ def setup_files():
files = os.listdir(gds_dir)
nametest = re.compile("\.gds$", re.IGNORECASE)
gds_files = list(filter(nametest.search, files))
import tech
if tech.blackbox_bitcell:
# Ignore DRC of all bitcells
nametest = re.compile("cell", re.IGNORECASE)
gds_files = list(filter(lambda v: not nametest.search(v), gds_files))
return (gds_dir, gds_files)

View File

@ -42,7 +42,7 @@ class wire_test(openram_test):
min_space = 2 * (tech.drc["minwidth_poly"] +
tech.drc["minwidth_metal1"])
layer_stack = ("metal1", "contact", "poly")
layer_stack = ("poly", "contact", "metal1")
old_position_list = [[0, 0],
[0, 3 * min_space],
[1 * min_space, 3 * min_space],

0
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):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
OPTS.nominal_corner_only = False
OPTS.netlist_only = True
from characterizer import lib

View File

@ -20,6 +20,7 @@ class lib_sram_model_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
OPTS.nominal_corner_only = False
OPTS.netlist_only = True
from characterizer import lib

View File

@ -21,6 +21,7 @@ class lib_sram_prune_test(openram_test):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
OPTS.analytical_delay = False
OPTS.netlist_only = True
OPTS.trim_netlist = True
# This is a hack to reload the characterizer __init__ with the spice version

View File

@ -20,6 +20,7 @@ class lib_test(openram_test):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
OPTS.analytical_delay = False
OPTS.netlist_only = True
OPTS.trim_netlist = False
# This is a hack to reload the characterizer __init__ with the spice version

View File

@ -11,20 +11,7 @@ num_words = 16
tech_name = OPTS.tech_name
process_corners = ["TT"]
supply_voltages = [5.0]
temperatures = [25]
nominal_corner_only = True
route_supplies = True
check_lvsdrc = True
if tech_name == "freepdk45":
supply_voltages = [1.0]
drc_name = "calibre"
lvs_name = "calibre"
pex_name = "calibre"
else:
drc_name = "magic"
lvs_name = "netgen"
pex_name = "magic"

View File

@ -10,22 +10,11 @@ word_size = 1
num_words = 16
tech_name = OPTS.tech_name
process_corners = ["TT"]
supply_voltages = [5.0]
temperatures = [25]
nominal_corner_only = True
route_supplies = True
check_lvsdrc = True
inline_lvsdrc = True
analytical_delay = False
if tech_name == "freepdk45":
supply_voltages = [1.0]
drc_name = "calibre"
lvs_name = "calibre"
pex_name = "calibre"
else:
drc_name = "magic"
lvs_name = "netgen"
pex_name = "magic"

View File

@ -10,18 +10,4 @@ word_size = 1
num_words = 16
tech_name = OPTS.tech_name
process_corners = ["TT"]
supply_voltages = [5.0]
temperatures = [25]
if tech_name == "freepdk45":
supply_voltages = [1.0]
drc_name = "calibre"
lvs_name = "calibre"
pex_name = "calibre"
else:
drc_name = "magic"
lvs_name = "netgen"
pex_name = "magic"

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 debug
from globals import OPTS,find_exe,get_tool
from globals import OPTS
from globals import find_exe
from globals import get_tool
from tech import drc_name
from tech import lvs_name
from tech import pex_name
import sys
debug.info(1,"Initializing verify...")
@ -29,29 +34,29 @@ if not OPTS.check_lvsdrc:
OPTS.pex_exe = None
else:
debug.info(1, "Finding DRC/LVS/PEX tools.")
OPTS.drc_exe = get_tool("DRC", ["calibre","assura","magic"], OPTS.drc_name)
OPTS.lvs_exe = get_tool("LVS", ["calibre","assura","netgen"], OPTS.lvs_name)
OPTS.pex_exe = get_tool("PEX", ["calibre","magic"], OPTS.pex_name)
OPTS.drc_exe = get_tool("DRC", ["calibre","assura","magic"], drc_name)
OPTS.lvs_exe = get_tool("LVS", ["calibre","assura","netgen"], lvs_name)
OPTS.pex_exe = get_tool("PEX", ["calibre","magic"], pex_name)
if OPTS.drc_exe == None:
from .none import run_drc,print_drc_stats
from .none import run_drc, print_drc_stats
elif "calibre"==OPTS.drc_exe[0]:
from .calibre import run_drc,print_drc_stats
from .calibre import run_drc, print_drc_stats
elif "assura"==OPTS.drc_exe[0]:
from .assura import run_drc,print_drc_stats
from .assura import run_drc, print_drc_stats
elif "magic"==OPTS.drc_exe[0]:
from .magic import run_drc,print_drc_stats
from .magic import run_drc, print_drc_stats
else:
debug.warning("Did not find a supported DRC tool.")
if OPTS.lvs_exe == None:
from .none import run_lvs,print_lvs_stats
from .none import run_lvs, print_lvs_stats
elif "calibre"==OPTS.lvs_exe[0]:
from .calibre import run_lvs,print_lvs_stats
from .calibre import run_lvs, print_lvs_stats
elif "assura"==OPTS.lvs_exe[0]:
from .assura import run_lvs,print_lvs_stats
from .assura import run_lvs, print_lvs_stats
elif "netgen"==OPTS.lvs_exe[0]:
from .magic import run_lvs,print_lvs_stats
from .magic import run_lvs, print_lvs_stats
else:
debug.warning("Did not find a supported LVS tool.")

View File

@ -44,8 +44,8 @@ layer["vtg"] = (6, 0)
layer["vth"] = (7, 0)
layer["thkox"] = (8, 0)
layer["poly"] = (9, 0)
layer["contact"] = (10, 0)
layer["active_contact"] = (10, 0)
layer["poly_contact"] = (10, 0)
layer["metal1"] = (11, 0)
layer["via1"] = (12, 0)
layer["metal2"] = (13, 0)
@ -89,10 +89,6 @@ drclvs_home=os.environ.get("DRCLVS_HOME")
drc = design_rules("freepdk45")
drc["body_tie_down"] = 0
drc["has_pwell"] = True
drc["has_nwell"] = True
#grid size
drc["grid"] = 0.0025
@ -120,7 +116,7 @@ drc["poly_to_poly"] = 0.14
# POLY.3 Minimum poly extension beyond active
drc["poly_extend_active"] = 0.055
# Not a rule
drc["poly_to_polycontact"] = 0.075
drc["poly_to_poly_contact"] = 0.075
# POLY.4 Minimum enclosure of active around gate
drc["active_enclosure_gate"] = 0.07
# POLY.5 Minimum spacing of field poly to active
@ -157,30 +153,45 @@ drc["implant_to_implant"] = 0.045
drc["minwidth_implant"] = 0.045
# CONTACT.1 Minimum width of contact
drc["minwidth_contact"] = 0.065
drc["minwidth_active_contact"] = 0.065
# CONTACT.2 Minimum spacing of contact
drc["contact_to_contact"] = 0.075
drc["active_contact_to_active_contact"] = 0.075
# CONTACT.4 Minimum enclosure of active around contact
drc["active_enclosure_contact"] = 0.005
drc["active_enclosure_active_contact"] = 0.005
# Reserved for asymmetric enclosures
drc["active_extend_contact"] = 0.005
# CONTACT.5 Minimum enclosure of poly around contact
drc["poly_enclosure_contact"] = 0.005
drc["active_extend_active_contact"] = 0.005
# CONTACT.6 Minimum spacing of contact and gate
drc["active_contact_to_gate"] = 0.0375 #changed from 0.035
# CONTACT.7 Minimum spacing of contact and poly
drc["active_contact_to_poly"] = 0.090
# CONTACT.1 Minimum width of contact
drc["minwidth_poly_contact"] = 0.065
# CONTACT.2 Minimum spacing of contact
drc["poly_contact_to_poly_contact"] = 0.075
# Reserved for asymmetric enclosures
drc["poly_extend_contact"] = 0.005
# CONTACT.5 Minimum enclosure of poly around contact
drc["poly_enclosure_poly_contact"] = 0.005
# Reserved for asymmetric enclosures
drc["poly_extend_poly_contact"] = 0.005
# CONTACT.6 Minimum spacing of contact and gate
drc["contact_to_gate"] = 0.0375 #changed from 0.035
drc["poly_contact_to_gate"] = 0.0375 #changed from 0.035
# CONTACT.7 Minimum spacing of contact and poly
drc["contact_to_poly"] = 0.090
drc["poly_contact_to_poly"] = 0.090
# METAL1.1 Minimum width of metal1
drc["minwidth_metal1"] = 0.065
# METAL1.2 Minimum spacing of metal1
drc["metal1_to_metal1"] = 0.065
# METAL1.3 Minimum enclosure around contact on two opposite sides
drc["metal1_enclosure_contact"] = 0
drc["metal1_enclosure_active_contact"] = 0
# Reserved for asymmetric enclosures
drc["metal1_extend_contact"] = 0.035
drc["metal1_extend_active_contact"] = 0.035
# METAL1.3 Minimum enclosure around contact on two opposite sides
drc["metal1_enclosure_poly_contact"] = 0
# Reserved for asymmetric enclosures
drc["metal1_extend_poly_contact"] = 0.035
# METAL1.4 inimum enclosure around via1 on two opposite sides
drc["metal1_extend_via1"] = 0.035
# Reserved for asymmetric enclosures
@ -339,3 +350,16 @@ parameter["bitcell_drain_cap"] = 0.1 #In Femto-Farad, approximation of dr
##END Spice Simulation Parameters
###################################################
###################################################
##BEGIN Technology Tool Preferences
###################################################
drc_name = "calibre"
lvs_name = "calibre"
pex_name = "calibre"
blackbox_bitcell = False
###################################################
##END Technology Tool Preferences
###################################################

View File

@ -35,9 +35,5 @@ except:
DRCLVS_HOME=OPENRAM_TECH+"/scn3me_subm/tech"
os.environ["DRCLVS_HOME"] = DRCLVS_HOME
# try:
# SPICE_MODEL_DIR = os.path.abspath(os.environ.get("SPICE_MODEL_DIR"))
# except:
OPENRAM_TECH=os.path.abspath(os.environ.get("OPENRAM_TECH"))
os.environ["SPICE_MODEL_DIR"] = "{0}/{1}/models".format(OPENRAM_TECH, TECHNOLOGY)
os.environ["SPICE_MODEL_DIR"] = "{0}/models".format(os.path.dirname(__file__))

View File

@ -277,3 +277,15 @@ parameter["bitcell_drain_cap"] = 0.2 #In Femto-Farad, approximation of dr
###################################################
##END Spice Simulation Parameters
###################################################
###################################################
##BEGIN Technology Tool Preferences
###################################################
drc_name = "magic"
lvs_name = "netgen"
pex_name = "magic"
###################################################
##END Technology Tool Preferences
###################################################

View File

@ -35,9 +35,5 @@ except:
DRCLVS_HOME=OPENRAM_TECH+"/scn4m_subm/tech"
os.environ["DRCLVS_HOME"] = DRCLVS_HOME
# try:
# SPICE_MODEL_DIR = os.path.abspath(os.environ.get("SPICE_MODEL_DIR"))
# except:
OPENRAM_TECH=os.path.abspath(os.environ.get("OPENRAM_TECH"))
os.environ["SPICE_MODEL_DIR"] = "{0}/{1}/models".format(OPENRAM_TECH, TECHNOLOGY)
os.environ["SPICE_MODEL_DIR"] = "{0}/models".format(os.path.dirname(__file__))

View File

@ -35,9 +35,8 @@ GDS["zoom"] = 0.5
# create the GDS layer map
layer={}
layer["vtg"] = (-1, 0)
layer["vth"] = (-1, 0)
layer["contact"] = (47, 0)
layer["vtg"] = None
layer["vth"] = None
layer["pwell"] = (41, 0)
layer["nwell"] = (42, 0)
layer["active"] = (43, 0)
@ -45,6 +44,7 @@ layer["pimplant"] = (44, 0)
layer["nimplant"] = (45, 0)
layer["poly"] = (46, 0)
layer["active_contact"] = (48, 0)
layer["poly_contact"] = (47, 0)
layer["metal1"] = (49, 0)
layer["via1"] = (50, 0)
layer["metal2"] = (51, 0)
@ -78,10 +78,6 @@ drclvs_home=os.environ.get("DRCLVS_HOME")
drc = design_rules("scn4me_sub")
drc["body_tie_down"] = 0
drc["has_pwell"] = True
drc["has_nwell"] = True
#grid size is 1/2 a lambda
drc["grid"]=0.5*_lambda_
@ -108,7 +104,7 @@ drc["poly_to_poly"] = 3*_lambda_
# 3.3 Minimum gate extension of active
drc["poly_extend_active"] = 2*_lambda_
# 5.5.b Minimum spacing between poly contact and other poly (alternative rules)
drc["poly_to_polycontact"] = 4*_lambda_
drc["poly_to_poly_contact"] = 4*_lambda_
# ??
drc["active_enclosure_gate"] = 0.0
# 3.5 Minimum field poly to active
@ -145,30 +141,43 @@ drc["implant_to_implant"] = 0
drc["minwidth_implant"] = 0
# 6.1 Exact contact size
drc["minwidth_contact"] = 2*_lambda_
drc["minwidth_active_contact"] = 2*_lambda_
# 5.3 Minimum contact spacing
drc["contact_to_contact"] = 3*_lambda_
drc["active_contact_to_active_contact"] = 3*_lambda_
# 6.2.b Minimum active overlap
drc["active_enclosure_contact"] = _lambda_
drc["active_enclosure_active_contact"] = _lambda_
# Reserved for asymmetric enclosure
drc["active_extend_contact"] = _lambda_
# 5.2.b Minimum poly overlap
drc["poly_enclosure_contact"] = _lambda_
# Reserved for asymmetric enclosures
drc["poly_extend_contact"] = _lambda_
drc["active_extend_active_contact"] = _lambda_
# Reserved for other technologies
drc["contact_to_gate"] = 2*_lambda_
drc["active_contact_to_gate"] = 2*_lambda_
# 5.4 Minimum spacing to gate of transistor
drc["contact_to_poly"] = 2*_lambda_
drc["active_contact_to_poly"] = 2*_lambda_
# 6.1 Exact contact size
drc["minwidth_poly_contact"] = 2*_lambda_
# 5.3 Minimum contact spacing
drc["poly_contact_to_poly_contact"] = 3*_lambda_
# 5.2.b Minimum poly overlap
drc["poly_enclosure_poly_contact"] = _lambda_
# Reserved for asymmetric enclosures
drc["poly_extend_poly_contact"] = _lambda_
# Reserved for other technologies
drc["poly_contact_to_gate"] = 2*_lambda_
# 5.4 Minimum spacing to gate of transistor
drc["poly_contact_to_poly"] = 2*_lambda_
# 7.1 Minimum width
drc["minwidth_metal1"] = 3*_lambda_
# 7.2 Minimum spacing
drc["metal1_to_metal1"] = 3*_lambda_
# 7.3 Minimum overlap of any contact
drc["metal1_enclosure_contact"] = _lambda_
drc["metal1_enclosure_active_contact"] = _lambda_
# Reserved for asymmetric enclosure
drc["metal1_extend_contact"] = _lambda_
drc["metal1_extend_active_contact"] = _lambda_
# 7.3 Minimum overlap of any contact
drc["metal1_enclosure_poly_contact"] = _lambda_
# Reserved for asymmetric enclosure
drc["metal1_extend_poly_contact"] = _lambda_
# 8.3 Minimum overlap by metal1
drc["metal1_enclosure_via1"] = _lambda_
# Reserve for asymmetric enclosures
@ -304,3 +313,17 @@ parameter["bitcell_drain_cap"] = 0.2 #In Femto-Farad, approximation of dr
###################################################
##END Spice Simulation Parameters
###################################################
###################################################
##BEGIN Technology Tool Preferences
###################################################
drc_name = "magic"
lvs_name = "netgen"
pex_name = "magic"
blackbox_bitcell = False
###################################################
##END Technology Tool Preferences
###################################################