Merge branch 'dev' into supply_routing

This commit is contained in:
Matt Guthaus 2018-10-20 14:29:19 -07:00
commit 7591f25a2e
11 changed files with 144 additions and 69 deletions

View File

@ -7,8 +7,8 @@ https://github.com/mguthaus/OpenRAM/blob/master/OpenRAM_ICCAD_2016_presentation.
The OpenRAM compiler has very few dependencies:
* ngspice-26 (or later) or HSpice I-2013.12-1 (or later) or CustomSim 2017 (or later)
* Python 3.5 and higher
* Python numpy
* flask_table
* Python numpy (pip3 install numpy)
* flask_table (pip3 install flask)
* a setup script for each technology
* a technology directory for each technology with the base cells
@ -49,7 +49,7 @@ We do not distribute the PDK, but you may get it from:
If you are using SCMOS, you should install Magic and netgen from:
http://opencircuitdesign.com/magic/
http://opencircuitdesign.com/netgen/
We have included the SCN3ME design rules from QFlow:
We have included the SCN4M design rules from QFlow:
http://opencircuitdesign.com/qflow/
# DIRECTORY STRUCTURE
@ -65,7 +65,7 @@ We have included the SCN3ME design rules from QFlow:
* compiler/tests - unit tests
* technology - openram technology directory (pointed to by OPENRAM_TECH)
* technology/freepdk45 - example configuration library for freepdk45 technology node
* technology/scn3me_subm - example configuration library SCMOS technology node
* technology/scn4m_subm - example configuration library SCMOS technology node
* technology/setup_scripts - setup scripts to customize your PDKs and OpenRAM technologies
* docs - LaTeX manual (likely outdated)
* lib - IP library of pregenerated memories
@ -90,8 +90,8 @@ To increase the verbosity of the test, add one (or more) -v options:
python tests/00_code_format_check_test.py -v -t freepdk45
```
To specify a particular technology use "-t <techname>" such as
"-t scn3me_subm". The default for a unit test is freepdk45 whereas
the default for openram.py is specified in the configuration file.
"-t freepdk45" or "-t scn4m_subm". The default for a unit test is scn4m_subm.
The default for openram.py is specified in the configuration file.
# CREATING CUSTOM TECHNOLOGIES

View File

@ -222,9 +222,9 @@ class pbitcell(design.design):
self.rowline_spacing = self.m1_space + contact.m1m2.width
# spacing for vdd
vdd_offset_well_constraint = self.well_enclose_active + 0.5*contact.well.width
vdd_offset_metal1_constraint = max(inverter_pmos_contact_extension, 0) + self.m1_space + 0.5*contact.well.width
self.vdd_offset = max(vdd_offset_well_constraint, vdd_offset_metal1_constraint)
implant_constraint = max(inverter_pmos_contact_extension, 0) + 2*self.implant_enclose_active + 0.5*(contact.well.width - self.m1_width)
metal1_constraint = max(inverter_pmos_contact_extension, 0) + self.m1_space
self.vdd_offset = max(implant_constraint, metal1_constraint) + 0.5*self.m1_width
# read port dimensions
width_reduction = self.read_nmos.active_width - self.read_nmos.get_pin("D").cx()
@ -334,7 +334,7 @@ class pbitcell(design.design):
layer="metal1",
offset=self.gnd_position,
width=self.width,
height=contact.well.second_layer_width)
height=self.m1_width)
vdd_ypos = self.inverter_nmos_ypos + self.inverter_nmos.active_height + self.inverter_gap + self.inverter_pmos.active_height + self.vdd_offset
self.vdd_position = vector(0, vdd_ypos)
@ -342,7 +342,7 @@ class pbitcell(design.design):
layer="metal1",
offset=self.vdd_position,
width=self.width,
height=contact.well.second_layer_width)
height=self.m1_width)
def create_readwrite_ports(self):
"""
@ -933,8 +933,9 @@ class pbitcell(design.design):
def route_rbc_short(self):
""" route the short from Q_bar to gnd necessary for the replica bitcell """
Q_bar_pos = self.inverter_pmos_right.get_pin("S").uc()
vdd_pos = vector(Q_bar_pos.x, self.vdd_position.y)
Q_bar_pos = self.inverter_pmos_right.get_pin("S").center()
vdd_pos = self.inverter_pmos_right.get_pin("D").center()
#vdd_pos = vector(Q_bar_pos.x, self.vdd_position.y)
self.add_path("metal1", [Q_bar_pos, vdd_pos])

View File

@ -526,15 +526,15 @@ class lib:
for (corner, lib_name) in zip(self.corners, self.lib_files):
ports = ""
if OPTS.num_rw_ports>0:
ports += "{}_".format(OPTS.num_rw_ports)
if OPTS.num_w_ports>0:
ports += "{}_".format(OPTS.num_w_ports)
if OPTS.num_r_ports>0:
ports += "{}_".format(OPTS.num_r_ports)
# ports = ""
# if OPTS.num_rw_ports>0:
# ports += "{}_".format(OPTS.num_rw_ports)
# if OPTS.num_w_ports>0:
# ports += "{}_".format(OPTS.num_w_ports)
# if OPTS.num_r_ports>0:
# ports += "{}_".format(OPTS.num_r_ports)
datasheet.write("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12}".format("sram_{0}_{1}_{2}{3}".format(OPTS.word_size, OPTS.num_words, ports, OPTS.tech_name),
datasheet.write("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13}".format("sram_{0}_{1}_{2}".format(OPTS.word_size, OPTS.num_words, OPTS.tech_name),
OPTS.num_words,
OPTS.num_banks,
OPTS.num_rw_ports,
@ -546,7 +546,8 @@ class lib:
self.corner[0],
round_time(self.char_sram_results["min_period"]),
self.out_dir,
lib_name))
lib_name,
OPTS.word_size))
datasheet.close()

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -3,16 +3,21 @@ from operating_conditions import *
from characterization_corners import *
from deliverables import *
from timing_and_current_data import *
from in_out import *
import os
from globals import OPTS
class datasheet():
def __init__(self,identifier):
self.io = []
self.corners = []
self.timing = []
self.operating = []
self.dlv = []
self.name = identifier
self.html = ""
def generate_html(self):
self.html = """<style>
@ -40,16 +45,25 @@ class datasheet():
color: white;
}
</style>"""
self.html +='<p style=font-size: 20px;font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;>{0}</p>'
self.html +='<p style=font-size: 20px;font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;>{0}</p>'
self.html +='<p style=font-size: 20px;font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;>{0}</p>'
self.html +='<p style=font-size: 20px;font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;>'+ self.name + '.html' + '</p>'
# self.html +='<p style=font-size: 20px;font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;>{0}</p>'
# self.html +='<p style=font-size: 20px;font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;>{0}</p>'
self.html +='<p style=font-size: 20px;font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;>Ports and Configuration (DEBUG)</p>'
self.html += in_out(self.io,table_id='data').__html__().replace('&lt;','<').replace('&#34;','"').replace('&gt;',">")
self.html +='<p style=font-size: 20px;font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;>Operating Conditions</p>'
self.html += operating_conditions(self.operating,table_id='data').__html__()
self.html += '<p style=font-size: 20px;font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;>Timing and Current Data</p>'
self.html += timing_and_current_data(self.timing,table_id='data').__html__()
self.html += '<p style=font-size: 20px;font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;>Characterization Corners</p>'
self.html += characterization_corners(self.corners,table_id='data').__html__()
self.html +='<p style=font-size: 20px;font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;>Deliverables</p>'
self.html += deliverables(self.dlv,table_id='data').__html__().replace('&lt;','<').replace('&#34;','"').replace('&gt;',">")
self.html +='<p style=font-size: 20px;font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;>*Feature only supported with characterizer</p>'
self.html +='<img src=' + os.path.abspath(os.environ.get("OPENRAM_HOME")) + '/datasheet/assets/vlsi_logo.png alt="VLSIDA" />'

View File

@ -8,17 +8,24 @@ Locate all timing elements in .lib
Diagram generation
Improve css
"""
import os, math
import optparse
from flask_table import *
import csv
import debug
from globals import OPTS
from deliverables import *
from operating_conditions import *
from timing_and_current_data import *
from characterization_corners import *
from datasheet import *
if OPTS.datasheet_gen:
import flask_table
import os, math
import optparse
import csv
from deliverables import *
from operating_conditions import *
from timing_and_current_data import *
from characterization_corners import *
from datasheet import *
from in_out import *
else:
debug.warning("Python library flask_table not found. Skipping html datasheet generation. This can be installed with pip install flask-table.")
def process_name(corner):
if corner == "TT":
@ -43,12 +50,13 @@ def parse_file(f,pages):
NUM_W_PORTS = row[4]
NUM_R_PORTS = row[5]
TECH_NAME = row[6]
TEMP = row[7]
VOLT = row[8]
TEMP = row[8]
VOLT = row[7]
PROC = row[9]
MIN_PERIOD = row[10]
OUT_DIR = row[11]
LIB_NAME = row[12]
WORD_SIZE = row[13]
for sheet in pages:
@ -95,39 +103,55 @@ def parse_file(f,pages):
new_sheet.operating.append(operating_conditions_item('Power supply (VDD) range',VOLT,VOLT,VOLT,'Volts'))
new_sheet.operating.append(operating_conditions_item('Operating Temperature',TEMP,TEMP,TEMP,'Celsius'))
try:
new_sheet.operating.append(operating_conditions_item('Operating Frequency (F)','','',str(math.floor(1000/float(MIN_PERIOD))),'MHz'))
new_sheet.operating.append(operating_conditions_item('Operating Frequency (F)*','','',str(math.floor(1000/float(MIN_PERIOD))),'MHz'))
except Exception:
new_sheet.operating.append(operating_conditions_item('Operating Frequency (F)','','',"unknown",'MHz')) #analytical model fails to provide MIN_PERIOD
new_sheet.operating.append(operating_conditions_item('Operating Frequency (F)*','','',"unknown",'MHz')) #analytical model fails to provide MIN_PERIOD
new_sheet.timing.append(timing_and_current_data_item('Cycle time','2','3','4'))
new_sheet.timing.append(timing_and_current_data_item('Access time','2','3','4'))
new_sheet.timing.append(timing_and_current_data_item('Positive clk setup','2','3','4'))
new_sheet.timing.append(timing_and_current_data_item('Positive clk hold','2','3','4'))
new_sheet.timing.append(timing_and_current_data_item('RW setup','2','3','4'))
new_sheet.timing.append(timing_and_current_data_item('RW hold','2','3','4'))
new_sheet.timing.append(timing_and_current_data_item('AC current','2','3','4'))
new_sheet.timing.append(timing_and_current_data_item('Standby current','2','3','4'))
new_sheet.timing.append(timing_and_current_data_item('Area','2','3','4'))
new_sheet.timing.append(timing_and_current_data_item('1','2','3','4'))
new_sheet.dlv.append(deliverables_item('.sp','SPICE netlists','<a href="file://{0}{1}.{2}">{1}.{2}</a>'.format(OUT_DIR,NAME,'sp')))
new_sheet.dlv.append(deliverables_item('.v','Verilog simulation models','<a href="file://{0}{1}.{2}">{1}.{2}</a>'.format(OUT_DIR,NAME,'v')))
new_sheet.dlv.append(deliverables_item('.gds','GDSII layout views','<a href="file://{0}{1}.{2}">{1}.{2}</a>'.format(OUT_DIR,NAME,'gds')))
new_sheet.dlv.append(deliverables_item('.lef','LEF files','<a href="file://{0}{1}.{2}">{1}.{2}</a>'.format(OUT_DIR,NAME,'lef')))
new_sheet.dlv.append(deliverables_item('.lib','Synthesis models','<a href="file://{0}">{1}</a>'.format(LIB_NAME,LIB_NAME.replace(OUT_DIR,''))))
new_sheet.io.append(in_out_item('WORD_SIZE',WORD_SIZE))
new_sheet.io.append(in_out_item('NUM_WORDS',NUM_WORDS))
new_sheet.io.append(in_out_item('NUM_BANKS',NUM_BANKS))
new_sheet.io.append(in_out_item('NUM_RW_PORTS',NUM_RW_PORTS))
new_sheet.io.append(in_out_item('NUM_R_PORTS',NUM_R_PORTS))
new_sheet.io.append(in_out_item('NUM_W_PORTS',NUM_W_PORTS))
class datasheet_gen():
def datasheet_write(name):
in_dir = OPTS.openram_temp
if not (os.path.isdir(in_dir)):
os.mkdir(in_dir)
if OPTS.datasheet_gen:
in_dir = OPTS.openram_temp
if not (os.path.isdir(in_dir)):
os.mkdir(in_dir)
#if not (os.path.isdir(out_dir)):
# os.mkdir(out_dir)
#if not (os.path.isdir(out_dir)):
# os.mkdir(out_dir)
datasheets = []
parse_file(in_dir + "/datasheet.info", datasheets)
datasheets = []
parse_file(in_dir + "/datasheet.info", datasheets)
for sheets in datasheets:
with open(name, 'w+') as f:
sheets.generate_html()
f.write(sheets.html)
for sheets in datasheets:
with open(name, 'w+') as f:
sheets.generate_html()
f.write(sheets.html)

View File

@ -0,0 +1,11 @@
from flask_table import *
class in_out(Table):
typ = Col('Type')
description = Col('Description')
class in_out_item(object):
def __init__(self, typ, description):
self.typ = typ
self.description = description

View File

@ -100,9 +100,17 @@ def check_versions():
minor_required = 5
if not (major_python_version == major_required and minor_python_version >= minor_required):
debug.error("Python {0}.{1} or greater is required.".format(major_required,minor_required),-1)
# FIXME: Check versions of other tools here??
# or, this could be done in each module (e.g. verify, characterizer, etc.)
global OPTS
try:
import flask_table
OPTS.datasheet_gen = 1
except:
OPTS.datasheet_gen = 0
def init_openram(config_file, is_unit_test=True):
"""Initialize the technology, paths, simulators, etc."""

View File

@ -76,7 +76,6 @@ class replica_bitline(design.design):
self.access_tx_offset = vector(-gap_width-self.access_tx.width-self.inv.width, 0.5*self.inv.height)
def add_modules(self):
""" Add the modules for later usage """
@ -184,19 +183,14 @@ class replica_bitline(design.design):
pin = self.rbl_inst.get_pin(wl)
# Route the connection to the right so that it doesn't interfere with the cells
# Wordlines may be close to each other when tiled, so gnd connections are routed in opposite directions
if row % 2 == 0:
vertical_extension = vector(0, 1.5*drc("minwidth_metal1") + 0.5*contact.m1m2.height)
else:
vertical_extension = vector(0, -1.5*drc("minwidth_metal1") - 1.5*contact.m1m2.height)
# Wordlines may be close to each other when tiled, so gnd connections are routed in opposite directions
pin_right = pin.rc()
pin_extension1 = pin_right + vector(self.m3_pitch,0)
pin_extension2 = pin_extension1 + vertical_extension
pin_extension = pin_right + vector(self.m3_pitch,0)
if pin.layer != "metal1":
continue
self.add_path("metal1", [pin_right, pin_extension1, pin_extension2])
self.add_power_pin("gnd", pin_extension2)
self.add_path("metal1", [pin_right, pin_extension])
self.add_power_pin("gnd", pin_extension)
# for multiport, need to short wordlines to each other so they all connect to gnd
wl_last = self.wl_list[self.total_ports-1]+"_{}".format(row)
@ -280,7 +274,7 @@ class replica_bitline(design.design):
# DRAIN ROUTE
# Route the drain to the vdd rail
drain_offset = self.tx_inst.get_pin("D").center()
self.add_power_pin("vdd", drain_offset)
self.add_power_pin("vdd", drain_offset, rotate=0)
# SOURCE ROUTE
# Route the drain to the RBL inverter input

View File

@ -39,7 +39,9 @@ import verify
from sram import sram
from sram_config import sram_config
#from parser import *
output_extensions = ["sp","v","lib","html"]
output_extensions = ["sp","v","lib"]
if OPTS.datasheet_gen:
output_extensions.append("html")
if not OPTS.netlist_only:
output_extensions.extend(["gds","lef"])
output_files = ["{0}.{1}".format(OPTS.output_name,x) for x in output_extensions]

View File

@ -99,6 +99,26 @@ def write_netgen_script(cell_name, sp_name):
f.close()
os.system("chmod u+x {}".format(run_file))
setup_file = OPTS.openram_temp + "setup.tcl"
f = open(setup_file, "w")
f.write("ignore class c\n")
f.write("equate class {{nfet {0}.spice}} {{n {1}}}\n".format(cell_name, sp_name))
f.write("equate class {{pfet {0}.spice}} {{p {1}}}\n".format(cell_name, sp_name))
# This circuit has symmetries and needs to be flattened to resolve them or the banks won't pass
# Is there a more elegant way to add this when needed?
f.write("flatten class {{{0}.spice bitcell_array}}\n".format(cell_name))
f.write("flatten class {{{0}.spice precharge_array_1}}\n".format(cell_name))
f.write("flatten class {{{0}.spice precharge_array_2}}\n".format(cell_name))
f.write("flatten class {{{0}.spice precharge_array_3}}\n".format(cell_name))
f.write("flatten class {{{0}.spice precharge_array_4}}\n".format(cell_name))
f.write("property {{nfet {0}.spice}} remove as ad ps pd\n".format(cell_name))
f.write("property {{pfet {0}.spice}} remove as ad ps pd\n".format(cell_name))
f.write("property {{n {0}}} remove as ad ps pd\n".format(sp_name))
f.write("property {{p {0}}} remove as ad ps pd\n".format(sp_name))
f.write("permute transistors\n")
f.write("permute pins n source drain\n")
f.write("permute pins p source drain\n")
f.close()
def run_drc(cell_name, gds_name, extract=False, final_verification=False):
"""Run DRC check on a cell which is implemented in gds_name."""