This commit is contained in:
Matt Guthaus 2018-07-05 16:27:49 -07:00
commit 3260468477
81 changed files with 1657 additions and 461 deletions

6
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,6 @@
freepdk45:
script: "/home/gitlab-runner/regress_freepdk45.sh"
scn3me_subm:
script: "/home/gitlab-runner/regress_scn3me_subm.sh"

View File

@ -6,7 +6,7 @@ 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 2.7 and higher (currently excludes Python 3 and up)
* Python 3.5 and higher
* Python numpy
* a setup script for each technology
* a technology directory for each technology with the base cells
@ -28,6 +28,10 @@ For example, in csh/tcsh, add to your .cshrc/.tcshrc:
setenv OPENRAM_HOME "$HOME/OpenRAM/compiler"
setenv OPENRAM_TECH "$HOME/OpenRAM/technology"
```
We include the tech files necessary for FreePDK and SCMOS. The SCMOS
spice models, however, are generic and should be replaced with foundry
models.
If you are using FreePDK, you should also have that set up and have the
environment variable point to the PDK.
For example, in bash, add to your .bashrc:
@ -44,13 +48,16 @@ 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/
In addition, you will need to install the MOSIS SCMOS rules for scn3me_subm
that are part of QFlow:
We have included the SCN3ME design rules from QFlow:
http://opencircuitdesign.com/qflow/
# DIRECTORY STRUCTURE
* compiler - openram compiler itself (pointed to by OPENRAM_HOME)
* compiler/base - base data structure modules
* compiler/pgates - parameterized cells (e.g. logic gates)
* compiler/modules - high-level modules (e.g. decoders, etc.)
* compiler/verify - DRC and LVS verification wrappers
* compiler/characterizer - timing characterization code
* compiler/gdsMill - GDSII reader/writer
* compiler/router - detailed router
@ -59,6 +66,8 @@ that are part of QFlow:
* technology/freepdk45 - example configuration library for freepdk45 technology node
* technology/scn3me_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
# UNIT TESTS
@ -232,3 +241,4 @@ ui().importCds("default",
When you import a gds file, make sure to attach the correct tech lib
or you will get incorrect layers in the resulting library.
TEST

View File

@ -40,10 +40,12 @@ class design(hierarchy_spice.spice, hierarchy_layout.layout):
'hierarchical_predecode3x8']
if name not in design.name_map:
design.name_map.append(name)
elif self.__class__.__name__ in ok_list:
pass
else:
debug.error("Duplicate layout reference name {0} of class {1}. GDS2 requires names be unique.".format(name,self.__class__),-1)
for ok_names in ok_list:
if ok_names in self.__class__.__name__:
break
else:
debug.error("Duplicate layout reference name {0} of class {1}. GDS2 requires names be unique.".format(name,self.__class__),-1)
def setup_drc_constants(self):
""" These are some DRC constants used in many places in the compiler."""

View File

@ -8,7 +8,7 @@ def relative_compare(value1,value2,error_tolerance=0.001):
return (abs(value1 - value2) / max(value1,value2) <= error_tolerance)
def parse_output(filename, key):
def parse_spice_list(filename, key):
"""Parses a hspice output.lis file for a key value"""
if OPTS.spice_name == "xa" :
# customsim has a different output file name
@ -22,6 +22,7 @@ def parse_output(filename, key):
except IOError:
debug.error("Unable to open spice output file: {0}".format(full_filename),1)
contents = f.read()
f.close()
# val = re.search(r"{0}\s*=\s*(-?\d+.?\d*\S*)\s+.*".format(key), contents)
val = re.search(r"{0}\s*=\s*(-?\d+.?\d*[e]?[-+]?[0-9]*\S*)\s+.*".format(key), contents)

View File

@ -339,16 +339,16 @@ class delay():
# Checking from not data_value to data_value
self.write_delay_stimulus()
self.stim.run_sim()
delay_hl = parse_output("timing", "delay_hl")
delay_lh = parse_output("timing", "delay_lh")
slew_hl = parse_output("timing", "slew_hl")
slew_lh = parse_output("timing", "slew_lh")
delay_hl = parse_spice_list("timing", "delay_hl")
delay_lh = parse_spice_list("timing", "delay_lh")
slew_hl = parse_spice_list("timing", "slew_hl")
slew_lh = parse_spice_list("timing", "slew_lh")
delays = (delay_hl, delay_lh, slew_hl, slew_lh)
read0_power=parse_output("timing", "read0_power")
write0_power=parse_output("timing", "write0_power")
read1_power=parse_output("timing", "read1_power")
write1_power=parse_output("timing", "write1_power")
read0_power=parse_spice_list("timing", "read0_power")
write0_power=parse_spice_list("timing", "write0_power")
read1_power=parse_spice_list("timing", "read1_power")
write1_power=parse_spice_list("timing", "write1_power")
if not self.check_valid_delays(delays):
return (False,{})
@ -378,13 +378,13 @@ class delay():
self.write_power_stimulus(trim=False)
self.stim.run_sim()
leakage_power=parse_output("timing", "leakage_power")
leakage_power=parse_spice_list("timing", "leakage_power")
debug.check(leakage_power!="Failed","Could not measure leakage power.")
self.write_power_stimulus(trim=True)
self.stim.run_sim()
trim_leakage_power=parse_output("timing", "leakage_power")
trim_leakage_power=parse_spice_list("timing", "leakage_power")
debug.check(trim_leakage_power!="Failed","Could not measure leakage power.")
# For debug, you sometimes want to inspect each simulation.
@ -473,10 +473,10 @@ class delay():
# Checking from not data_value to data_value
self.write_delay_stimulus()
self.stim.run_sim()
delay_hl = parse_output("timing", "delay_hl")
delay_lh = parse_output("timing", "delay_lh")
slew_hl = parse_output("timing", "slew_hl")
slew_lh = parse_output("timing", "slew_lh")
delay_hl = parse_spice_list("timing", "delay_hl")
delay_lh = parse_spice_list("timing", "delay_lh")
slew_hl = parse_spice_list("timing", "slew_hl")
slew_lh = parse_spice_list("timing", "slew_lh")
# if it failed or the read was longer than a period
if type(delay_hl)!=float or type(delay_lh)!=float or type(slew_lh)!=float or type(slew_hl)!=float:
debug.info(2,"Invalid measures: Period {0}, delay_hl={1}ns, delay_lh={2}ns slew_hl={3}ns slew_lh={4}ns".format(self.period,

View File

@ -186,8 +186,8 @@ class setup_hold():
target_time=feasible_bound,
correct_value=correct_value)
self.stim.run_sim()
ideal_clk_to_q = convert_to_float(parse_output("timing", "clk2q_delay"))
setuphold_time = convert_to_float(parse_output("timing", "setup_hold_time"))
ideal_clk_to_q = convert_to_float(parse_spice_list("timing", "clk2q_delay"))
setuphold_time = convert_to_float(parse_spice_list("timing", "setup_hold_time"))
debug.info(2,"*** {0} CHECK: {1} Ideal Clk-to-Q: {2} Setup/Hold: {3}".format(mode, correct_value,ideal_clk_to_q,setuphold_time))
if type(ideal_clk_to_q)!=float or type(setuphold_time)!=float:
@ -219,8 +219,8 @@ class setup_hold():
self.stim.run_sim()
clk_to_q = convert_to_float(parse_output("timing", "clk2q_delay"))
setuphold_time = convert_to_float(parse_output("timing", "setup_hold_time"))
clk_to_q = convert_to_float(parse_spice_list("timing", "clk2q_delay"))
setuphold_time = convert_to_float(parse_spice_list("timing", "setup_hold_time"))
if type(clk_to_q)==float and (clk_to_q<1.1*ideal_clk_to_q) and type(setuphold_time)==float:
if mode == "SETUP": # SETUP is clk-din, not din-clk
setuphold_time *= -1e9

View File

@ -17,6 +17,7 @@ class trim_spice():
# Load the file into a buffer for performance
sp = open(self.sp_file, "r")
self.spice = sp.readlines()
sp.close()
for i in range(len(self.spice)):
self.spice[i] = self.spice[i].rstrip(" \n")
@ -97,6 +98,7 @@ class trim_spice():
# Finally, write out the buffer as the new reduced file
sp = open(self.reduced_spfile, "w")
sp.write("\n".join(self.sp_buffer))
sp.close()
def remove_insts(self, subckt_name, keep_inst_list):

View File

@ -89,11 +89,13 @@ def print_banner():
def check_versions():
""" Run some checks of required software versions. """
# Now require python >=3.6
# Now require python >=3.5
major_python_version = sys.version_info.major
minor_python_version = sys.version_info.minor
if not (major_python_version == 3 and minor_python_version >= 6):
debug.error("Python 3.6 or greater is required.",-1)
major_required = 3
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.)

View File

@ -11,7 +11,7 @@ class bitcell(design.design):
library.
"""
pin_names = ["BL", "BR", "WL", "vdd", "gnd"]
pin_names = ["bl", "br", "wl", "vdd", "gnd"]
(width,height) = utils.get_libcell_size("cell_6t", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "cell_6t", GDS["unit"], layer["boundary"])
@ -34,7 +34,59 @@ class bitcell(design.design):
c_para = spice["min_tx_drain_c"]
result = self.cal_delay_with_rc(r = r, c = c_para+load, slew = slew, swing = swing)
return result
def list_bitcell_pins(self, col, row):
""" Creates a list of connections in the bitcell, indexed by column and row, for instance use in bitcell_array """
bitcell_pins = ["bl[{0}]".format(col),
"br[{0}]".format(col),
"wl[{0}]".format(row),
"vdd",
"gnd"]
return bitcell_pins
def list_row_pins(self):
""" Creates a list of all row pins (except for gnd and vdd) """
row_pins = ["wl"]
return row_pins
def list_read_row_pins(self):
""" Creates a list of row pins associated with read ports """
row_pins = ["wl"]
return row_pins
def list_write_row_pins(self):
""" Creates a list of row pins associated with write ports """
row_pins = ["wl"]
return row_pins
def list_column_pins(self):
""" Creates a list of all column pins (except for gnd and vdd) """
column_pins = ["bl", "br"]
return column_pins
def list_read_column_pins(self):
""" Creates a list of column pins associated with read ports """
column_pins = ["bl"]
return column_pins
def list_read_bar_column_pins(self):
""" Creates a list of column pins associated with read_bar ports """
column_pins = ["br"]
return column_pins
def list_write_column_pins(self):
""" Creates a list of column pins associated with write ports """
column_pins = ["bl"]
return column_pins
def list_write_bar_column_pins(self):
""" Creates a list of column pins asscociated with write_bar ports"""
column_pins = ["br"]
return column_pins
def analytical_power(self, proc, vdd, temp, load):
"""Bitcell power in nW. Only characterizes leakage."""
from tech import spice
@ -42,3 +94,4 @@ class bitcell(design.design):
dynamic = 0 #temporary
total_power = self.return_power(dynamic, leakage)
return total_power

View File

@ -1,204 +1,202 @@
import debug
import design
from tech import drc, spice
from vector import vector
from globals import OPTS
class bitcell_array(design.design):
"""
Creates a rows x cols array of memory cells. Assumes bit-lines
and word line is connected by abutment.
Connects the word lines and bit lines.
"""
def __init__(self, cols, rows, name="bitcell_array"):
design.design.__init__(self, name)
debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols))
self.column_size = cols
self.row_size = rows
from importlib import reload
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.cell = self.mod_bitcell()
self.add_mod(self.cell)
# We increase it by a well enclosure so the precharges don't overlap our wells
self.height = self.row_size*self.cell.height + drc["well_enclosure_active"] + self.m1_width
self.width = self.column_size*self.cell.width + self.m1_width
self.add_pins()
self.create_layout()
self.add_layout_pins()
# We don't offset this because we need to align
# the replica bitcell in the control logic
#self.offset_all_coordinates()
self.DRC_LVS()
def add_pins(self):
for col in range(self.column_size):
self.add_pin("bl[{0}]".format(col))
self.add_pin("br[{0}]".format(col))
for row in range(self.row_size):
self.add_pin("wl[{0}]".format(row))
self.add_pin("vdd")
self.add_pin("gnd")
def create_layout(self):
xoffset = 0.0
self.cell_inst = {}
for col in range(self.column_size):
yoffset = 0.0
for row in range(self.row_size):
name = "bit_r{0}_c{1}".format(row, col)
if row % 2:
tempy = yoffset + self.cell.height
dir_key = "MX"
else:
tempy = yoffset
dir_key = ""
self.cell_inst[row,col]=self.add_inst(name=name,
mod=self.cell,
offset=[xoffset, tempy],
mirror=dir_key)
self.connect_inst(["bl[{0}]".format(col),
"br[{0}]".format(col),
"wl[{0}]".format(row),
"vdd",
"gnd"])
yoffset += self.cell.height
xoffset += self.cell.width
def add_layout_pins(self):
""" Add the layout pins """
offset = vector(0.0, 0.0)
for col in range(self.column_size):
# get the pin of the lower row cell and make it the full width
bl_pin = self.cell_inst[0,col].get_pin("BL")
br_pin = self.cell_inst[0,col].get_pin("BR")
self.add_layout_pin(text="bl[{0}]".format(col),
layer="metal2",
offset=bl_pin.ll(),
width=bl_pin.width(),
height=self.height)
self.add_layout_pin(text="br[{0}]".format(col),
layer="metal2",
offset=br_pin.ll(),
width=br_pin.width(),
height=self.height)
# increments to the next column width
offset.x += self.cell.width
offset.x = 0.0
for row in range(self.row_size):
wl_pin = self.cell_inst[row,0].get_pin("WL")
self.add_layout_pin(text="wl[{0}]".format(row),
layer="metal1",
offset=wl_pin.ll(),
width=self.width,
height=wl_pin.height())
# increments to the next row height
offset.y += self.cell.height
# For every second row and column, add a via for vdd
for row in range(self.row_size):
for col in range(self.column_size):
inst = self.cell_inst[row,col]
for vdd_pin in inst.get_pins("vdd"):
# Drop to M1 if needed
if vdd_pin.layer == "metal1":
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=vdd_pin.center(),
rotate=90)
# Always drop to M2
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=vdd_pin.center())
self.add_layout_pin_rect_center(text="vdd",
layer="metal3",
offset=vdd_pin.center())
# For every second row and column (+1), add a via for gnd
for row in range(self.row_size):
for col in range(self.column_size):
inst = self.cell_inst[row,col]
for gnd_pin in inst.get_pins("gnd"):
# Drop to M1 if needed
if gnd_pin.layer == "metal1":
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=gnd_pin.center(),
rotate=90)
# Always drop to M2
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=gnd_pin.center())
self.add_layout_pin_rect_center(text="gnd",
layer="metal3",
offset=gnd_pin.center())
def analytical_delay(self, slew, load=0):
from tech import drc
wl_wire = self.gen_wl_wire()
wl_wire.return_delay_over_wire(slew)
wl_to_cell_delay = wl_wire.return_delay_over_wire(slew)
# hypothetical delay from cell to bl end without sense amp
bl_wire = self.gen_bl_wire()
cell_load = 2 * bl_wire.return_input_cap() # we ingore the wire r
# hence just use the whole c
bl_swing = 0.1
cell_delay = self.cell.analytical_delay(wl_to_cell_delay.slew, cell_load, swing = bl_swing)
#we do not consider the delay over the wire for now
return self.return_delay(cell_delay.delay+wl_to_cell_delay.delay,
wl_to_cell_delay.slew)
def analytical_power(self, proc, vdd, temp, load):
"""Power of Bitcell array and bitline in nW."""
from tech import drc
# Dynamic Power from Bitline
bl_wire = self.gen_bl_wire()
cell_load = 2 * bl_wire.return_input_cap()
bl_swing = 0.1 #This should probably be defined in the tech file or input
freq = spice["default_event_rate"]
bitline_dynamic = bl_swing*cell_load*vdd*vdd*freq #not sure if calculation is correct
#Calculate the bitcell power which currently only includes leakage
cell_power = self.cell.analytical_power(proc, vdd, temp, load)
#Leakage power grows with entire array and bitlines.
total_power = self.return_power(cell_power.dynamic + bitline_dynamic * self.column_size,
cell_power.leakage * self.column_size * self.row_size)
return total_power
def gen_wl_wire(self):
wl_wire = self.generate_rc_net(int(self.column_size), self.width, drc["minwidth_metal1"])
wl_wire.wire_c = 2*spice["min_tx_gate_c"] + wl_wire.wire_c # 2 access tx gate per cell
return wl_wire
def gen_bl_wire(self):
bl_pos = 0
bl_wire = self.generate_rc_net(int(self.row_size-bl_pos), self.height, drc["minwidth_metal1"])
bl_wire.wire_c =spice["min_tx_drain_c"] + bl_wire.wire_c # 1 access tx d/s per cell
return bl_wire
def output_load(self, bl_pos=0):
bl_wire = self.gen_bl_wire()
return bl_wire.wire_c # sense amp only need to charge small portion of the bl
# set as one segment for now
def input_load(self):
wl_wire = self.gen_wl_wire()
return wl_wire.return_input_cap()
import debug
import design
from tech import drc, spice
from vector import vector
from globals import OPTS
class bitcell_array(design.design):
"""
Creates a rows x cols array of memory cells. Assumes bit-lines
and word line is connected by abutment.
Connects the word lines and bit lines.
"""
def __init__(self, cols, rows, name="bitcell_array"):
design.design.__init__(self, name)
debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols))
self.column_size = cols
self.row_size = rows
from importlib import reload
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.cell = self.mod_bitcell()
self.add_mod(self.cell)
# We increase it by a well enclosure so the precharges don't overlap our wells
self.height = self.row_size*self.cell.height + drc["well_enclosure_active"] + self.m1_width
self.width = self.column_size*self.cell.width + self.m1_width
self.add_pins()
self.create_layout()
self.add_layout_pins()
# We don't offset this because we need to align
# the replica bitcell in the control logic
#self.offset_all_coordinates()
self.DRC_LVS()
def add_pins(self):
row_list = self.cell.list_row_pins()
column_list = self.cell.list_column_pins()
for col in range(self.column_size):
for cell_column in column_list:
self.add_pin(cell_column+"[{0}]".format(col))
for row in range(self.row_size):
for cell_row in row_list:
self.add_pin(cell_row+"[{0}]".format(row))
self.add_pin("vdd")
self.add_pin("gnd")
def create_layout(self):
xoffset = 0.0
self.cell_inst = {}
for col in range(self.column_size):
yoffset = 0.0
for row in range(self.row_size):
name = "bit_r{0}_c{1}".format(row, col)
if row % 2:
tempy = yoffset + self.cell.height
dir_key = "MX"
else:
tempy = yoffset
dir_key = ""
self.cell_inst[row,col]=self.add_inst(name=name,
mod=self.cell,
offset=[xoffset, tempy],
mirror=dir_key)
self.connect_inst(self.cell.list_bitcell_pins(col, row))
yoffset += self.cell.height
xoffset += self.cell.width
def add_layout_pins(self):
""" Add the layout pins """
row_list = self.cell.list_row_pins()
column_list = self.cell.list_column_pins()
offset = vector(0.0, 0.0)
for col in range(self.column_size):
for cell_column in column_list:
bl_pin = self.cell_inst[0,col].get_pin(cell_column)
self.add_layout_pin(text=cell_column+"[{0}]".format(col),
layer="metal2",
offset=bl_pin.ll(),
width=bl_pin.width(),
height=self.height)
# increments to the next column width
offset.x += self.cell.width
offset.x = 0.0
for row in range(self.row_size):
for cell_row in row_list:
wl_pin = self.cell_inst[row,0].get_pin(cell_row)
self.add_layout_pin(text=cell_row+"[{0}]".format(row),
layer="metal1",
offset=wl_pin.ll(),
width=self.width,
height=wl_pin.height())
# increments to the next row height
offset.y += self.cell.height
# For every second row and column, add a via for vdd
for row in range(self.row_size):
for col in range(self.column_size):
inst = self.cell_inst[row,col]
for vdd_pin in inst.get_pins("vdd"):
# Drop to M1 if needed
if vdd_pin.layer == "metal1":
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=vdd_pin.center(),
rotate=90)
# Always drop to M2
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=vdd_pin.center())
self.add_layout_pin_rect_center(text="vdd",
layer="metal3",
offset=vdd_pin.center())
# For every second row and column (+1), add a via for gnd
for row in range(self.row_size):
for col in range(self.column_size):
inst = self.cell_inst[row,col]
for gnd_pin in inst.get_pins("gnd"):
# Drop to M1 if needed
if gnd_pin.layer == "metal1":
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=gnd_pin.center(),
rotate=90)
# Always drop to M2
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=gnd_pin.center())
self.add_layout_pin_rect_center(text="gnd",
layer="metal3",
offset=gnd_pin.center())
def analytical_delay(self, slew, load=0):
from tech import drc
wl_wire = self.gen_wl_wire()
wl_wire.return_delay_over_wire(slew)
wl_to_cell_delay = wl_wire.return_delay_over_wire(slew)
# hypothetical delay from cell to bl end without sense amp
bl_wire = self.gen_bl_wire()
cell_load = 2 * bl_wire.return_input_cap() # we ingore the wire r
# hence just use the whole c
bl_swing = 0.1
cell_delay = self.cell.analytical_delay(wl_to_cell_delay.slew, cell_load, swing = bl_swing)
#we do not consider the delay over the wire for now
return self.return_delay(cell_delay.delay+wl_to_cell_delay.delay,
wl_to_cell_delay.slew)
def analytical_power(self, proc, vdd, temp, load):
"""Power of Bitcell array and bitline in nW."""
from tech import drc
# Dynamic Power from Bitline
bl_wire = self.gen_bl_wire()
cell_load = 2 * bl_wire.return_input_cap()
bl_swing = 0.1 #This should probably be defined in the tech file or input
freq = spice["default_event_rate"]
bitline_dynamic = bl_swing*cell_load*vdd*vdd*freq #not sure if calculation is correct
#Calculate the bitcell power which currently only includes leakage
cell_power = self.cell.analytical_power(proc, vdd, temp, load)
#Leakage power grows with entire array and bitlines.
total_power = self.return_power(cell_power.dynamic + bitline_dynamic * self.column_size,
cell_power.leakage * self.column_size * self.row_size)
return total_power
def gen_wl_wire(self):
wl_wire = self.generate_rc_net(int(self.column_size), self.width, drc["minwidth_metal1"])
wl_wire.wire_c = 2*spice["min_tx_gate_c"] + wl_wire.wire_c # 2 access tx gate per cell
return wl_wire
def gen_bl_wire(self):
bl_pos = 0
bl_wire = self.generate_rc_net(int(self.row_size-bl_pos), self.height, drc["minwidth_metal1"])
bl_wire.wire_c =spice["min_tx_drain_c"] + bl_wire.wire_c # 1 access tx d/s per cell
return bl_wire
def output_load(self, bl_pos=0):
bl_wire = self.gen_bl_wire()
return bl_wire.wire_c # sense amp only need to charge small portion of the bl
# set as one segment for now
def input_load(self):
wl_wire = self.gen_wl_wire()
return wl_wire.return_input_cap()

View File

@ -33,9 +33,8 @@ class sense_amp_array(design.design):
def add_pins(self):
for i in range(0,self.row_size,self.words_per_row):
index = int(i/self.words_per_row)
self.add_pin("data[{0}]".format(index))
for i in range(0,self.word_size):
self.add_pin("data[{0}]".format(i))
self.add_pin("bl[{0}]".format(i))
self.add_pin("br[{0}]".format(i))
@ -55,23 +54,22 @@ class sense_amp_array(design.design):
br_pin = self.amp.get_pin("br")
dout_pin = self.amp.get_pin("dout")
for i in range(0,self.row_size,self.words_per_row):
amp_spacing = self.amp.width * self.words_per_row
for i in range(0,self.word_size):
name = "sa_d{0}".format(i)
amp_position = vector(self.amp.width * i, 0)
amp_position = vector(amp_spacing * i, 0)
bl_offset = amp_position + bl_pin.ll().scale(1,0)
br_offset = amp_position + br_pin.ll().scale(1,0)
dout_offset = amp_position + dout_pin.ll()
index = int(i/self.words_per_row)
inst = self.add_inst(name=name,
mod=self.amp,
offset=amp_position)
self.connect_inst(["bl[{0}]".format(i),
"br[{0}]".format(i),
"data[{0}]".format(index),
"data[{0}]".format(i),
"en", "vdd", "gnd"])
@ -100,7 +98,7 @@ class sense_amp_array(design.design):
width=br_pin.width(),
height=br_pin.height())
self.add_layout_pin(text="data[{0}]".format(index),
self.add_layout_pin(text="data[{0}]".format(i),
layer="metal2",
offset=dout_offset,
width=dout_pin.width(),

View File

@ -48,6 +48,7 @@ class options(optparse.Values):
# These are the configuration parameters
rw_ports = 1
r_ports = 0
w_ports = 0
# These will get initialized by the the file
supply_voltages = ""
temperatures = ""

1138
compiler/pgates/pbitcell.py Normal file

File diff suppressed because it is too large Load Diff

View File

@ -82,12 +82,12 @@ class precharge(pgate.pgate):
"""Adds both the upper_pmos and lower_pmos to the module"""
# adds the lower pmos to layout
#base = vector(self.width - 2*self.pmos.width + self.overlap_offset.x, 0)
self.lower_pmos_position = vector(self.bitcell.get_pin("BL").lx(),
self.lower_pmos_position = vector(self.bitcell.get_pin("bl").lx(),
self.pmos.active_offset.y)
self.lower_pmos_inst=self.add_inst(name="lower_pmos",
mod=self.pmos,
offset=self.lower_pmos_position)
self.connect_inst(["bl", "en", "BR", "vdd"])
self.connect_inst(["bl", "en", "br", "vdd"])
# adds the upper pmos(s) to layout
ydiff = self.pmos.height + 2*self.m1_space + contact.poly.width
@ -159,7 +159,7 @@ class precharge(pgate.pgate):
def add_bitlines(self):
"""Adds both bit-line and bit-line-bar to the module"""
# adds the BL on metal 2
offset = vector(self.bitcell.get_pin("BL").cx(),0) - vector(0.5 * self.m2_width,0)
offset = vector(self.bitcell.get_pin("bl").cx(),0) - vector(0.5 * self.m2_width,0)
self.add_layout_pin(text="bl",
layer="metal2",
offset=offset,
@ -167,7 +167,7 @@ class precharge(pgate.pgate):
height=self.height)
# adds the BR on metal 2
offset = vector(self.bitcell.get_pin("BR").cx(),0) - vector(0.5 * self.m2_width,0)
offset = vector(self.bitcell.get_pin("br").cx(),0) - vector(0.5 * self.m2_width,0)
self.add_layout_pin(text="br",
layer="metal2",
offset=offset,

View File

@ -31,7 +31,7 @@ class single_level_column_mux(design.design):
self.add_ptx()
self.pin_height = 2*self.m2_width
self.width = self.bitcell.width
self.height = self.nmos2.uy() + self.pin_height
self.height = self.nmos_upper.uy() + self.pin_height
self.connect_poly()
self.add_bitline_pins()
self.connect_bitlines()
@ -40,8 +40,8 @@ class single_level_column_mux(design.design):
def add_bitline_pins(self):
""" Add the top and bottom pins to this cell """
bl_pos = vector(self.bitcell.get_pin("BL").lx(), 0)
br_pos = vector(self.bitcell.get_pin("BR").lx(), 0)
bl_pos = vector(self.bitcell.get_pin("bl").lx(), 0)
br_pos = vector(self.bitcell.get_pin("br").lx(), 0)
# bl and br
self.add_layout_pin(text="bl",
@ -67,32 +67,32 @@ class single_level_column_mux(design.design):
def add_ptx(self):
""" Create the two pass gate NMOS transistors to switch the bitlines"""
# Adds nmos1,nmos2 to the module
# Adds nmos_lower,nmos_upper to the module
self.nmos = ptx(width=self.ptx_width)
self.add_mod(self.nmos)
# Space it in the center
nmos1_position = self.nmos.active_offset.scale(0,1) + vector(0.5*self.bitcell.width-0.5*self.nmos.active_width,0)
self.nmos1=self.add_inst(name="mux_tx1",
nmos_lower_position = self.nmos.active_offset.scale(0,1) + vector(0.5*self.bitcell.width-0.5*self.nmos.active_width,0)
self.nmos_lower=self.add_inst(name="mux_tx1",
mod=self.nmos,
offset=nmos1_position)
offset=nmos_lower_position)
self.connect_inst(["bl", "sel", "bl_out", "gnd"])
# This aligns it directly above the other tx with gates abutting
nmos2_position = nmos1_position + vector(0,self.nmos.active_height + self.poly_space)
self.nmos2=self.add_inst(name="mux_tx2",
nmos_upper_position = nmos_lower_position + vector(0,self.nmos.active_height + self.poly_space)
self.nmos_upper=self.add_inst(name="mux_tx2",
mod=self.nmos,
offset=nmos2_position)
offset=nmos_upper_position)
self.connect_inst(["br", "sel", "br_out", "gnd"])
def connect_poly(self):
""" Connect the poly gate of the two pass transistors """
height=self.nmos2.get_pin("G").uy() - self.nmos1.get_pin("G").by()
height=self.nmos_upper.get_pin("G").uy() - self.nmos_lower.get_pin("G").by()
self.add_layout_pin(text="sel",
layer="poly",
offset=self.nmos1.get_pin("G").ll(),
offset=self.nmos_lower.get_pin("G").ll(),
height=height)
@ -105,36 +105,36 @@ class single_level_column_mux(design.design):
br_out_pin = self.get_pin("br_out")
# These are on metal1
nmos1_s_pin = self.nmos1.get_pin("S")
nmos1_d_pin = self.nmos1.get_pin("D")
nmos2_s_pin = self.nmos2.get_pin("S")
nmos2_d_pin = self.nmos2.get_pin("D")
nmos_lower_s_pin = self.nmos_lower.get_pin("S")
nmos_lower_d_pin = self.nmos_lower.get_pin("D")
nmos_upper_s_pin = self.nmos_upper.get_pin("S")
nmos_upper_d_pin = self.nmos_upper.get_pin("D")
# Add vias to bl, br_out, nmos2/S, nmos1/D
# Add vias to bl, br_out, nmos_upper/S, nmos_lower/D
self.add_via_center(layers=("metal1","via1","metal2"),
offset=bl_pin.bc())
self.add_via_center(layers=("metal1","via1","metal2"),
offset=br_out_pin.uc())
self.add_via_center(layers=("metal1","via1","metal2"),
offset=nmos2_s_pin.center())
offset=nmos_upper_s_pin.center())
self.add_via_center(layers=("metal1","via1","metal2"),
offset=nmos1_d_pin.center())
offset=nmos_lower_d_pin.center())
# bl -> nmos2/D on metal1
# bl_out -> nmos2/S on metal2
self.add_path("metal1",[bl_pin.ll(), vector(nmos2_d_pin.cx(),bl_pin.by()), nmos2_d_pin.center()])
# bl -> nmos_upper/D on metal1
# bl_out -> nmos_upper/S on metal2
self.add_path("metal1",[bl_pin.ll(), vector(nmos_upper_d_pin.cx(),bl_pin.by()), nmos_upper_d_pin.center()])
# halfway up, move over
mid1 = bl_out_pin.uc().scale(1,0.5)+nmos2_s_pin.bc().scale(0,0.5)
mid2 = bl_out_pin.uc().scale(0,0.5)+nmos2_s_pin.bc().scale(1,0.5)
self.add_path("metal2",[bl_out_pin.uc(), mid1, mid2, nmos2_s_pin.bc()])
mid1 = bl_out_pin.uc().scale(1,0.5)+nmos_upper_s_pin.bc().scale(0,0.5)
mid2 = bl_out_pin.uc().scale(0,0.5)+nmos_upper_s_pin.bc().scale(1,0.5)
self.add_path("metal2",[bl_out_pin.uc(), mid1, mid2, nmos_upper_s_pin.bc()])
# br -> nmos1/D on metal2
# br_out -> nmos1/S on metal1
self.add_path("metal1",[br_out_pin.uc(), vector(nmos1_s_pin.cx(),br_out_pin.uy()), nmos1_s_pin.center()])
# br -> nmos_lower/D on metal2
# br_out -> nmos_lower/S on metal1
self.add_path("metal1",[br_out_pin.uc(), vector(nmos_lower_s_pin.cx(),br_out_pin.uy()), nmos_lower_s_pin.center()])
# halfway up, move over
mid1 = br_pin.bc().scale(1,0.5)+nmos1_d_pin.uc().scale(0,0.5)
mid2 = br_pin.bc().scale(0,0.5)+nmos1_d_pin.uc().scale(1,0.5)
self.add_path("metal2",[br_pin.bc(), mid1, mid2, nmos1_d_pin.uc()])
mid1 = br_pin.bc().scale(1,0.5)+nmos_lower_d_pin.uc().scale(0,0.5)
mid2 = br_pin.bc().scale(0,0.5)+nmos_lower_d_pin.uc().scale(1,0.5)
self.add_path("metal2",[br_pin.bc(), mid1, mid2, nmos_lower_d_pin.uc()])
def add_wells(self):
@ -144,11 +144,11 @@ class single_level_column_mux(design.design):
"""
# Add it to the right, aligned in between the two tx
active_pos = self.nmos2.lr().scale(0,0.5) + self.nmos1.ur().scale(1,0.5)
self.add_via_center(layers=("active", "contact", "metal1"),
offset=active_pos,
implant_type="p",
well_type="p")
active_pos = vector(self.bitcell.width,self.nmos_upper.by())
active_via = self.add_via_center(layers=("active", "contact", "metal1"),
offset=active_pos,
implant_type="p",
well_type="p")
# Add the M1->M2->M3 stack
@ -159,6 +159,12 @@ class single_level_column_mux(design.design):
self.add_layout_pin_rect_center(text="gnd",
layer="metal3",
offset=active_pos)
# Add well enclosure over all the tx and contact
self.add_rect(layer="pwell",
offset=vector(0,0),
width=self.bitcell.width,
height=self.height)

View File

@ -1,154 +0,0 @@
#!/usr/bin/env python2.7
"Run a regresion test on a basic parameterized transistors"
import unittest
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
from globals import OPTS
import debug
class ptx_test(unittest.TestCase):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
OPTS.check_lvsdrc = False
import ptx
import tech
debug.info(2, "Checking three fingers PMOS")
fet = ptx.ptx(width=tech.drc["minwidth_tx"],
mults=4,
tx_type="pmos",
connect_active=True,
connect_poly=True)
self.local_check(fet)
OPTS.check_lvsdrc = True
globals.end_openram()
def add_mods(self, fet):
self.create_contacts()
self.add_well_extension(fet)
self.add_wire_extension(fet)
self.add_well_tiedown(fet)
self.add_poly_tiedown(fet)
def create_contacts(self):
layer_stack = ("active", "contact", "metal1")
self.well_contact = contact.contact(layer_stack)
layer_stack = ("poly", "contact", "metal1")
self.poly_contact = contact.contact(layer_stack)
def add_well_tiedown(self, fet):
offset = [fet.active_contact_positions[0][0],
fet.active_contact_positions[0][1] + fet.well_height]
fet.add_inst(name="well_tap",
mod=self.well_contact,
offset=offset,
mirror="R0",
rotate=0)
fet.well_contact = self.well_contact
fet.well_tiedown_location = offset
def add_well_extension(self, fet):
well_define = {"pmos": "nwell",
"nmos": "pwell"}
well_type = well_define[fet.tx_type]
offset = getattr(fet,"{}_position".format(well_type))
if tech.info["has_{0}".format(well_type)]:
fet.add_rect(layerNumber=tech.layer[well_type],
offset=offset,
width=fet.well_width,
height=2 * fet.well_height)
fet.add_rect(layerNumber=tech.layer["{0}implant".format(fet.tx_type[0])],
offset=offset,
width=fet.well_width,
height=2 * fet.well_height)
fet.add_rect(layerNumber=tech.layer["vtg"],
offset=offset,
width=fet.well_width,
height=2 * fet.well_height)
well_type = "{0}well".format(fet.tx_type[0])
offset[1] = offset[1] - 3 * fet.well_height
if tech.info["has_{0}".format(well_type)]:
fet.add_rect(layerNumber=tech.layer[well_type],
offset=offset,
width=fet.well_width,
height=3 * fet.well_height)
fet.add_rect(layerNumber=tech.layer["{0}implant".format(well_define[fet.tx_type][
0])],
offset=offset,
width=fet.well_width,
height=3 * fet.well_height)
fet.add_rect(layerNumber=tech.layer["vtg"],
offset=offset,
width=fet.well_width,
height=3 * fet.well_height)
def add_wire_extension(self, fet):
xcorrect = (fet.active_contact.width / 2) - (tech.drc["minwidth_metal1"] / 2)
offset = [fet.active_contact_positions[0][0] + xcorrect,
fet.active_contact_positions[0][1]]
fet.add_rect(layerNumber=tech.layer["metal1"],
offset=offset,
width=tech.drc["minwidth_metal1"],
height=fet.well_height)
offset = [fet.active_contact_positions[-1][0] + xcorrect,
fet.active_contact_positions[-1][1] - 2 * fet.well_height]
fet.add_rect(layerNumber=tech.layer["metal1"],
offset=offset,
width=tech.drc["minwidth_metal1"],
height=2 * fet.well_height)
offset = [fet.poly_positions[-1][0],
fet.poly_positions[-1][1] - (fet.well_height)]
fet.add_rect(layerNumber=tech.layer["poly"],
offset=offset,
width=tech.drc["minwidth_poly"],
height=fet.well_height)
def add_poly_tiedown(self, fet):
xcorrect = abs(self.poly_contact.upper_layer_vertical_enclosure -
self.poly_contact.lower_layer_vertical_enclosure)
offset = [fet.poly_positions[-1][0] - xcorrect,
fet.poly_positions[-1][1] - (fet.well_height)]
fet.add_inst(name="poly_contact",
mod=self.poly_contact,
offset=offset,
mirror="R270")
offset = [fet.active_contact_positions[-1][0], fet.active_contact_positions
[-1][1] - 2 * fet.well_height - self.well_contact.height]
fet.poly_tiedown_location = offset
fet.add_inst(name="n_tiedown",
mod=self.well_contact,
offset=offset)
tech.ptx_port.add_custom_layer(fet)
def local_check(self, fet):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
fet.sp_write(tempspice)
fet.gds_write(tempgds)
self.assertFalse(verify.run_drc(fet.name, tempgds))
os.remove(tempspice)
os.remove(tempgds)
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()

0
compiler/tests/00_code_format_check_test.py Normal file → Executable file
View File

0
compiler/tests/01_library_drc_test.py Normal file → Executable file
View File

0
compiler/tests/02_library_lvs_test.py Normal file → Executable file
View File

0
compiler/tests/03_contact_test.py Normal file → Executable file
View File

0
compiler/tests/03_path_test.py Normal file → Executable file
View File

0
compiler/tests/03_ptx_1finger_nmos_test.py Normal file → Executable file
View File

0
compiler/tests/03_ptx_1finger_pmos_test.py Normal file → Executable file
View File

0
compiler/tests/03_ptx_3finger_nmos_test.py Normal file → Executable file
View File

0
compiler/tests/03_ptx_3finger_pmos_test.py Normal file → Executable file
View File

0
compiler/tests/03_ptx_4finger_nmos_test.py Normal file → Executable file
View File

0
compiler/tests/03_ptx_4finger_pmos_test.py Normal file → Executable file
View File

0
compiler/tests/03_wire_test.py Normal file → Executable file
View File

View File

@ -0,0 +1,80 @@
#!/usr/bin/env python2.7
"""
Run regresion tests on a parameterized bitcell
"""
import unittest
from testutils import header,openram_test
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
from globals import OPTS
import debug
OPTS = globals.OPTS
#@unittest.skip("SKIPPING 04_pbitcell_test")
class pbitcell_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
OPTS.check_lvsdrc = False
import pbitcell
import tech
debug.info(2, "Bitcell with 1 of each port: read/write, write, and read")
tx = pbitcell.pbitcell(num_readwrite=1,num_write=1,num_read=1)
self.local_check(tx)
debug.info(2, "Bitcell with 0 read/write ports")
tx = pbitcell.pbitcell(num_readwrite=0,num_write=1,num_read=1)
self.local_check(tx)
debug.info(2, "Bitcell with 0 write ports")
tx = pbitcell.pbitcell(num_readwrite=1,num_write=0,num_read=1)
self.local_check(tx)
debug.info(2, "Bitcell with 0 read ports")
tx = pbitcell.pbitcell(num_readwrite=1,num_write=1,num_read=0)
self.local_check(tx)
debug.info(2, "Bitcell with 0 read ports and 0 write ports")
tx = pbitcell.pbitcell(num_readwrite=1,num_write=0,num_read=0)
self.local_check(tx)
debug.info(2, "Bitcell with 2 of each port: read/write, write, and read")
tx = pbitcell.pbitcell(num_readwrite=2,num_write=2,num_read=2)
self.local_check(tx)
debug.info(2, "Bitcell with 0 read/write ports")
tx = pbitcell.pbitcell(num_readwrite=0,num_write=2,num_read=2)
self.local_check(tx)
debug.info(2, "Bitcell with 0 write ports")
tx = pbitcell.pbitcell(num_readwrite=2,num_write=0,num_read=2)
self.local_check(tx)
debug.info(2, "Bitcell with 0 read ports")
tx = pbitcell.pbitcell(num_readwrite=2,num_write=2,num_read=0)
self.local_check(tx)
debug.info(2, "Bitcell with 0 read ports and 0 write ports")
tx = pbitcell.pbitcell(num_readwrite=2,num_write=0,num_read=0)
self.local_check(tx)
OPTS.check_lvsdrc = True
globals.end_openram()
OPTS.bitcell = "bitcell"
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()

0
compiler/tests/04_pinv_10x_test.py Normal file → Executable file
View File

0
compiler/tests/04_pinv_1x_beta_test.py Normal file → Executable file
View File

0
compiler/tests/04_pinv_1x_test.py Normal file → Executable file
View File

0
compiler/tests/04_pinv_2x_test.py Normal file → Executable file
View File

0
compiler/tests/04_pinvbuf_test.py Normal file → Executable file
View File

0
compiler/tests/04_pnand2_test.py Normal file → Executable file
View File

0
compiler/tests/04_pnand3_test.py Normal file → Executable file
View File

0
compiler/tests/04_pnor2_test.py Normal file → Executable file
View File

0
compiler/tests/04_precharge_test.py Normal file → Executable file
View File

0
compiler/tests/04_single_level_column_mux_test.py Normal file → Executable file
View File

0
compiler/tests/05_bitcell_array_test.py Normal file → Executable file
View File

View File

@ -0,0 +1,53 @@
#!/usr/bin/env python3
"""
Run a regression test on a basic array
"""
import unittest
from testutils import header,openram_test
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
from globals import OPTS
import debug
#@unittest.skip("SKIPPING 05_array_multiport_test")
class array_multiport_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
OPTS.check_lvsdrc = False
import bitcell_array
OPTS.bitcell = "pbitcell"
OPTS.rw_ports = 2
OPTS.r_ports = 2
OPTS.w_ports = 2
debug.info(2, "Testing 4x4 array for multiport bitcell, with read ports at the edge of the bit cell")
a = bitcell_array.bitcell_array(name="pbitcell_array", cols=4, rows=4)
self.local_check(a)
OPTS.rw_ports = 2
OPTS.r_ports = 0
OPTS.w_ports = 2
debug.info(2, "Testing 4x4 array for multiport bitcell, with read/write ports at the edge of the bit cell")
a = bitcell_array.bitcell_array(name="pbitcell_array", cols=4, rows=4)
self.local_check(a)
OPTS.bitcell = "bitcell"
OPTS.check_lvsdrc = True
globals.end_openram()
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()

0
compiler/tests/06_hierarchical_decoder_test.py Normal file → Executable file
View File

0
compiler/tests/06_hierarchical_predecode2x4_test.py Normal file → Executable file
View File

0
compiler/tests/06_hierarchical_predecode3x8_test.py Normal file → Executable file
View File

View File

0
compiler/tests/08_precharge_array_test.py Normal file → Executable file
View File

0
compiler/tests/08_wordline_driver_test.py Normal file → Executable file
View File

0
compiler/tests/09_sense_amp_array_test.py Normal file → Executable file
View File

0
compiler/tests/10_write_driver_array_test.py Normal file → Executable file
View File

0
compiler/tests/11_dff_array_test.py Normal file → Executable file
View File

0
compiler/tests/11_dff_buf_array_test.py Normal file → Executable file
View File

0
compiler/tests/11_dff_buf_test.py Normal file → Executable file
View File

0
compiler/tests/11_dff_inv_array_test.py Normal file → Executable file
View File

0
compiler/tests/11_dff_inv_test.py Normal file → Executable file
View File

0
compiler/tests/11_ms_flop_array_test.py Normal file → Executable file
View File

0
compiler/tests/12_tri_gate_array_test.py Normal file → Executable file
View File

0
compiler/tests/13_delay_chain_test.py Normal file → Executable file
View File

0
compiler/tests/14_replica_bitline_test.py Normal file → Executable file
View File

0
compiler/tests/16_control_logic_test.py Normal file → Executable file
View File

0
compiler/tests/19_bank_select_test.py Normal file → Executable file
View File

0
compiler/tests/19_multi_bank_test.py Normal file → Executable file
View File

0
compiler/tests/19_single_bank_test.py Normal file → Executable file
View File

0
compiler/tests/20_sram_1bank_test.py Normal file → Executable file
View File

0
compiler/tests/20_sram_2bank_test.py Normal file → Executable file
View File

0
compiler/tests/20_sram_4bank_test.py Normal file → Executable file
View File

2
compiler/tests/21_hspice_delay_test.py Normal file → Executable file
View File

@ -45,7 +45,7 @@ class timing_sram_test(openram_test):
debug.info(1, "Probe address {0} probe data {1}".format(probe_address, probe_data))
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
d = delay.delay(s,tempspice,corner)
d = delay(s,tempspice,corner)
import tech
loads = [tech.spice["msflop_in_cap"]*4]
slews = [tech.spice["rise_time"]*2]

2
compiler/tests/21_hspice_setuphold_test.py Normal file → Executable file
View File

@ -33,7 +33,7 @@ class timing_setup_test(openram_test):
slews = [tech.spice["rise_time"]*2]
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
sh = setup_hold.setup_hold(corner)
sh = setup_hold(corner)
data = sh.analyze(slews,slews)
#print data
if OPTS.tech_name == "freepdk45":

2
compiler/tests/21_ngspice_delay_test.py Normal file → Executable file
View File

@ -43,7 +43,7 @@ class timing_sram_test(openram_test):
debug.info(1, "Probe address {0} probe data {1}".format(probe_address, probe_data))
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
d = delay.delay(s,tempspice,corner)
d = delay(s,tempspice,corner)
import tech
loads = [tech.spice["msflop_in_cap"]*4]
slews = [tech.spice["rise_time"]*2]

2
compiler/tests/21_ngspice_setuphold_test.py Normal file → Executable file
View File

@ -32,7 +32,7 @@ class timing_setup_test(openram_test):
slews = [tech.spice["rise_time"]*2]
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
sh = setup_hold.setup_hold(corner)
sh = setup_hold(corner)
data = sh.analyze(slews,slews)
#print data
if OPTS.tech_name == "freepdk45":

0
compiler/tests/22_sram_func_test.py Normal file → Executable file
View File

2
compiler/tests/23_lib_sram_model_test.py Normal file → Executable file
View File

@ -30,7 +30,7 @@ class lib_test(openram_test):
tempspice = OPTS.openram_temp + "temp.sp"
s.sp_write(tempspice)
lib.lib(out_dir=OPTS.openram_temp, sram=s, sp_file=tempspice, use_model=True)
lib(out_dir=OPTS.openram_temp, sram=s, sp_file=tempspice, use_model=True)
# get all of the .lib files generated
files = os.listdir(OPTS.openram_temp)

2
compiler/tests/23_lib_sram_prune_test.py Normal file → Executable file
View File

@ -40,7 +40,7 @@ class lib_test(openram_test):
tempspice = OPTS.openram_temp + "temp.sp"
s.sp_write(tempspice)
lib.lib(out_dir=OPTS.openram_temp, sram=s, sp_file=tempspice, use_model=False)
lib(out_dir=OPTS.openram_temp, sram=s, sp_file=tempspice, use_model=False)
# get all of the .lib files generated
files = os.listdir(OPTS.openram_temp)

2
compiler/tests/23_lib_sram_test.py Normal file → Executable file
View File

@ -40,7 +40,7 @@ class lib_test(openram_test):
tempspice = OPTS.openram_temp + "temp.sp"
s.sp_write(tempspice)
lib.lib(out_dir=OPTS.openram_temp, sram=s, sp_file=tempspice, use_model=False)
lib(out_dir=OPTS.openram_temp, sram=s, sp_file=tempspice, use_model=False)
# get all of the .lib files generated
files = os.listdir(OPTS.openram_temp)

0
compiler/tests/24_lef_sram_test.py Normal file → Executable file
View File

0
compiler/tests/25_verilog_sram_test.py Normal file → Executable file
View File

0
compiler/tests/30_openram_test.py Normal file → Executable file
View File

View File

@ -91,25 +91,25 @@ class openram_test(unittest.TestCase):
import re
import debug
numeric_const_pattern = r"""
[-+]? # optional sign
(?:
(?: \d* \. \d+ ) # .1 .12 .123 etc 9.1 etc 98.1 etc
|
(?: \d+ \.? ) # 1. 12. 123. etc 1 12 123 etc
)
# followed by optional exponent part if desired
(?: [Ee] [+-]? \d+ ) ?
"""
rx = re.compile(numeric_const_pattern, re.VERBOSE)
with open(f1, 'rb') as fp1, open(f2, 'rb') as fp2:
while True:
b1 = fp1.readline()
b2 = fp2.readline()
b1 = fp1.readline().decode('utf-8')
b2 = fp2.readline().decode('utf-8')
#print "b1:",b1,
#print "b2:",b2,
# 1. Find all of the floats using a regex
numeric_const_pattern = r"""
[-+]? # optional sign
(?:
(?: \d* \. \d+ ) # .1 .12 .123 etc 9.1 etc 98.1 etc
|
(?: \d+ \.? ) # 1. 12. 123. etc 1 12 123 etc
)
# followed by optional exponent part if desired
(?: [Ee] [+-]? \d+ ) ?
"""
rx = re.compile(numeric_const_pattern, re.VERBOSE)
b1_floats=rx.findall(b1)
b2_floats=rx.findall(b2)
debug.info(3,"b1_floats: "+str(b1_floats))
@ -117,9 +117,9 @@ class openram_test(unittest.TestCase):
# 2. Remove the floats from the string
for f in b1_floats:
b1=b1.replace(str(f),"",1)
b1=b1.replace(f,"",1)
for f in b2_floats:
b2=b2.replace(str(f),"",1)
b2=b2.replace(f,"",1)
#print "b1:",b1,
#print "b2:",b2,

View File

@ -89,7 +89,7 @@ def run_drc(cell_name, gds_name):
# write the runset file
f = open(OPTS.openram_temp + "drc_runset", "w")
for k in sorted(drc_runset.iterkeys()):
for k in sorted(iter(drc_runset.keys())):
f.write("*{0}: {1}\n".format(k, drc_runset[k]))
f.close()
@ -177,7 +177,7 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
# write the runset file
f = open(OPTS.openram_temp + "lvs_runset", "w")
for k in sorted(lvs_runset.iterkeys()):
for k in sorted(iter(lvs_runset.keys())):
f.write("*{0}: {1}\n".format(k, lvs_runset[k]))
f.close()
@ -286,7 +286,7 @@ def run_pex(cell_name, gds_name, sp_name, output=None):
# write the runset file
f = open(OPTS.openram_temp + "pex_runset", "w")
for k in sorted(pex_runset.iterkeys()):
for k in sorted(iter(pex_runset.keys())):
f.write("*{0}: {1}\n".format(k, pex_runset[k]))
f.close()