mirror of https://github.com/VLSIDA/OpenRAM.git
Merge branch 'dev' into supply_routing
This commit is contained in:
commit
7591f25a2e
12
README.md
12
README.md
|
|
@ -7,8 +7,8 @@ https://github.com/mguthaus/OpenRAM/blob/master/OpenRAM_ICCAD_2016_presentation.
|
||||||
The OpenRAM compiler has very few dependencies:
|
The OpenRAM compiler has very few dependencies:
|
||||||
* ngspice-26 (or later) or HSpice I-2013.12-1 (or later) or CustomSim 2017 (or later)
|
* ngspice-26 (or later) or HSpice I-2013.12-1 (or later) or CustomSim 2017 (or later)
|
||||||
* Python 3.5 and higher
|
* Python 3.5 and higher
|
||||||
* Python numpy
|
* Python numpy (pip3 install numpy)
|
||||||
* flask_table
|
* flask_table (pip3 install flask)
|
||||||
* a setup script for each technology
|
* a setup script for each technology
|
||||||
* a technology directory for each technology with the base cells
|
* 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:
|
If you are using SCMOS, you should install Magic and netgen from:
|
||||||
http://opencircuitdesign.com/magic/
|
http://opencircuitdesign.com/magic/
|
||||||
http://opencircuitdesign.com/netgen/
|
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/
|
http://opencircuitdesign.com/qflow/
|
||||||
|
|
||||||
# DIRECTORY STRUCTURE
|
# DIRECTORY STRUCTURE
|
||||||
|
|
@ -65,7 +65,7 @@ We have included the SCN3ME design rules from QFlow:
|
||||||
* compiler/tests - unit tests
|
* compiler/tests - unit tests
|
||||||
* technology - openram technology directory (pointed to by OPENRAM_TECH)
|
* technology - openram technology directory (pointed to by OPENRAM_TECH)
|
||||||
* technology/freepdk45 - example configuration library for freepdk45 technology node
|
* 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
|
* technology/setup_scripts - setup scripts to customize your PDKs and OpenRAM technologies
|
||||||
* docs - LaTeX manual (likely outdated)
|
* docs - LaTeX manual (likely outdated)
|
||||||
* lib - IP library of pregenerated memories
|
* 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
|
python tests/00_code_format_check_test.py -v -t freepdk45
|
||||||
```
|
```
|
||||||
To specify a particular technology use "-t <techname>" such as
|
To specify a particular technology use "-t <techname>" such as
|
||||||
"-t scn3me_subm". The default for a unit test is freepdk45 whereas
|
"-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.
|
The default for openram.py is specified in the configuration file.
|
||||||
|
|
||||||
|
|
||||||
# CREATING CUSTOM TECHNOLOGIES
|
# CREATING CUSTOM TECHNOLOGIES
|
||||||
|
|
|
||||||
|
|
@ -222,9 +222,9 @@ class pbitcell(design.design):
|
||||||
self.rowline_spacing = self.m1_space + contact.m1m2.width
|
self.rowline_spacing = self.m1_space + contact.m1m2.width
|
||||||
|
|
||||||
# spacing for vdd
|
# spacing for vdd
|
||||||
vdd_offset_well_constraint = self.well_enclose_active + 0.5*contact.well.width
|
implant_constraint = max(inverter_pmos_contact_extension, 0) + 2*self.implant_enclose_active + 0.5*(contact.well.width - self.m1_width)
|
||||||
vdd_offset_metal1_constraint = max(inverter_pmos_contact_extension, 0) + self.m1_space + 0.5*contact.well.width
|
metal1_constraint = max(inverter_pmos_contact_extension, 0) + self.m1_space
|
||||||
self.vdd_offset = max(vdd_offset_well_constraint, vdd_offset_metal1_constraint)
|
self.vdd_offset = max(implant_constraint, metal1_constraint) + 0.5*self.m1_width
|
||||||
|
|
||||||
# read port dimensions
|
# read port dimensions
|
||||||
width_reduction = self.read_nmos.active_width - self.read_nmos.get_pin("D").cx()
|
width_reduction = self.read_nmos.active_width - self.read_nmos.get_pin("D").cx()
|
||||||
|
|
@ -334,7 +334,7 @@ class pbitcell(design.design):
|
||||||
layer="metal1",
|
layer="metal1",
|
||||||
offset=self.gnd_position,
|
offset=self.gnd_position,
|
||||||
width=self.width,
|
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
|
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)
|
self.vdd_position = vector(0, vdd_ypos)
|
||||||
|
|
@ -342,7 +342,7 @@ class pbitcell(design.design):
|
||||||
layer="metal1",
|
layer="metal1",
|
||||||
offset=self.vdd_position,
|
offset=self.vdd_position,
|
||||||
width=self.width,
|
width=self.width,
|
||||||
height=contact.well.second_layer_width)
|
height=self.m1_width)
|
||||||
|
|
||||||
def create_readwrite_ports(self):
|
def create_readwrite_ports(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -933,8 +933,9 @@ class pbitcell(design.design):
|
||||||
|
|
||||||
def route_rbc_short(self):
|
def route_rbc_short(self):
|
||||||
""" route the short from Q_bar to gnd necessary for the replica bitcell """
|
""" route the short from Q_bar to gnd necessary for the replica bitcell """
|
||||||
Q_bar_pos = self.inverter_pmos_right.get_pin("S").uc()
|
Q_bar_pos = self.inverter_pmos_right.get_pin("S").center()
|
||||||
vdd_pos = vector(Q_bar_pos.x, self.vdd_position.y)
|
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])
|
self.add_path("metal1", [Q_bar_pos, vdd_pos])
|
||||||
|
|
||||||
|
|
@ -526,15 +526,15 @@ class lib:
|
||||||
|
|
||||||
for (corner, lib_name) in zip(self.corners, self.lib_files):
|
for (corner, lib_name) in zip(self.corners, self.lib_files):
|
||||||
|
|
||||||
ports = ""
|
# ports = ""
|
||||||
if OPTS.num_rw_ports>0:
|
# if OPTS.num_rw_ports>0:
|
||||||
ports += "{}_".format(OPTS.num_rw_ports)
|
# ports += "{}_".format(OPTS.num_rw_ports)
|
||||||
if OPTS.num_w_ports>0:
|
# if OPTS.num_w_ports>0:
|
||||||
ports += "{}_".format(OPTS.num_w_ports)
|
# ports += "{}_".format(OPTS.num_w_ports)
|
||||||
if OPTS.num_r_ports>0:
|
# if OPTS.num_r_ports>0:
|
||||||
ports += "{}_".format(OPTS.num_r_ports)
|
# 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_words,
|
||||||
OPTS.num_banks,
|
OPTS.num_banks,
|
||||||
OPTS.num_rw_ports,
|
OPTS.num_rw_ports,
|
||||||
|
|
@ -546,7 +546,8 @@ class lib:
|
||||||
self.corner[0],
|
self.corner[0],
|
||||||
round_time(self.char_sram_results["min_period"]),
|
round_time(self.char_sram_results["min_period"]),
|
||||||
self.out_dir,
|
self.out_dir,
|
||||||
lib_name))
|
lib_name,
|
||||||
|
OPTS.word_size))
|
||||||
|
|
||||||
|
|
||||||
datasheet.close()
|
datasheet.close()
|
||||||
|
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
|
|
@ -3,10 +3,14 @@ from operating_conditions import *
|
||||||
from characterization_corners import *
|
from characterization_corners import *
|
||||||
from deliverables import *
|
from deliverables import *
|
||||||
from timing_and_current_data import *
|
from timing_and_current_data import *
|
||||||
|
from in_out import *
|
||||||
|
import os
|
||||||
|
from globals import OPTS
|
||||||
|
|
||||||
class datasheet():
|
class datasheet():
|
||||||
|
|
||||||
def __init__(self,identifier):
|
def __init__(self,identifier):
|
||||||
|
self.io = []
|
||||||
self.corners = []
|
self.corners = []
|
||||||
self.timing = []
|
self.timing = []
|
||||||
self.operating = []
|
self.operating = []
|
||||||
|
|
@ -14,6 +18,7 @@ class datasheet():
|
||||||
self.name = identifier
|
self.name = identifier
|
||||||
self.html = ""
|
self.html = ""
|
||||||
|
|
||||||
|
|
||||||
def generate_html(self):
|
def generate_html(self):
|
||||||
self.html = """<style>
|
self.html = """<style>
|
||||||
#data {
|
#data {
|
||||||
|
|
@ -40,16 +45,25 @@ class datasheet():
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
</style>"""
|
</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;>'+ 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;>{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('<','<').replace('"','"').replace('>',">")
|
||||||
|
|
||||||
self.html +='<p style=font-size: 20px;font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;>Operating Conditions</p>'
|
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 += 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 += '<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 += 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 += '<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 += 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 +='<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('<','<').replace('"','"').replace('>',">")
|
self.html += deliverables(self.dlv,table_id='data').__html__().replace('<','<').replace('"','"').replace('>',">")
|
||||||
|
|
||||||
|
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" />'
|
||||||
|
|
|
||||||
|
|
@ -8,17 +8,24 @@ Locate all timing elements in .lib
|
||||||
Diagram generation
|
Diagram generation
|
||||||
Improve css
|
Improve css
|
||||||
"""
|
"""
|
||||||
|
import debug
|
||||||
import os, math
|
|
||||||
import optparse
|
|
||||||
from flask_table import *
|
|
||||||
import csv
|
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
from deliverables import *
|
|
||||||
from operating_conditions import *
|
if OPTS.datasheet_gen:
|
||||||
from timing_and_current_data import *
|
import flask_table
|
||||||
from characterization_corners import *
|
import os, math
|
||||||
from datasheet import *
|
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):
|
def process_name(corner):
|
||||||
if corner == "TT":
|
if corner == "TT":
|
||||||
|
|
@ -43,12 +50,13 @@ def parse_file(f,pages):
|
||||||
NUM_W_PORTS = row[4]
|
NUM_W_PORTS = row[4]
|
||||||
NUM_R_PORTS = row[5]
|
NUM_R_PORTS = row[5]
|
||||||
TECH_NAME = row[6]
|
TECH_NAME = row[6]
|
||||||
TEMP = row[7]
|
TEMP = row[8]
|
||||||
VOLT = row[8]
|
VOLT = row[7]
|
||||||
PROC = row[9]
|
PROC = row[9]
|
||||||
MIN_PERIOD = row[10]
|
MIN_PERIOD = row[10]
|
||||||
OUT_DIR = row[11]
|
OUT_DIR = row[11]
|
||||||
LIB_NAME = row[12]
|
LIB_NAME = row[12]
|
||||||
|
WORD_SIZE = row[13]
|
||||||
for sheet in pages:
|
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('Power supply (VDD) range',VOLT,VOLT,VOLT,'Volts'))
|
||||||
new_sheet.operating.append(operating_conditions_item('Operating Temperature',TEMP,TEMP,TEMP,'Celsius'))
|
new_sheet.operating.append(operating_conditions_item('Operating Temperature',TEMP,TEMP,TEMP,'Celsius'))
|
||||||
try:
|
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:
|
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('.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('.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('.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('.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.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():
|
class datasheet_gen():
|
||||||
def datasheet_write(name):
|
def datasheet_write(name):
|
||||||
|
|
||||||
in_dir = OPTS.openram_temp
|
if OPTS.datasheet_gen:
|
||||||
|
in_dir = OPTS.openram_temp
|
||||||
|
|
||||||
if not (os.path.isdir(in_dir)):
|
if not (os.path.isdir(in_dir)):
|
||||||
os.mkdir(in_dir)
|
os.mkdir(in_dir)
|
||||||
|
|
||||||
#if not (os.path.isdir(out_dir)):
|
#if not (os.path.isdir(out_dir)):
|
||||||
# os.mkdir(out_dir)
|
# os.mkdir(out_dir)
|
||||||
|
|
||||||
datasheets = []
|
datasheets = []
|
||||||
parse_file(in_dir + "/datasheet.info", datasheets)
|
parse_file(in_dir + "/datasheet.info", datasheets)
|
||||||
|
|
||||||
|
|
||||||
for sheets in datasheets:
|
for sheets in datasheets:
|
||||||
with open(name, 'w+') as f:
|
with open(name, 'w+') as f:
|
||||||
sheets.generate_html()
|
sheets.generate_html()
|
||||||
f.write(sheets.html)
|
f.write(sheets.html)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -103,6 +103,14 @@ def check_versions():
|
||||||
|
|
||||||
# FIXME: Check versions of other tools here??
|
# FIXME: Check versions of other tools here??
|
||||||
# or, this could be done in each module (e.g. verify, characterizer, etc.)
|
# 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):
|
def init_openram(config_file, is_unit_test=True):
|
||||||
"""Initialize the technology, paths, simulators, etc."""
|
"""Initialize the technology, paths, simulators, etc."""
|
||||||
|
|
|
||||||
|
|
@ -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)
|
self.access_tx_offset = vector(-gap_width-self.access_tx.width-self.inv.width, 0.5*self.inv.height)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def add_modules(self):
|
def add_modules(self):
|
||||||
""" Add the modules for later usage """
|
""" Add the modules for later usage """
|
||||||
|
|
||||||
|
|
@ -185,18 +184,13 @@ class replica_bitline(design.design):
|
||||||
|
|
||||||
# Route the connection to the right so that it doesn't interfere with the cells
|
# 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
|
# 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)
|
|
||||||
|
|
||||||
pin_right = pin.rc()
|
pin_right = pin.rc()
|
||||||
pin_extension1 = pin_right + vector(self.m3_pitch,0)
|
pin_extension = pin_right + vector(self.m3_pitch,0)
|
||||||
pin_extension2 = pin_extension1 + vertical_extension
|
|
||||||
if pin.layer != "metal1":
|
if pin.layer != "metal1":
|
||||||
continue
|
continue
|
||||||
self.add_path("metal1", [pin_right, pin_extension1, pin_extension2])
|
self.add_path("metal1", [pin_right, pin_extension])
|
||||||
self.add_power_pin("gnd", pin_extension2)
|
self.add_power_pin("gnd", pin_extension)
|
||||||
|
|
||||||
# for multiport, need to short wordlines to each other so they all connect to gnd
|
# 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)
|
wl_last = self.wl_list[self.total_ports-1]+"_{}".format(row)
|
||||||
|
|
@ -280,7 +274,7 @@ class replica_bitline(design.design):
|
||||||
# DRAIN ROUTE
|
# DRAIN ROUTE
|
||||||
# Route the drain to the vdd rail
|
# Route the drain to the vdd rail
|
||||||
drain_offset = self.tx_inst.get_pin("D").center()
|
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
|
# SOURCE ROUTE
|
||||||
# Route the drain to the RBL inverter input
|
# Route the drain to the RBL inverter input
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,9 @@ import verify
|
||||||
from sram import sram
|
from sram import sram
|
||||||
from sram_config import sram_config
|
from sram_config import sram_config
|
||||||
#from parser import *
|
#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:
|
if not OPTS.netlist_only:
|
||||||
output_extensions.extend(["gds","lef"])
|
output_extensions.extend(["gds","lef"])
|
||||||
output_files = ["{0}.{1}".format(OPTS.output_name,x) for x in output_extensions]
|
output_files = ["{0}.{1}".format(OPTS.output_name,x) for x in output_extensions]
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,26 @@ def write_netgen_script(cell_name, sp_name):
|
||||||
f.close()
|
f.close()
|
||||||
os.system("chmod u+x {}".format(run_file))
|
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):
|
def run_drc(cell_name, gds_name, extract=False, final_verification=False):
|
||||||
"""Run DRC check on a cell which is implemented in gds_name."""
|
"""Run DRC check on a cell which is implemented in gds_name."""
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue