Merge multiport

This commit is contained in:
Matt Guthaus 2018-10-08 11:45:50 -07:00
commit a2b1d025ab
182 changed files with 2437 additions and 4307755 deletions

View File

@ -18,6 +18,7 @@ class design(hierarchy_design):
hierarchy_design.__init__(self,name)
self.setup_drc_constants()
self.setup_multiport_constants()
self.m1_pitch = max(contact.m1m2.width,contact.m1m2.height) + max(self.m1_space, self.m2_space)
self.m2_pitch = max(contact.m2m3.width,contact.m2m3.height) + max(self.m2_space, self.m3_space)
@ -45,7 +46,35 @@ class design(hierarchy_design):
self.contact_to_gate = drc["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"]
self.implant_space = drc["implant_to_implant"]
def setup_multiport_constants(self):
""" These are contants and lists that aid multiport design """
self.total_write = OPTS.num_rw_ports + OPTS.num_w_ports
self.total_read = OPTS.num_rw_ports + OPTS.num_r_ports
self.total_ports = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports
self.num_rw_ports = OPTS.num_rw_ports
# Port indices used for data, address, and control signals
# Port IDs used to identify port type
self.write_index = []
self.read_index = []
self.port_id = []
port_number = 0
for port in range(OPTS.num_rw_ports):
self.write_index.append(port_number)
self.read_index.append(port_number)
self.port_id.append("rw")
port_number += 1
for port in range(OPTS.num_w_ports):
self.write_index.append(port_number)
self.port_id.append("w")
port_number += 1
for port in range(OPTS.num_r_ports):
self.read_index.append(port_number)
self.port_id.append("r")
port_number += 1
def analytical_power(self, proc, vdd, temp, load):
""" Get total power of a module """

View File

@ -123,7 +123,8 @@ class layout(lef.lef):
"""Adds an instance of a mod to this module"""
self.insts.append(geometry.instance(name, mod, offset, mirror, rotate))
debug.info(3, "adding instance {}".format(self.insts[-1]))
debug.info(4, "instance list: " + ",".join(x.name for x in self.insts))
# This is commented out for runtime reasons
#debug.info(4, "instance list: " + ",".join(x.name for x in self.insts))
return self.insts[-1]
def get_inst(self, name):

View File

@ -12,14 +12,19 @@ class pbitcell(design.design):
with a variable number of read/write, write, and read ports
"""
def __init__(self):
def __init__(self, replica_bitcell=False):
self.num_rw_ports = OPTS.num_rw_ports
self.num_w_ports = OPTS.num_w_ports
self.num_r_ports = OPTS.num_r_ports
self.total_ports = self.num_rw_ports + self.num_w_ports + self.num_r_ports
name = "pbitcell_{0}RW_{1}W_{2}R".format(self.num_rw_ports, self.num_w_ports, self.num_r_ports)
self.replica_bitcell = replica_bitcell
if self.replica_bitcell:
name = "replica_pbitcell_{0}RW_{1}W_{2}R".format(self.num_rw_ports, self.num_w_ports, self.num_r_ports)
else:
name = "pbitcell_{0}RW_{1}W_{2}R".format(self.num_rw_ports, self.num_w_ports, self.num_r_ports)
# This is not a pgate because pgates depend on the bitcell height!
design.design.__init__(self, name)
debug.info(2, "create a multi-port bitcell with {0} rw ports, {1} w ports and {2} r ports".format(self.num_rw_ports,
@ -30,7 +35,7 @@ class pbitcell(design.design):
# We must always create the bitcell layout because
# some transistor sizes in the other netlists depend on it
self.create_layout()
def create_netlist(self):
self.add_pins()
@ -70,7 +75,13 @@ class pbitcell(design.design):
self.route_read_access()
self.extend_well()
self.offset_all_coordinates()
if self.replica_bitcell:
self.route_rbc_short()
# in netlist_only mode, calling offset_all_coordinates will not be possible
# this function is not needed to calculate the dimensions of pbitcell in netlist_only mode though
if not OPTS.netlist_only:
self.offset_all_coordinates()
self.DRC_LVS()
def add_pins(self):
@ -121,6 +132,11 @@ class pbitcell(design.design):
self.add_pin("vdd")
self.add_pin("gnd")
if self.replica_bitcell:
self.Q_bar = "vdd"
else:
self.Q_bar = "Q_bar"
def add_modules(self):
"""
@ -229,6 +245,10 @@ class pbitcell(design.design):
# calculation for row line tiling
self.rail_tile_height = drc["active_to_body_active"] + contact.well.width
if self.inverter_pmos_contact_extension > 0:
self.vdd_tile_height = self.inverter_pmos_contact_extension + drc["minwidth_metal1"] + contact.well.width
else:
self.vdd_tile_height = self.rail_tile_height
self.rowline_tile_height = drc["minwidth_metal1"] + contact.m1m2.width
# calculations related to inverter connections
@ -292,7 +312,7 @@ class pbitcell(design.design):
# topmost position = height of the inverter + height of vdd
self.topmost_ypos = self.inverter_nmos.active_height + self.inverter_gap + self.inverter_pmos.active_height \
+ self.rail_tile_height
+ self.vdd_tile_height
# calculations for the cell dimensions
array_vdd_overlap = 0.5*contact.well.width
@ -309,20 +329,20 @@ class pbitcell(design.design):
# create active for nmos
self.inverter_nmos_left = self.add_inst(name="inverter_nmos_left",
mod=self.inverter_nmos)
self.connect_inst(["Q_bar", "Q", "gnd", "gnd"])
self.connect_inst([self.Q_bar, "Q", "gnd", "gnd"])
self.inverter_nmos_right = self.add_inst(name="inverter_nmos_right",
mod=self.inverter_nmos)
self.connect_inst(["gnd", "Q_bar", "Q", "gnd"])
self.connect_inst(["gnd", self.Q_bar, "Q", "gnd"])
# create active for pmos
self.inverter_pmos_left = self.add_inst(name="inverter_pmos_left",
mod=self.inverter_pmos)
self.connect_inst(["Q_bar", "Q", "vdd", "vdd"])
self.connect_inst([self.Q_bar, "Q", "vdd", "vdd"])
self.inverter_pmos_right = self.add_inst(name="inverter_pmos_right",
mod=self.inverter_pmos)
self.connect_inst(["vdd", "Q_bar", "Q", "vdd"])
self.connect_inst(["vdd", self.Q_bar, "Q", "vdd"])
def place_storage(self):
@ -343,6 +363,7 @@ class pbitcell(design.design):
self.inverter_pmos_left.place([left_inverter_xpos, inverter_pmos_ypos])
self.inverter_pmos_right.place([right_inverter_xpos, inverter_pmos_ypos])
def route_storage(self):
"""
Routes inputs and outputs of inverters to cross couple them
@ -391,13 +412,13 @@ class pbitcell(design.design):
height=contact.well.second_layer_width)
vdd_ypos = self.inverter_nmos.active_height + self.inverter_gap + self.inverter_pmos.active_height \
+ drc["active_to_body_active"] + 0.5*(drc["minwidth_tx"] - drc["minwidth_metal1"])
+ self.vdd_tile_height - contact.well.second_layer_width
self.vdd_position = vector(self.leftmost_xpos, vdd_ypos)
self.vdd = self.add_layout_pin(text="vdd",
layer="metal1",
offset=self.vdd_position,
width=self.width,
height=drc["minwidth_metal1"])
height=contact.well.second_layer_width)
# Connect inverters to rails
# connect inverter nmos to gnd
@ -438,7 +459,7 @@ class pbitcell(design.design):
self.readwrite_nmos_right[k] = self.add_inst(name="readwrite_nmos_right{}".format(k),
mod=self.readwrite_nmos)
self.connect_inst(["Q_bar", self.rw_wl_names[k], self.rw_br_names[k], "gnd"])
self.connect_inst([self.Q_bar, self.rw_wl_names[k], self.rw_br_names[k], "gnd"])
def place_readwrite_ports(self):
@ -642,7 +663,7 @@ class pbitcell(design.design):
self.write_nmos_right[k] = self.add_inst(name="write_nmos_right{}".format(k),
mod=self.write_nmos)
self.connect_inst(["Q_bar", self.w_wl_names[k], self.w_br_names[k], "gnd"])
self.connect_inst([self.Q_bar, self.w_wl_names[k], self.w_br_names[k], "gnd"])
def place_write_ports(self):
@ -845,7 +866,7 @@ class pbitcell(design.design):
# add read-access transistors
self.read_access_nmos_left[k] = self.add_inst(name="read_access_nmos_left{}".format(k),
mod=self.read_nmos)
self.connect_inst(["RA_to_R_left{}".format(k), " Q_bar", "gnd", "gnd"])
self.connect_inst(["RA_to_R_left{}".format(k), self.Q_bar, "gnd", "gnd"])
self.read_access_nmos_right[k] = self.add_inst(name="read_access_nmos_right{}".format(k),
mod=self.read_nmos)
@ -1153,7 +1174,7 @@ class pbitcell(design.design):
well_type="p")
# connect nimplants to vdd
offset = vector(0, self.vdd_position.y + 0.5*drc["minwidth_metal1"])
offset = vector(0, self.vdd_position.y + 0.5*contact.well.second_layer_width)
self.add_contact_center(layers=("active", "contact", "metal1"),
offset=offset,
rotate=90,
@ -1215,3 +1236,10 @@ class pbitcell(design.design):
""" Creates a list of br pin names asscociated with write ports"""
br_pins = self.rw_br_names + self.w_br_names
return br_pins
def route_rbc_short(self):
""" route the short from Q_bar to gnd necessary for the replica bitcell """
Q_bar_pos = self.inverter_pmos_left.get_pin("D").uc()
vdd_pos = vector(Q_bar_pos.x, self.vdd_position.y)
self.add_path("metal1", [Q_bar_pos, vdd_pos])

View File

@ -5,6 +5,8 @@ from globals import OPTS,find_exe,get_tool
from .lib import *
from .delay import *
from .setup_hold import *
from .functional import *
from .simulation import *
debug.info(1,"Initializing characterizer...")

View File

@ -34,12 +34,61 @@ class delay():
self.num_rows = self.sram.num_rows
self.num_banks = self.sram.num_banks
self.sp_file = spfile
self.total_ports = self.sram.total_ports
self.total_write = self.sram.total_write
self.total_read = self.sram.total_read
self.read_index = self.sram.read_index
self.write_index = self.sram.write_index
self.port_id = self.sram.port_id
# These are the member variables for a simulation
self.period = 0
self.set_load_slew(0,0)
self.set_corner(corner)
self.create_port_names()
self.create_signal_names()
#Create global measure names. Should maybe be an input at some point.
self.create_measurement_names()
def create_measurement_names(self):
"""Create measurement names. The names themselves currently define the type of measurement"""
#Altering the names will crash the characterizer. TODO: object orientated approach to the measurements.
self.delay_meas_names = ["delay_lh", "delay_hl", "slew_lh", "slew_hl"]
self.power_meas_names = ["read0_power", "read1_power", "write0_power", "write1_power"]
def create_signal_names(self):
self.addr_name = "A"
self.din_name = "DIN"
self.dout_name = "DOUT"
#This is TODO once multiport control has been finalized.
#self.control_name = "CSB"
def create_port_names(self):
"""Generates the port names to be used in characterization and sets default simulation target ports"""
self.write_ports = []
self.read_ports = []
self.total_port_num = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports
#save a member variable to avoid accessing global. readwrite ports have different control signals.
self.readwrite_port_num = OPTS.num_rw_ports
#Generate the port names. readwrite ports are required to be added first for this to work.
for readwrite_port_num in range(OPTS.num_rw_ports):
self.read_ports.append(readwrite_port_num)
self.write_ports.append(readwrite_port_num)
#This placement is intentional. It makes indexing input data easier. See self.data_values
for write_port_num in range(OPTS.num_rw_ports, OPTS.num_rw_ports+OPTS.num_w_ports):
self.write_ports.append(write_port_num)
for read_port_num in range(OPTS.num_rw_ports+OPTS.num_w_ports, OPTS.num_rw_ports+OPTS.num_w_ports+OPTS.num_r_ports):
self.read_ports.append(read_port_num)
#Set the default target ports for simulation. Default is all the ports.
self.targ_read_ports = self.read_ports
self.targ_write_ports = self.write_ports
def set_corner(self,corner):
""" Set the corner values """
self.corner = corner
@ -78,15 +127,16 @@ class delay():
# instantiate the sram
self.sf.write("\n* Instantiation of the SRAM\n")
self.stim.inst_sram(abits=self.addr_size,
dbits=self.word_size,
port_info=(self.total_port_num,self.readwrite_port_num,self.read_ports,self.write_ports),
self.stim.inst_sram(sram=self.sram,
port_signal_names=(self.addr_name,self.din_name,self.dout_name),
port_info=(self.total_port_num,self.write_ports,self.read_ports),
abits=self.addr_size,
dbits=self.word_size,
sram_name=self.name)
self.sf.write("\n* SRAM output loads\n")
for port in self.read_ports:
for i in range(self.word_size):
self.sf.write("CD{0}{1} DOUT{0}[{1}] 0 {2}f\n".format(port,i,self.load))
self.sf.write("CD{0}{1} {2}{0}_{1} 0 {3}f\n".format(port,i,self.dout_name,self.load))
def write_delay_stimulus(self):
@ -121,14 +171,15 @@ class delay():
self.sf.write("\n* Generation of control signals\n")
self.gen_control()
self.sf.write("\n* Generation of global clock signal\n")
self.stim.gen_pulse(sig_name="CLK",
v1=0,
v2=self.vdd_voltage,
offset=self.period,
period=self.period,
t_rise=self.slew,
t_fall=self.slew)
self.sf.write("\n* Generation of Port clock signal\n")
for port in range(self.total_port_num):
self.stim.gen_pulse(sig_name="CLK{0}".format(port),
v1=0,
v2=self.vdd_voltage,
offset=self.period,
period=self.period,
t_rise=self.slew,
t_fall=self.slew)
self.write_delay_measures()
@ -165,22 +216,23 @@ class delay():
self.sf.write("\n* Generation of data and address signals\n")
for write_port in self.write_ports:
for i in range(self.word_size):
self.stim.gen_constant(sig_name="DIN{0}[{1}] ".format(write_port, i),
self.stim.gen_constant(sig_name="{0}{1}_{2} ".format(self.din_name,write_port, i),
v_val=0)
for port in range(self.total_port_num):
for i in range(self.addr_size):
self.stim.gen_constant(sig_name="A{0}[{1}]".format(port, i),
self.stim.gen_constant(sig_name="{0}{1}_{2}".format(self.addr_name,port, i),
v_val=0)
# generate control signals
self.sf.write("\n* Generation of control signals\n")
for port in range(self.total_port_num):
self.stim.gen_constant(sig_name="CSB{0}".format(port), v_val=self.vdd_voltage)
if port in self.read_ports and port in self.write_ports:
if port in self.write_ports and port in self.read_ports:
self.stim.gen_constant(sig_name="WEB{0}".format(port), v_val=self.vdd_voltage)
self.sf.write("\n* Generation of global clock signal\n")
self.stim.gen_constant(sig_name="CLK", v_val=0)
for port in range(self.total_port_num):
self.stim.gen_constant(sig_name="CLK{0}".format(port), v_val=0)
self.write_power_measures()
@ -189,87 +241,85 @@ class delay():
self.sf.close()
def get_delay_meas_values(self, delay_name, port):
"""Get the values needed to generate a Spice measurement statement based on the name of the measurement."""
debug.check('lh' in delay_name or 'hl' in delay_name, "Measure command {0} does not contain direction (lh/hl)")
trig_clk_name = "clk{0}".format(port)
meas_name="{0}{1}".format(delay_name, port)
targ_name = "{0}".format("{0}{1}_{2}".format(self.dout_name,port,self.probe_data))
half_vdd = 0.5 * self.vdd_voltage
trig_slew_low = 0.1 * self.vdd_voltage
targ_slew_high = 0.9 * self.vdd_voltage
if 'delay' in delay_name:
trig_dir="RISE"
trig_val = half_vdd
targ_val = half_vdd
trig_name = trig_clk_name
if 'lh' in delay_name:
targ_dir="RISE"
trig_td = targ_td = self.cycle_times[self.measure_cycles["read1_{0}".format(port)]]
else:
targ_dir="FALL"
trig_td = targ_td = self.cycle_times[self.measure_cycles["read0_{0}".format(port)]]
elif 'slew' in delay_name:
trig_name = targ_name
if 'lh' in delay_name:
trig_val = trig_slew_low
targ_val = targ_slew_high
targ_dir = trig_dir = "RISE"
trig_td = targ_td = self.cycle_times[self.measure_cycles["read1_{0}".format(port)]]
else:
trig_val = targ_slew_high
targ_val = trig_slew_low
targ_dir = trig_dir = "FALL"
trig_td = targ_td = self.cycle_times[self.measure_cycles["read0_{0}".format(port)]]
else:
debug.error(1, "Measure command {0} not recognized".format(delay_name))
return (meas_name,trig_name,targ_name,trig_val,targ_val,trig_dir,targ_dir,trig_td,targ_td)
def write_delay_measures_read_port(self, port):
"""
Write the measure statements to quantify the delay and power results for a read port.
"""
# Trigger on the clk of the appropriate cycle
trig_name = "clk"
#Target name should be an input to the function or a member variable. That way, the ports can be singled out for testing
targ_name = "{0}".format("DOUT{0}[{1}]".format(port,self.probe_data))
trig_val = targ_val = 0.5 * self.vdd_voltage
# Delay the target to measure after the negative edge
self.stim.gen_meas_delay(meas_name="DELAY_HL{0}".format(port),
trig_name=trig_name,
targ_name=targ_name,
trig_val=trig_val,
targ_val=targ_val,
trig_dir="RISE",
targ_dir="FALL",
trig_td=self.cycle_times[self.measure_cycles["read0_{0}".format(port)]],
targ_td=self.cycle_times[self.measure_cycles["read0_{0}".format(port)]])
self.stim.gen_meas_delay(meas_name="DELAY_LH{0}".format(port),
trig_name=trig_name,
targ_name=targ_name,
trig_val=trig_val,
targ_val=targ_val,
trig_dir="RISE",
targ_dir="RISE",
trig_td=self.cycle_times[self.measure_cycles["read1_{0}".format(port)]],
targ_td=self.cycle_times[self.measure_cycles["read1_{0}".format(port)]])
self.stim.gen_meas_delay(meas_name="SLEW_HL{0}".format(port),
trig_name=targ_name,
targ_name=targ_name,
trig_val=0.9*self.vdd_voltage,
targ_val=0.1*self.vdd_voltage,
trig_dir="FALL",
targ_dir="FALL",
trig_td=self.cycle_times[self.measure_cycles["read0_{0}".format(port)]],
targ_td=self.cycle_times[self.measure_cycles["read0_{0}".format(port)]])
self.stim.gen_meas_delay(meas_name="SLEW_LH{0}".format(port),
trig_name=targ_name,
targ_name=targ_name,
trig_val=0.1*self.vdd_voltage,
targ_val=0.9*self.vdd_voltage,
trig_dir="RISE",
targ_dir="RISE",
trig_td=self.cycle_times[self.measure_cycles["read1_{0}".format(port)]],
targ_td=self.cycle_times[self.measure_cycles["read1_{0}".format(port)]])
# add measure statements for delays/slews
for dname in self.delay_meas_names:
meas_values = self.get_delay_meas_values(dname, port)
self.stim.gen_meas_delay(*meas_values)
# add measure statements for power
t_initial = self.cycle_times[self.measure_cycles["read0_{0}".format(port)]]
t_final = self.cycle_times[self.measure_cycles["read0_{0}".format(port)]+1]
self.stim.gen_meas_power(meas_name="READ0_POWER{0}".format(port),
t_initial=t_initial,
t_final=t_final)
t_initial = self.cycle_times[self.measure_cycles["read1_{0}".format(port)]]
t_final = self.cycle_times[self.measure_cycles["read1_{0}".format(port)]+1]
self.stim.gen_meas_power(meas_name="READ1_POWER{0}".format(port),
t_initial=t_initial,
t_final=t_final)
for pname in self.power_meas_names:
if "read" not in pname:
continue
#Different naming schemes are used for the measure cycle dict and measurement names.
#TODO: make them the same so they can be indexed the same.
if '1' in pname:
t_initial = self.cycle_times[self.measure_cycles["read1_{0}".format(port)]]
t_final = self.cycle_times[self.measure_cycles["read1_{0}".format(port)]+1]
elif '0' in pname:
t_initial = self.cycle_times[self.measure_cycles["read0_{0}".format(port)]]
t_final = self.cycle_times[self.measure_cycles["read0_{0}".format(port)]+1]
self.stim.gen_meas_power(meas_name="{0}{1}".format(pname, port),
t_initial=t_initial,
t_final=t_final)
def write_delay_measures_write_port(self, port):
"""
Write the measure statements to quantify the power results for a write port.
"""
# add measure statements for power
t_initial = self.cycle_times[self.measure_cycles["write0_{0}".format(port)]]
t_final = self.cycle_times[self.measure_cycles["write0_{0}".format(port)]+1]
self.stim.gen_meas_power(meas_name="WRITE0_POWER{0}".format(port),
t_initial=t_initial,
t_final=t_final)
t_initial = self.cycle_times[self.measure_cycles["write1_{0}".format(port)]]
t_final = self.cycle_times[self.measure_cycles["write1_{0}".format(port)]+1]
self.stim.gen_meas_power(meas_name="WRITE1_POWER{0}".format(port),
t_initial=t_initial,
t_final=t_final)
for pname in self.power_meas_names:
if "write" not in pname:
continue
t_initial = self.cycle_times[self.measure_cycles["write0_{0}".format(port)]]
t_final = self.cycle_times[self.measure_cycles["write0_{0}".format(port)]+1]
if '1' in pname:
t_initial = self.cycle_times[self.measure_cycles["write1_{0}".format(port)]]
t_final = self.cycle_times[self.measure_cycles["write1_{0}".format(port)]+1]
self.stim.gen_meas_power(meas_name="{0}{1}".format(pname, port),
t_initial=t_initial,
t_final=t_final)
def write_delay_measures(self):
"""
@ -311,8 +361,7 @@ class delay():
starting point.
"""
debug.check(port in self.read_ports, "Characterizer requires a read port to determine a period.")
#Adding this as a sanity check for editing this function later. This function assumes period has been set previously
debug.check(self.period > 0, "Initial starting period not defined")
feasible_period = float(tech.spice["feasible_period"])
#feasible_period = float(2.5)#What happens if feasible starting point is wrong?
time_out = 9
@ -334,38 +383,34 @@ class delay():
if not success:
feasible_period = 2 * feasible_period
break
feasible_delay_lh = results["delay_lh{0}".format(port)]
feasible_delay_hl = results["delay_hl{0}".format(port)]
feasible_slew_lh = results["slew_lh{0}".format(port)]
feasible_slew_hl = results["slew_hl{0}".format(port)]
delay_str = "feasible_delay {0:.4f}ns/{1:.4f}ns".format(feasible_delay_lh, feasible_delay_hl)
slew_str = "slew {0:.4f}ns/{1:.4f}ns".format(feasible_slew_lh, feasible_slew_hl)
continue
#Positions of measurements currently hardcoded. First 2 are delays, next 2 are slews
feasible_delays = [results[port][mname] for mname in self.delay_meas_names if "delay" in mname]
feasible_slews = [results[port][mname] for mname in self.delay_meas_names if "slew" in mname]
delay_str = "feasible_delay {0:.4f}ns/{1:.4f}ns".format(*feasible_delays)
slew_str = "slew {0:.4f}ns/{1:.4f}ns".format(*feasible_slews)
debug.info(2, "feasible_period passed for Port {3}: {0}ns {1} {2} ".format(feasible_period,
delay_str,
slew_str,
port))
#Add feasible delays of port to dict
#feasible_delays_lh[port] = feasible_delay_lh
#feasible_delays_hl[port] = feasible_delay_hl
if success:
debug.info(1, "Found feasible_period: {0}ns".format(feasible_period))
debug.info(2, "Found feasible_period for port {0}: {1}ns".format(port, feasible_period))
self.period = feasible_period
return (feasible_delay_lh, feasible_delay_hl)
#Only return results related to input port.
return results[port]
def find_feasible_period(self):
"""
Loops through all read ports determining the feasible period and collecting
delay information from each port.
"""
feasible_delays_lh = {}
feasible_delays_hl = {}
feasible_delays = [{} for i in range(self.total_port_num)]
self.period = float(tech.spice["feasible_period"])
#Get initial feasible period from first port
(feasible_delays_lh[0], feasible_delays_hl[0]) = self.find_feasible_period_one_port(self.read_ports[0])
#Get initial feasible delays from first port
feasible_delays[self.read_ports[0]] = self.find_feasible_period_one_port(self.read_ports[0])
previous_period = self.period
@ -374,23 +419,27 @@ class delay():
i = 1
while i < len(self.read_ports):
port = self.read_ports[i]
(feasible_delays_lh[port], feasible_delays_hl[port]) = self.find_feasible_period_one_port(port)
#Only extract port values from the specified port, not the entire results.
feasible_delays[port].update(self.find_feasible_period_one_port(port))
#Function sets the period. Restart the entire process if period changes to collect accurate delays
if self.period > previous_period:
i = 0
else:
i+=1
previous_period = self.period
return (feasible_delays_lh, feasible_delays_hl)
debug.info(1, "Found feasible_period: {0}ns".format(self.period))
return feasible_delays
def parse_values(self, values_names, mult = 1.0):
"""Parse multiple values in the timing output file. Optional multiplier."""
def parse_values(self, values_names, port, mult = 1.0):
"""Parse multiple values in the timing output file. Optional multiplier.
Return a dict of the input names and values. Port used for parsing file.
"""
values = []
all_values_floats = True
for vname in values_names:
#ngspice converts all measure characters to lowercase, not tested on other sims
value = parse_spice_list("timing", vname.lower())
value = parse_spice_list("timing", "{0}{1}".format(vname.lower(), port))
#Check if any of the values fail to parse
if type(value)!=float:
all_values_floats = False
@ -409,7 +458,10 @@ class delay():
works on the trimmed netlist by default, so powers do not
include leakage of all cells.
"""
result = {}
#Sanity Check
debug.check(self.period > 0, "Target simulation period non-positive")
result = [{} for i in range(self.total_port_num)]
# Checking from not data_value to data_value
self.write_delay_stimulus()
@ -418,29 +470,30 @@ class delay():
#Loop through all targeted ports and collect delays and powers.
#Too much duplicate code here. Try reducing
for port in self.targ_read_ports:
delay_names = ["delay_hl{0}".format(port), "delay_lh{0}".format(port),
"slew_hl{0}".format(port), "slew_lh{0}".format(port)]
delays = self.parse_values(delay_names, 1e9) # scale delays to ns
if not self.check_valid_delays((delays[delay_names[0]],delays[delay_names[1]],delays[delay_names[2]],delays[delay_names[3]])):
debug.info(2, "Check delay values for port {}".format(port))
delay_names = ["{0}{1}".format(mname,port) for mname in self.delay_meas_names]
delay_names = [mname for mname in self.delay_meas_names]
delays = self.parse_values(delay_names, port, 1e9) # scale delays to ns
if not self.check_valid_delays(tuple(delays.values())):
return (False,{})
result.update(delays)
result[port].update(delays)
power_names = ["read0_power{0}".format(port), "read1_power{0}".format(port)]
powers = self.parse_values(power_names, 1e3) # scale power to mw
power_names = [mname for mname in self.power_meas_names if 'read' in mname]
powers = self.parse_values(power_names, port, 1e3) # scale power to mw
#Check that power parsing worked.
for name, power in powers.items():
if type(power)!=float:
debug.error("Failed to Parse Power Values:\n\t\t{0}".format(powers),1) #Printing the entire dict looks bad.
result.update(powers)
result[port].update(powers)
for port in self.targ_write_ports:
power_names = ["write0_power{0}".format(port), "write1_power{0}".format(port)]
powers = self.parse_values(power_names, 1e3) # scale power to mw
power_names = [mname for mname in self.power_meas_names if 'write' in mname]
powers = self.parse_values(power_names, port, 1e3) # scale power to mw
#Check that power parsing worked.
for name, power in powers.items():
if type(power)!=float:
debug.error("Failed to Parse Power Values:\n\t\t{0}".format(powers),1) #Printing the entire dict looks bad.
result.update(powers)
result[port].update(powers)
# The delay is from the negative edge for our SRAM
return (True,result)
@ -499,11 +552,11 @@ class delay():
return True
def find_min_period(self, feasible_delays_lh, feasible_delays_hl):
def find_min_period(self, feasible_delays):
"""
Determine the minimum period for all ports.
Determine a single minimum period for all ports.
"""
feasible_period = ub_period = self.period
lb_period = 0.0
target_period = 0.5 * (ub_period + lb_period)
@ -511,7 +564,7 @@ class delay():
#Find the minimum period for all ports. Start at one port and perform binary search then use that delay as a starting position.
#For testing purposes, only checks read ports.
for port in self.read_ports:
target_period = self.find_min_period_one_port(feasible_delays_lh, feasible_delays_hl, port, lb_period, ub_period, target_period)
target_period = self.find_min_period_one_port(feasible_delays, port, lb_period, ub_period, target_period)
#The min period of one port becomes the new lower bound. Reset the upper_bound.
lb_period = target_period
ub_period = feasible_period
@ -521,10 +574,10 @@ class delay():
self.targ_write_ports = []
return target_period
def find_min_period_one_port(self, feasible_delays_lh, feasible_delays_hl, port, lb_period, ub_period, target_period):
def find_min_period_one_port(self, feasible_delays, port, lb_period, ub_period, target_period):
"""
Searches for the smallest period with output delays being within 5% of
long period. For the current logic to characterize multiport, bound are required as an input.
long period. For the current logic to characterize multiport, bounds are required as an input.
"""
#previous_period = ub_period = self.period
@ -546,24 +599,20 @@ class delay():
lb_period,
port))
if self.try_period(feasible_delays_lh, feasible_delays_hl):
if self.try_period(feasible_delays):
ub_period = target_period
else:
lb_period = target_period
if relative_compare(ub_period, lb_period, error_tolerance=0.05):
# ub_period is always feasible. When done with a port, set the target period of the next port as the lower bound
# and reset the upperbound
# ub_period is always feasible.
return ub_period
#target_period = lb_period = ub_period
#ub_period = previous_period
#break
#Update target
target_period = 0.5 * (ub_period + lb_period)
def try_period(self, feasible_delays_lh, feasible_delays_hl):
def try_period(self, feasible_delays):
"""
This tries to simulate a period and checks if the result
works. If it does and the delay is within 5% still, it returns True.
@ -574,27 +623,20 @@ class delay():
return False
#Check the values of target readwrite and read ports. Write ports do not produce delays in this current version
for port in self.targ_read_ports:
delay_hl = results["delay_hl{0}".format(port)]
delay_lh = results["delay_lh{0}".format(port)]
slew_hl = results["slew_hl{0}".format(port)]
slew_lh = results["slew_lh{0}".format(port)]
if not relative_compare(delay_lh,feasible_delays_lh[port],error_tolerance=0.05):
debug.info(2,"Delay too big {0} vs {1}".format(delay_lh,feasible_delays_lh[port]))
return False
elif not relative_compare(delay_hl,feasible_delays_hl[port],error_tolerance=0.05):
debug.info(2,"Delay too big {0} vs {1}".format(delay_hl,feasible_delays_hl[port]))
return False
for port in self.targ_read_ports:
delay_port_names = [mname for mname in self.delay_meas_names if "delay" in mname]
for dname in delay_port_names:
if not relative_compare(results[port][dname],feasible_delays[port][dname],error_tolerance=0.05):
debug.info(2,"Delay too big {0} vs {1}".format(results[port][dname],feasible_delays[port][dname]))
return False
#key=raw_input("press return to continue")
debug.info(2,"Successful period {0}, Port {5}, delay_hl={1}ns, delay_lh={2}ns slew_hl={3}ns slew_lh={4}ns".format(self.period,
delay_hl,
delay_lh,
slew_hl,
slew_lh,
port))
#Dynamic way to build string. A bit messy though.
delay_str = ', '.join("{0}={1}ns".format(mname, results[port][mname]) for mname in self.delay_meas_names)
debug.info(2,"Successful period {0}, Port {2}, {1}".format(self.period,
delay_str,
port))
return True
def set_probe(self,probe_address, probe_data):
@ -633,12 +675,11 @@ class delay():
"""
Main function to characterize an SRAM for a table. Computes both delay and power characterization.
"""
#Dict to hold all characterization values
char_sram_data = {}
self.set_probe(probe_address, probe_data)
self.create_port_names()
self.create_char_data_dict()
self.load=max(loads)
self.slew=max(slews)
# This is for debugging a full simulation
@ -652,7 +693,7 @@ class delay():
# sys.exit(1)
#For debugging, skips characterization and returns dummy values.
# char_data = self.char_data
# char_data = self.get_empty_measure_data_dict()
# i = 1.0
# for slew in slews:
# for load in loads:
@ -664,34 +705,29 @@ class delay():
# return char_data
# 1) Find a feasible period and it's corresponding delays using the trimmed array.
(feasible_delays_lh, feasible_delays_hl) = self.find_feasible_period()
#Check all the delays
for k,v in feasible_delays_lh.items():
debug.check(v>0,"Negative delay may not be possible")
for k,v in feasible_delays_hl.items():
debug.check(v>0,"Negative delay may not be possible")
feasible_delays = self.find_feasible_period()
# 2) Finds the minimum period without degrading the delays by X%
self.set_load_slew(max(loads),max(slews))
min_period = self.find_min_period(feasible_delays_lh, feasible_delays_hl)
min_period = self.find_min_period(feasible_delays)
debug.check(type(min_period)==float,"Couldn't find minimum period.")
debug.info(1, "Min Period Found: {0}ns".format(min_period))
self.char_data["min_period"] = round_time(min_period)
char_sram_data["min_period"] = round_time(min_period)
# 3) Find the leakage power of the trimmmed and UNtrimmed arrays.
(full_array_leakage, trim_array_leakage)=self.run_power_simulation()
self.char_data["leakage_power"]=full_array_leakage
char_sram_data["leakage_power"]=full_array_leakage
leakage_offset = full_array_leakage - trim_array_leakage
# 4) At the minimum period, measure the delay, slew and power for all slew/load pairs.
self.simulate_loads_and_slews(slews, loads, leakage_offset)
return self.char_data
self.period = min_period
char_port_data = self.simulate_loads_and_slews(slews, loads, leakage_offset)
return (char_sram_data, char_port_data)
def simulate_loads_and_slews(self, slews, loads, leakage_offset):
"""Simulate all specified output loads and input slews pairs"""
#Set the target simulation ports to all available ports. This make sims slower but failed sims exit anyways.
"""Simulate all specified output loads and input slews pairs of all ports"""
measure_data = self.get_empty_measure_data_dict()
#Set the target simulation ports to all available ports. This make sims slower but failed sims exit anyways.
self.targ_read_ports = self.read_ports
self.targ_write_ports = self.write_ports
for slew in slews:
@ -700,13 +736,17 @@ class delay():
# Find the delay, dynamic power, and leakage power of the trimmed array.
(success, delay_results) = self.run_delay_simulation()
debug.check(success,"Couldn't run a simulation. slew={0} load={1}\n".format(self.slew,self.load))
for k,v in delay_results.items():
if "power" in k:
# Subtract partial array leakage and add full array leakage for the power measures
self.char_data[k].append(v + leakage_offset)
else:
self.char_data[k].append(v)
debug.info(1, "Simulation Passed: Port {0} slew={1} load={2}".format("All", self.slew,self.load))
#The results has a dict for every port but dicts can be empty (e.g. ports were not targeted).
for port in range(self.total_port_num):
for mname,value in delay_results[port].items():
if "power" in mname:
# Subtract partial array leakage and add full array leakage for the power measures
measure_data[port][mname].append(value + leakage_offset)
else:
measure_data[port][mname].append(value)
return measure_data
def add_data(self, data, port):
""" Add the array of data values """
debug.check(len(data)==self.word_size, "Invalid data word size.")
@ -720,7 +760,7 @@ class delay():
else:
debug.error("Non-binary data string",1)
index += 1
def add_address(self, address, port):
""" Add the array of address values """
debug.check(len(address)==self.addr_size, "Invalid address size.")
@ -744,9 +784,7 @@ class delay():
def add_noop_all_ports(self, comment, address, data):
""" Add the control values for a noop to all ports. """
self.cycle_comments.append("Cycle {0:2d}\tPort All\t{1:5.2f}ns:\t{2}".format(len(self.cycle_times),
self.t_current,
comment))
self.add_comment("All", comment)
self.cycle_times.append(self.t_current)
self.t_current += self.period
@ -757,10 +795,7 @@ class delay():
def add_read(self, comment, address, data, port):
""" Add the control values for a read cycle. """
debug.check(port in self.read_ports, "Cannot add read cycle to a write port.")
self.cycle_comments.append("Cycle {0:2d}\tPort {3}\t{1:5.2f}ns:\t{2}".format(len(self.cycle_comments),
self.t_current,
comment,
port))
self.add_comment(port, comment)
self.cycle_times.append(self.t_current)
self.t_current += self.period
self.add_control_one_port(port, "read")
@ -780,10 +815,7 @@ class delay():
def add_write(self, comment, address, data, port):
""" Add the control values for a write cycle. """
debug.check(port in self.write_ports, "Cannot add read cycle to a read port.")
self.cycle_comments.append("Cycle {0:2d}\tPort {3}\t{1:5.2f}ns:\t{2}".format(len(self.cycle_comments),
self.t_current,
comment,
port))
self.add_comment(port, comment)
self.cycle_times.append(self.t_current)
self.t_current += self.period
@ -814,9 +846,19 @@ class delay():
#Append the values depending on the type of port
self.csb_values[port].append(csb_val)
#If port is in both lists, add rw control signal. Condition indicates its a RW port.
if port < len(self.web_values):
if port in self.write_ports and port in self.read_ports:
self.web_values[port].append(web_val)
def add_comment(self, port, comment):
"""Add comment to list to be printed in stimulus file"""
#Clean up time before appending. Make spacing dynamic as well.
time = "{0:.2f} ns:".format(self.t_current)
time_spacing = len(time)+6
self.cycle_comments.append("Cycle {0:<6d} Port {1:<6} {2:<{3}}: {4}".format(len(self.cycle_times),
port,
time,
time_spacing,
comment))
def gen_test_cycles_one_port(self, read_port, write_port):
"""Intended but not implemented: Returns a list of key time-points [ns] of the waveform (each rising edge)
of the cycles to do a timing evaluation of a single port. Current: Values overwritten for multiple calls"""
@ -906,14 +948,14 @@ class delay():
self.measure_cycles = {}
# Control signals for ports. These are not the final signals and will likely be changed later.
#write enable bar for readwrite ports to control read or write
self.web_values = [[] for i in range(self.readwrite_port_num)]
#csb represents a basic "enable" signal that all ports have.
self.csb_values = [[] for i in range(self.total_port_num)]
#web is the enable for write ports. Dicts used for simplicity as ports are not necessarily incremental.
self.web_values = {port:[] for port in self.write_ports}
#csb acts as an enable for the read ports.
self.csb_values = {port:[] for port in range(self.total_port_num)}
# Address and data values for each address/data bit. A dict of 3d lists of size #ports x bits x cycles.
self.data_values=[[[] for i in range(self.addr_size)]]*len(self.write_ports)
self.addr_values=[[[] for i in range(self.addr_size)]]*self.total_port_num
# Address and data values for each address/data bit. A 3d list of size #ports x bits x cycles.
self.data_values=[[[] for bit in range(self.word_size)] for port in range(len(self.write_ports))]
self.addr_values=[[[] for bit in range(self.addr_size)] for port in range(self.total_port_num)]
#Get any available read/write port in case only a single write or read ports is being characterized.
cur_read_port = self.get_available_port(get_read_port=True)
@ -969,24 +1011,24 @@ class delay():
debug.info(1,"Dynamic Power: {0} mW".format(power.dynamic))
debug.info(1,"Leakage Power: {0} mW".format(power.leakage))
data = {"min_period": 0,
"delay_lh0": delay_lh,
"delay_hl0": delay_hl,
"slew_lh0": slew_lh,
"slew_hl0": slew_hl,
"read0_power0": power.dynamic,
"read1_power0": power.dynamic,
"write0_power0": power.dynamic,
"write1_power0": power.dynamic,
"leakage_power": power.leakage
}
return data
sram_data = { "min_period": 0,
"leakage_power": power.leakage}
port_data = [{"delay_lh": delay_lh,
"delay_hl": delay_hl,
"slew_lh": slew_lh,
"slew_hl": slew_hl,
"read0_power": power.dynamic,
"read1_power": power.dynamic,
"write0_power": power.dynamic,
"write1_power": power.dynamic,
}]
return (sram_data,port_data)
def gen_data(self):
""" Generates the PWL data inputs for a simulation timing test. """
for write_port in self.write_ports:
for i in range(self.word_size):
sig_name="DIN{0}[{1}] ".format(write_port, i)
sig_name="{0}{1}_{2} ".format(self.din_name,write_port, i)
self.stim.gen_pwl(sig_name, self.cycle_times, self.data_values[write_port][i], self.period, self.slew, 0.05)
def gen_addr(self):
@ -996,46 +1038,20 @@ class delay():
"""
for port in range(self.total_port_num):
for i in range(self.addr_size):
sig_name = "A{0}[{1}]".format(port,i)
sig_name = "{0}{1}_{2}".format(self.addr_name,port,i)
self.stim.gen_pwl(sig_name, self.cycle_times, self.addr_values[port][i], self.period, self.slew, 0.05)
def gen_control(self):
""" Generates the control signals """
for port in range(self.total_port_num):
self.stim.gen_pwl("CSB{0}".format(port), self.cycle_times, self.csb_values[port], self.period, self.slew, 0.05)
if port in self.read_ports and port in self.write_ports:
self.stim.gen_pwl("WEB{0}".format(port), self.cycle_times, self.web_values[port], self.period, self.slew, 0.05)
for readwrite_port in range(self.readwrite_port_num):
self.stim.gen_pwl("WEB{0}".format(readwrite_port), self.cycle_times, self.web_values[readwrite_port], self.period, self.slew, 0.05)
def create_port_names(self):
"""Generates the port names to be used in characterization and sets default simulation target ports"""
self.write_ports = []
self.read_ports = []
self.total_port_num = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports
#save a member variable to avoid accessing global. readwrite ports have different control signals.
self.readwrite_port_num = OPTS.num_rw_ports
#Generate the port names. readwrite ports are required to be added first for this to work.
for readwrite_port_num in range(OPTS.num_rw_ports):
self.read_ports.append(readwrite_port_num)
self.write_ports.append(readwrite_port_num)
#This placement is intentional. It makes indexing input data easier. See self.data_values
for write_port_num in range(OPTS.num_rw_ports, OPTS.num_rw_ports+OPTS.num_w_ports):
self.write_ports.append(write_port_num)
for read_port_num in range(OPTS.num_rw_ports+OPTS.num_w_ports, OPTS.num_rw_ports+OPTS.num_w_ports+OPTS.num_r_ports):
self.read_ports.append(read_port_num)
#Set the default target ports for simulation. Default is all the ports.
self.targ_read_ports = self.read_ports
self.targ_write_ports = self.write_ports
def create_char_data_dict(self):
"""Make a dict of lists for each type of measurement to append results to"""
#Making this a member variable may not be the best option, but helps reduce code clutter
self.char_data = {}
for port in range(self.total_port_num):
for m in ["delay_lh", "delay_hl", "slew_lh", "slew_hl", "read0_power",
"read1_power", "write0_power", "write1_power"]:
self.char_data ["{0}{1}".format(m,port)]=[]
def get_empty_measure_data_dict(self):
"""Make a dict of lists for each type of delay and power measurement to append results to"""
measure_names = self.delay_meas_names + self.power_meas_names
#Create list of dicts. List lengths is # of ports. Each dict maps the measurement names to lists.
measure_data = [{mname:[] for mname in measure_names} for i in range(self.total_port_num)]
return measure_data

View File

@ -0,0 +1,272 @@
import sys,re,shutil
from design import design
import debug
import math
import tech
import random
from .stimuli import *
from .charutils import *
import utils
from globals import OPTS
from .simulation import simulation
class functional(simulation):
"""
Functions to write random data values to a random address then read them back and check
for successful SRAM operation.
"""
def __init__(self, sram, spfile, corner):
simulation.__init__(self, sram, spfile, corner)
self.set_corner(corner)
self.set_spice_constants()
self.set_stimulus_variables()
self.create_signal_names()
# Number of checks can be changed
self.num_cycles = 2
self.stored_words = {}
self.write_check = []
self.read_check = []
def run(self):
# Generate a random sequence of reads and writes
self.write_random_memory_sequence()
# Run SPICE simulation
self.write_functional_stimulus()
self.stim.run_sim()
# read DOUT values from SPICE simulation. If the values do not fall within the noise margins, return the error.
(success, error) = self.read_stim_results()
if not success:
return (0, error)
# Check read values with written values. If the values do not match, return an error.
return self.check_stim_results()
def write_random_memory_sequence(self):
rw_ops = ["noop", "write", "read"]
w_ops = ["noop", "write"]
r_ops = ["noop", "read"]
rw_read_data = "0"*self.word_size
check = 0
# First cycle idle
self.add_noop_all_ports("Idle at time {0}n".format(self.t_current),
"0"*self.addr_size, "0"*self.word_size)
# Write at least once
addr = self.gen_addr()
word = self.gen_data()
self.add_write("Writing {0} to address {1} (from port {2}) at time {3}n".format(word, addr, 0, self.t_current),
addr, word, 0)
self.stored_words[addr] = word
# Read at least once. For multiport, it is important that one read cycle uses all RW and R port to read from the same address simultaniously.
# This will test the viablilty of the transistor sizing in the bitcell.
for port in range(self.total_ports):
if self.port_id[port] == "w":
self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, port)
else:
self.add_read_one_port("Reading {0} from address {1} (from port {2}) at time {3}n".format(word, addr, port, self.t_current),
addr, rw_read_data, port)
self.write_check.append([word, "{0}{1}".format(self.dout_name,port), self.t_current+self.period, check])
check += 1
self.cycle_times.append(self.t_current)
self.t_current += self.period
# Perform a random sequence of writes and reads on random ports, using random addresses and random words
for i in range(self.num_cycles):
w_addrs = []
for port in range(self.total_ports):
if self.port_id[port] == "rw":
op = random.choice(rw_ops)
elif self.port_id[port] == "w":
op = random.choice(w_ops)
else:
op = random.choice(r_ops)
if op == "noop":
addr = "0"*self.addr_size
word = "0"*self.word_size
self.add_noop_one_port(addr, word, port)
elif op == "write":
addr = self.gen_addr()
word = self.gen_data()
# two ports cannot write to the same address
if addr in w_addrs:
self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, port)
else:
self.add_write_one_port("Writing {0} to address {1} (from port {2}) at time {3}n".format(word, addr, port, self.t_current),
addr, word, port)
self.stored_words[addr] = word
w_addrs.append(addr)
else:
(addr,word) = random.choice(list(self.stored_words.items()))
# cannot read from an address that is currently being written to
if addr in w_addrs:
self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, port)
else:
self.add_read_one_port("Reading {0} from address {1} (from port {2}) at time {3}n".format(word, addr, port, self.t_current),
addr, rw_read_data, port)
self.write_check.append([word, "{0}{1}".format(self.dout_name,port), self.t_current+self.period, check])
check += 1
self.cycle_times.append(self.t_current)
self.t_current += self.period
# Last cycle idle needed to correctly measure the value on the second to last clock edge
self.add_noop_all_ports("Idle at time {0}n".format(self.t_current),
"0"*self.addr_size, "0"*self.word_size)
def read_stim_results(self):
# Extrat DOUT values from spice timing.lis
for (word, dout_port, eo_period, check) in self.write_check:
sp_read_value = ""
for bit in range(self.word_size):
value = parse_spice_list("timing", "v{0}.{1}ck{2}".format(dout_port.lower(),bit,check))
if value > 0.9 * self.vdd_voltage:
sp_read_value = "1" + sp_read_value
elif value < 0.1 * self.vdd_voltage:
sp_read_value = "0" + sp_read_value
else:
error ="FAILED: {0}_{1} value {2} at time {3}n does not fall within noise margins <{4} or >{5}.".format(dout_port,
bit,
value,
eo_period,
0.1*self.vdd_voltage,
0.9*self.vdd_voltage)
return (0, error)
self.read_check.append([sp_read_value, dout_port, eo_period, check])
return (1, "SUCCESS")
def check_stim_results(self):
for i in range(len(self.write_check)):
if self.write_check[i][0] != self.read_check[i][0]:
error = "FAILED: {0} value {1} does not match written value {2} read at time {3}n".format(self.read_check[i][1],
self.read_check[i][0],
self.write_check[i][0],
self.read_check[i][2])
return(0, error)
return(1, "SUCCESS")
def gen_data(self):
""" Generates a random word to write. """
rand = random.randint(0,(2**self.word_size)-1)
data_bits = self.convert_to_bin(rand,False)
return data_bits
def gen_addr(self):
""" Generates a random address value to write to. """
rand = random.randint(0,(2**self.addr_size)-1)
addr_bits = self.convert_to_bin(rand,True)
return addr_bits
def get_data(self):
""" Gets an available address and corresponding word. """
# Currently unused but may need later depending on how the functional test develops
addr = random.choice(self.stored_words.keys())
word = self.stored_words[addr]
return (addr,word)
def convert_to_bin(self,value,is_addr):
""" Converts addr & word to usable binary values. """
new_value = str.replace(bin(value),"0b","")
if(is_addr):
expected_value = self.addr_size
else:
expected_value = self.word_size
for i in range (expected_value - len(new_value)):
new_value = "0" + new_value
#print("Binary Conversion: {} to {}".format(value, new_value))
return new_value
def create_signal_names(self):
self.addr_name = "A"
self.din_name = "DIN"
self.dout_name = "DOUT"
def write_functional_stimulus(self):
""" Writes SPICE stimulus. """
temp_stim = "{0}/stim.sp".format(OPTS.openram_temp)
self.sf = open(temp_stim,"w")
self.sf.write("* Functional test stimulus file for {}ns period\n\n".format(self.period))
self.stim = stimuli(self.sf,self.corner)
#Write include statements
self.sram_sp_file = "{}sram.sp".format(OPTS.openram_temp)
shutil.copy(self.sp_file, self.sram_sp_file)
self.stim.write_include(self.sram_sp_file)
#Write Vdd/Gnd statements
self.sf.write("\n* Global Power Supplies\n")
self.stim.write_supply()
#Instantiate the SRAM
self.sf.write("\n* Instantiation of the SRAM\n")
self.stim.inst_sram(sram=self.sram,
port_signal_names=(self.addr_name,self.din_name,self.dout_name),
port_info=(self.total_ports, self.write_index, self.read_index),
abits=self.addr_size,
dbits=self.word_size,
sram_name=self.name)
# Add load capacitance to each of the read ports
self.sf.write("\n* SRAM output loads\n")
for port in range(self.total_read):
for bit in range(self.word_size):
sig_name="{0}{1}_{2} ".format(self.dout_name, self.read_index[port], bit)
self.sf.write("CD{0}{1} {2} 0 {3}f\n".format(self.read_index[port], bit, sig_name, self.load))
# Generate data input bits
self.sf.write("\n* Generation of data and address signals\n")
for port in range(self.total_write):
for bit in range(self.word_size):
sig_name="{0}{1}_{2} ".format(self.din_name, port, bit)
self.stim.gen_pwl(sig_name, self.cycle_times, self.data_values[port][bit], self.period, self.slew, 0.05)
# Generate address bits
for port in range(self.total_ports):
for bit in range(self.addr_size):
sig_name="{0}{1}_{2} ".format(self.addr_name, port, bit)
self.stim.gen_pwl(sig_name, self.cycle_times, self.addr_values[port][bit], self.period, self.slew, 0.05)
# Generate control signals
self.sf.write("\n * Generation of control signals\n")
for port in range(self.total_ports):
self.stim.gen_pwl("CSB{}".format(port), self.cycle_times , self.csb_values[port], self.period, self.slew, 0.05)
for port in range(self.num_rw_ports):
self.stim.gen_pwl("WEB{}".format(port), self.cycle_times , self.web_values[port], self.period, self.slew, 0.05)
# Generate CLK signals
for port in range(self.total_ports):
self.stim.gen_pulse(sig_name="{0}{1}".format(tech.spice["clk"], port),
v1=self.gnd_voltage,
v2=self.vdd_voltage,
offset=self.period,
period=self.period,
t_rise=self.slew,
t_fall=self.slew)
# Generate DOUT value measurements
self.sf.write("\n * Generation of dout measurements\n")
for (word, dout_port, eo_period, check) in self.write_check:
t_intital = eo_period - 0.01*self.period
t_final = eo_period + 0.01*self.period
for bit in range(self.word_size):
self.stim.gen_meas_value(meas_name="V{0}_{1}ck{2}".format(dout_port,bit,check),
dout="{0}_{1}".format(dout_port,bit),
t_intital=t_intital,
t_final=t_final)
self.stim.write_control(self.cycle_times[-1] + self.period)
self.sf.close()

View File

@ -12,10 +12,6 @@ class lib:
""" lib file generation."""
def __init__(self, out_dir, sram, sp_file, use_model=OPTS.analytical_delay):
#Temporary Workaround to here to set num of ports. Crashes if set in config file.
#OPTS.num_rw_ports = 2
#OPTS.num_r_ports = 1
#OPTS.num_w_ports = 1
self.out_dir = out_dir
self.sram = sram
@ -161,7 +157,7 @@ class lib:
# Leakage is included in dynamic when macro is enabled
self.lib.write(" leakage_power () {\n")
self.lib.write(" when : \"{0}\";\n".format(control_str))
self.lib.write(" value : {};\n".format(self.char_results["leakage_power"]))
self.lib.write(" value : {};\n".format(self.char_sram_results["leakage_power"]))
self.lib.write(" }\n")
self.lib.write(" cell_leakage_power : {};\n".format(0))
@ -347,16 +343,16 @@ class lib:
self.lib.write(" related_pin : \"clk\"; \n")
self.lib.write(" timing_type : rising_edge; \n")
self.lib.write(" cell_rise(CELL_TABLE) {\n")
self.write_values(self.char_results["delay_lh{0}".format(read_port)],len(self.loads)," ")
self.write_values(self.char_port_results[read_port]["delay_lh"],len(self.loads)," ")
self.lib.write(" }\n") # rise delay
self.lib.write(" cell_fall(CELL_TABLE) {\n")
self.write_values(self.char_results["delay_hl{0}".format(read_port)],len(self.loads)," ")
self.write_values(self.char_port_results[read_port]["delay_hl"],len(self.loads)," ")
self.lib.write(" }\n") # fall delay
self.lib.write(" rise_transition(CELL_TABLE) {\n")
self.write_values(self.char_results["slew_lh{0}".format(read_port)],len(self.loads)," ")
self.write_values(self.char_port_results[read_port]["slew_lh"],len(self.loads)," ")
self.lib.write(" }\n") # rise trans
self.lib.write(" fall_transition(CELL_TABLE) {\n")
self.write_values(self.char_results["slew_hl{0}".format(read_port)],len(self.loads)," ")
self.write_values(self.char_port_results[read_port]["slew_hl"],len(self.loads)," ")
self.lib.write(" }\n") # fall trans
self.lib.write(" }\n") # timing
self.lib.write(" }\n") # pin
@ -428,8 +424,8 @@ class lib:
for port in range(self.total_port_num):
self.add_clk_control_power(port)
min_pulse_width = round_time(self.char_results["min_period"])/2.0
min_period = round_time(self.char_results["min_period"])
min_pulse_width = round_time(self.char_sram_results["min_period"])/2.0
min_period = round_time(self.char_sram_results["min_period"])
self.lib.write(" timing(){ \n")
self.lib.write(" timing_type :\"min_pulse_width\"; \n")
self.lib.write(" related_pin : clk; \n")
@ -461,7 +457,7 @@ class lib:
if port in self.write_ports:
if port in self.read_ports:
web_name = " & !WEb{0}".format(port)
avg_write_power = np.mean(self.char_results["write1_power{0}".format(port)] + self.char_results["write0_power{0}".format(port)])
avg_write_power = np.mean(self.char_port_results[port]["write1_power"] + self.char_port_results[port]["write0_power"])
self.lib.write(" internal_power(){\n")
self.lib.write(" when : \"!CSb{0} & clk{1}\"; \n".format(port, web_name))
self.lib.write(" rise_power(scalar){\n")
@ -475,7 +471,7 @@ class lib:
if port in self.read_ports:
if port in self.write_ports:
web_name = " & WEb{0}".format(port)
avg_read_power = np.mean(self.char_results["read1_power{0}".format(port)] + self.char_results["read0_power{0}".format(port)])
avg_read_power = np.mean(self.char_port_results[port]["read1_power"] + self.char_port_results[port]["read0_power"])
self.lib.write(" internal_power(){\n")
self.lib.write(" when : \"!CSb{0} & !clk{1}\"; \n".format(port, web_name))
self.lib.write(" rise_power(scalar){\n")
@ -502,13 +498,14 @@ class lib:
if not hasattr(self,"d"):
self.d = delay(self.sram, self.sp_file, self.corner)
if self.use_model:
self.char_results = self.d.analytical_delay(self.sram,self.slews,self.loads)
char_results = self.d.analytical_delay(self.sram,self.slews,self.loads)
self.char_sram_results, self.char_port_results = char_results
else:
probe_address = "1" * self.sram.addr_size
probe_data = self.sram.word_size - 1
self.char_results = self.d.analyze(probe_address, probe_data, self.slews, self.loads)
char_results = self.d.analyze(probe_address, probe_data, self.slews, self.loads)
self.char_sram_results, self.char_port_results = char_results
def compute_setup_hold(self):
""" Do the analysis if we haven't characterized a FF yet """
# Do the analysis if we haven't characterized a FF yet

View File

@ -0,0 +1,200 @@
import sys,re,shutil
from design import design
import debug
import math
import tech
import random
from .stimuli import *
from .trim_spice import *
from .charutils import *
import utils
from globals import OPTS
class simulation():
def __init__(self, sram, spfile, corner):
self.sram = sram
self.name = self.sram.name
self.word_size = self.sram.word_size
self.addr_size = self.sram.addr_size
self.num_cols = self.sram.num_cols
self.num_rows = self.sram.num_rows
self.num_banks = self.sram.num_banks
self.sp_file = spfile
self.total_ports = self.sram.total_ports
self.total_write = self.sram.total_write
self.total_read = self.sram.total_read
self.read_index = self.sram.read_index
self.write_index = self.sram.write_index
self.num_rw_ports = self.sram.num_rw_ports
self.port_id = self.sram.port_id
def set_corner(self,corner):
""" Set the corner values """
self.corner = corner
(self.process, self.vdd_voltage, self.temperature) = corner
def set_spice_constants(self):
""" sets feasible timing parameters """
self.period = tech.spice["feasible_period"]
self.slew = tech.spice["rise_time"]*2
self.load = tech.spice["msflop_in_cap"]*4
self.gnd_voltage = 0
def set_stimulus_variables(self):
# Clock signals
self.cycle_times = []
self.t_current = 0
# control signals: only one cs_b for entire multiported sram, one we_b for each write port
self.csb_values = [[] for port in range(self.total_ports)]
self.web_values = [[] for port in range(self.num_rw_ports)]
# Three dimensional list to handle each addr and data bits for wach port over the number of checks
self.addr_values = [[[] for bit in range(self.addr_size)] for port in range(self.total_ports)]
self.data_values = [[[] for bit in range(self.word_size)] for port in range(self.total_write)]
# For generating comments in SPICE stimulus
self.cycle_comments = []
def add_control_one_port(self, port, op):
"""Appends control signals for operation to a given port"""
#Determine values to write to port
web_val = 1
csb_val = 1
if op == "read":
csb_val = 0
elif op == "write":
csb_val = 0
web_val = 0
elif op != "noop":
debug.error("Could not add control signals for port {0}. Command {1} not recognized".format(port,op),1)
# Append the values depending on the type of port
self.csb_values[port].append(csb_val)
# If port is in both lists, add rw control signal. Condition indicates its a RW port.
if port < self.num_rw_ports:
self.web_values[port].append(web_val)
def add_data(self, data, port):
""" Add the array of data values """
debug.check(len(data)==self.word_size, "Invalid data word size.")
#debug.check(port < len(self.data_values), "Port number cannot index data values.")
bit = self.word_size - 1
for c in data:
if c=="0":
self.data_values[port][bit].append(0)
elif c=="1":
self.data_values[port][bit].append(1)
else:
debug.error("Non-binary data string",1)
bit -= 1
def add_address(self, address, port):
""" Add the array of address values """
debug.check(len(address)==self.addr_size, "Invalid address size.")
bit = self.addr_size - 1
for c in address:
if c=="0":
self.addr_values[port][bit].append(0)
elif c=="1":
self.addr_values[port][bit].append(1)
else:
debug.error("Non-binary address string",1)
bit -= 1
def add_write(self, comment, address, data, port):
""" Add the control values for a write cycle. """
debug.info(1, comment)
debug.check(port in self.write_index, "Cannot add write cycle to a read port. Port {0}, Write Ports {1}".format(port, self.write_index))
self.cycle_comments.append("Cycle {0:2d}\tPort {3}\t{1:5.2f}ns:\t{2}".format(len(self.cycle_comments),
self.t_current,
comment,
port))
self.cycle_times.append(self.t_current)
self.t_current += self.period
self.add_control_one_port(port, "write")
self.add_data(data,port)
self.add_address(address,port)
#This value is hard coded here. Possibly change to member variable or set in add_noop_one_port
noop_data = "0"*self.word_size
#Add noops to all other ports.
for unselected_port in range(self.total_ports):
if unselected_port != port:
self.add_noop_one_port(address, noop_data, unselected_port)
def add_read(self, comment, address, data, port):
""" Add the control values for a read cycle. """
debug.info(1, comment)
debug.check(port in self.read_index, "Cannot add read cycle to a write port. Port {0}, Read Ports {1}".format(port, self.read_index))
self.cycle_comments.append("Cycle {0:2d}\tPort {3}\t{1:5.2f}ns:\t{2}".format(len(self.cycle_comments),
self.t_current,
comment,
port))
self.cycle_times.append(self.t_current)
self.t_current += self.period
self.add_control_one_port(port, "read")
#If the port is also a readwrite then add data.
if port in self.write_index:
self.add_data(data,port)
self.add_address(address, port)
#This value is hard coded here. Possibly change to member variable or set in add_noop_one_port
noop_data = "0"*self.word_size
#Add noops to all other ports.
for unselected_port in range(self.total_ports):
if unselected_port != port:
self.add_noop_one_port(address, noop_data, unselected_port)
def add_noop_all_ports(self, comment, address, data):
""" Add the control values for a noop to all ports. """
debug.info(1, comment)
self.cycle_comments.append("Cycle {0:2d}\tPort All\t{1:5.2f}ns:\t{2}".format(len(self.cycle_times),
self.t_current,
comment))
self.cycle_times.append(self.t_current)
self.t_current += self.period
for port in range(self.total_ports):
self.add_noop_one_port(address, data, port)
def add_write_one_port(self, comment, address, data, port):
""" Add the control values for a write cycle. Does not increment the period. """
debug.check(port in self.write_index, "Cannot add write cycle to a read port. Port {0}, Write Ports {1}".format(port, self.write_index))
debug.info(1, comment)
self.cycle_comments.append("Cycle {0:2d}\tPort {3}\t{1:5.2f}ns:\t{2}".format(len(self.cycle_comments),
self.t_current,
comment,
port))
self.add_control_one_port(port, "write")
self.add_data(data,port)
self.add_address(address,port)
def add_read_one_port(self, comment, address, data, port):
""" Add the control values for a read cycle. Does not increment the period. """
debug.check(port in self.read_index, "Cannot add read cycle to a write port. Port {0}, Read Ports {1}".format(port, self.read_index))
debug.info(1, comment)
self.cycle_comments.append("Cycle {0:2d}\tPort {3}\t{1:5.2f}ns:\t{2}".format(len(self.cycle_comments),
self.t_current,
comment,
port))
self.add_control_one_port(port, "read")
#If the port is also a readwrite then add data.
if port in self.write_index:
self.add_data(data,port)
self.add_address(address, port)
def add_noop_one_port(self, address, data, port):
""" Add the control values for a noop to a single port. Does not increment the period. """
self.add_control_one_port(port, "noop")
if port in self.write_index:
self.add_data(data,port)
self.add_address(address, port)

View File

@ -28,39 +28,53 @@ class stimuli():
(self.process, self.voltage, self.temperature) = corner
self.device_models = tech.spice["fet_models"][self.process]
def inst_sram(self, abits, dbits, port_info, sram_name):
def inst_sram(self, sram, port_signal_names, port_info, abits, dbits, sram_name):
""" Function to instatiate an SRAM subckt. """
pin_names = self.gen_pin_names(port_signal_names, port_info, abits, dbits)
#Only checking length. This should check functionality as well (TODO) and/or import that information from the SRAM
debug.check(len(sram.pins) == len(pin_names), "Number of pins generated for characterization do match pins of SRAM\nsram.pins = {0}\npin_names = {1}".format(sram.pins,pin_names))
self.sf.write("Xsram ")
#Un-tuple the port names. This was done to avoid passing them all as arguments. Could be improved still.
#This should be generated from the pin list of the sram... change when multiport pins done.
(total_port_num,readwrite_num,read_ports,write_ports) = port_info
for write_input in write_ports:
for i in range(dbits):
self.sf.write("DIN{0}[{1}] ".format(write_input, i))
for port in range(total_port_num):
for i in range(abits):
self.sf.write("A{0}[{1}] ".format(port,i))
#These control signals assume 6t sram i.e. a single readwrite port. If multiple readwrite ports are used then add more
#control signals. Not sure if this is correct, consider a temporary change until control signals for multiport are finalized.
for port in range(total_port_num):
self.sf.write("CSB{0} ".format(port))
for readwrite_port in range(readwrite_num):
self.sf.write("WEB{0} ".format(readwrite_port))
self.sf.write("{0} ".format(tech.spice["clk"]))
for read_output in read_ports:
for i in range(dbits):
self.sf.write("DOUT{0}[{1}] ".format(read_output, i))
self.sf.write("{0} {1} ".format(self.vdd_name, self.gnd_name))
for pin in pin_names:
self.sf.write("{0} ".format(pin))
self.sf.write("{0}\n".format(sram_name))
def gen_pin_names(self, port_signal_names, port_info, abits, dbits):
"""Creates the pins names of the SRAM based on the no. of ports."""
#This may seem redundant as the pin names are already defined in the sram. However, it is difficult to extract the
#functionality from the names, so they are recreated. As the order is static, changing the order of the pin names
#will cause issues here.
pin_names = []
(addr_name, din_name, dout_name) = port_signal_names
(total_ports, write_index, read_index) = port_info
for write_input in write_index:
for i in range(dbits):
pin_names.append("{0}{1}_{2}".format(din_name,write_input, i))
for port in range(total_ports):
for i in range(abits):
pin_names.append("{0}{1}_{2}".format(addr_name,port,i))
#Control signals not finalized.
for port in range(total_ports):
pin_names.append("CSB{0}".format(port))
for port in range(total_ports):
if (port in read_index) and (port in write_index):
pin_names.append("WEB{0}".format(port))
for port in range(total_ports):
pin_names.append("{0}{1}".format(tech.spice["clk"], port))
for read_output in read_index:
for i in range(dbits):
pin_names.append("{0}{1}_{2}".format(dout_name,read_output, i))
pin_names.append("{0}".format(self.vdd_name))
pin_names.append("{0}".format(self.gnd_name))
return pin_names
def inst_model(self, pins, model_name):
""" Function to instantiate a generic model with a set of pins """
self.sf.write("X{0} ".format(model_name))
@ -153,7 +167,7 @@ class stimuli():
to the initial value.
"""
# the initial value is not a clock time
debug.check(len(clk_times)==len(data_values),"Clock and data value lengths don't match.")
debug.check(len(clk_times)==len(data_values),"Clock and data value lengths don't match. {0} clock values, {1} data values for {2}".format(len(clk_times), len(data_values), sig_name))
# shift signal times earlier for setup time
times = np.array(clk_times) - setup*period
@ -213,6 +227,10 @@ class stimuli():
power_exp,
t_initial,
t_final))
def gen_meas_value(self, meas_name, dout, t_intital, t_final):
measure_string=".meas tran {0} AVG v({1}) FROM={2}n TO={3}n\n\n".format(meas_name, dout, t_intital, t_final)
self.sf.write(measure_string)
def write_control(self, end_time):
""" Write the control cards to run and end the simulation """
@ -255,12 +273,15 @@ class stimuli():
def write_supply(self):
""" Writes supply voltage statements """
self.sf.write("V{0} {0} 0.0 {1}\n".format(self.vdd_name, self.voltage))
self.sf.write("V{0} {0} 0.0 {1}\n".format(self.gnd_name, 0))
gnd_node_name = "0"
self.sf.write("V{0} {0} {1} {2}\n".format(self.vdd_name, gnd_node_name, self.voltage))
# This is for the test power supply
self.sf.write("V{0} {0} 0.0 {1}\n".format("test"+self.vdd_name, self.voltage))
self.sf.write("V{0} {0} 0.0 {1}\n".format("test"+self.gnd_name, 0))
self.sf.write("V{0} {0} {1} {2}\n".format("test"+self.vdd_name, gnd_node_name, self.voltage))
self.sf.write("V{0} {0} {1} {2}\n".format("test"+self.gnd_name, gnd_node_name, 0.0))
#Adding a commented out supply for simulators where gnd and 0 are not global grounds.
self.sf.write("\n*Nodes gnd and 0 are the same global ground node in ngspice/hspice/xa. Otherwise, this source may be needed.\n")
self.sf.write("*V{0} {0} {1} {2}\n".format(self.gnd_name, gnd_node_name, 0.0))
def run_sim(self):
""" Run hspice in batch mode and output rawfile to parse. """

View File

@ -1,5 +1,6 @@
import debug
from math import log
import re
class trim_spice():
"""
@ -73,25 +74,28 @@ class trim_spice():
self.sp_buffer.insert(0, "* It should NOT be used for LVS!!")
self.sp_buffer.insert(0, "* WARNING: This is a TRIMMED NETLIST.")
self.remove_insts("bitcell_array",[wl_name,bl_name])
wl_regex = r"wl\d*\[{}\]".format(wl_address)
bl_regex = r"bl\d*\[{}\]".format(int(self.words_per_row*data_bit + col_address))
self.remove_insts("bitcell_array",[wl_regex,bl_regex])
# 2. Keep sense amps basd on BL
# FIXME: The bit lines are not indexed the same in sense_amp_array
#self.remove_insts("sense_amp_array",[bl_name])
#self.remove_insts("sense_amp_array",[bl_regex])
# 3. Keep column muxes basd on BL
self.remove_insts("column_mux_array",[bl_name])
self.remove_insts("column_mux_array",[bl_regex])
# 4. Keep write driver based on DATA
data_name = "data[{}]".format(data_bit)
self.remove_insts("write_driver_array",[data_name])
data_regex = r"data\[{}\]".format(data_bit)
self.remove_insts("write_driver_array",[data_regex])
# 5. Keep wordline driver based on WL
# Need to keep the gater too
#self.remove_insts("wordline_driver",wl_name)
#self.remove_insts("wordline_driver",wl_regex)
# 6. Keep precharges based on BL
self.remove_insts("precharge_array",[bl_name])
self.remove_insts("precharge_array",[bl_regex])
# Everything else isn't worth removing. :)
@ -107,6 +111,9 @@ class trim_spice():
match of the line with a term so you can search for a single
net connection, the instance name, anything..
"""
#Expects keep_inst_list are regex patterns. Compile them here.
compiled_patterns = [re.compile(pattern) for pattern in keep_inst_list]
start_name = ".SUBCKT {}".format(subckt_name)
end_name = ".ENDS {}".format(subckt_name)
@ -120,8 +127,8 @@ class trim_spice():
new_buffer.append(line)
in_subckt=False
elif in_subckt:
for k in keep_inst_list:
if k in line:
for pattern in compiled_patterns:
if pattern.search(line) != None:
new_buffer.append(line)
break
else:

View File

@ -10,10 +10,10 @@ temperatures = [25]
output_path = "temp"
output_name = "sram_{0}_{1}_{2}_{3}".format(word_size,num_words,num_banks,tech_name)
#Below are some additions to test additional ports on sram
#bitcell = "pbitcell"
# These are the configuration parameters
#rw_ports = 2
#r_ports = 2
#w_ports = 2
#Setting for multiport
# netlist_only = True
# bitcell = "pbitcell"
# replica_bitcell="replica_pbitcell"
# num_rw_ports = 1
# num_r_ports = 0
# num_w_ports = 1

View File

@ -2,10 +2,18 @@ word_size = 2
num_words = 16
num_banks = 1
tech_name = "scn3me_subm"
tech_name = "scn4m_subm"
process_corners = ["TT"]
supply_voltages = [ 5.0 ]
temperatures = [ 25 ]
output_path = "temp"
output_name = "sram_{0}_{1}_{2}_{3}".format(word_size,num_words,num_banks,tech_name)
#Setting for multiport
# netlist_only = True
# bitcell = "pbitcell"
# replica_bitcell="replica_pbitcell"
# num_rw_ports = 1
# num_r_ports = 1
# num_w_ports = 0

View File

@ -74,10 +74,12 @@ def print_banner():
print("|=========" + name.center(60) + "=========|")
print("|=========" + " ".center(60) + "=========|")
print("|=========" + "VLSI Design and Automation Lab".center(60) + "=========|")
print("|=========" + "University of California Santa Cruz CE Department".center(60) + "=========|")
print("|=========" + "Computer Science and Engineering Department".center(60) + "=========|")
print("|=========" + "University of California Santa Cruz".center(60) + "=========|")
print("|=========" + " ".center(60) + "=========|")
print("|=========" + "VLSI Computer Architecture Research Group".center(60) + "=========|")
print("|=========" + "Oklahoma State University ECE Department".center(60) + "=========|")
print("|=========" + "Electrical and Computer Engineering Department".center(60) + "=========|")
print("|=========" + "Oklahoma State University".center(60) + "=========|")
print("|=========" + " ".center(60) + "=========|")
user_info = "Usage help: openram-user-group@ucsc.edu"
print("|=========" + user_info.center(60) + "=========|")
@ -223,13 +225,17 @@ def read_config(config_file, is_unit_test=True):
# If config didn't set output name, make a reasonable default.
if (OPTS.output_name == ""):
OPTS.output_name = "sram_{0}b_{1}w_{2}bank_{3}rw_{4}w_{5}r_{6}".format(OPTS.word_size,
OPTS.num_words,
OPTS.num_banks,
OPTS.num_rw_ports,
OPTS.num_w_ports,
OPTS.num_r_ports,
OPTS.tech_name)
ports = ""
if OPTS.num_rw_ports>0:
ports += "{}rw_".format(OPTS.num_rw_ports)
if OPTS.num_w_ports>0:
ports += "{}w_".format(OPTS.num_w_ports)
if OPTS.num_r_ports>0:
ports += "{}r_".format(OPTS.num_r_ports)
OPTS.output_name = "sram_{0}b_{1}_{2}{3}".format(OPTS.word_size,
OPTS.num_words,
ports,
OPTS.tech_name)
@ -387,8 +393,6 @@ def report_status():
debug.error("{0} is not an integer in config file.".format(OPTS.word_size))
if type(OPTS.num_words)!=int:
debug.error("{0} is not an integer in config file.".format(OPTS.sram_size))
if type(OPTS.num_banks)!=int:
debug.error("{0} is not an integer in config file.".format(OPTS.num_banks))
if not OPTS.tech_name:
debug.error("Tech name must be specified in config file.")

View File

@ -29,10 +29,6 @@ class bank(design.design):
design.design.__init__(self, name)
debug.info(2, "create sram of size {0} with {1} words".format(self.word_size,self.num_words))
self.total_write = OPTS.num_rw_ports + OPTS.num_w_ports
self.total_read = OPTS.num_rw_ports + OPTS.num_r_ports
self.total_ports = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports
# The local control signals are gated when we have bank select logic,
# so this prefix will be added to all of the input signals to create
@ -53,6 +49,7 @@ class bank(design.design):
self.add_modules()
self.create_modules()
def create_layout(self):
self.place_modules()
self.setup_routing_constraints()
@ -65,19 +62,9 @@ class bank(design.design):
self.bank_center=self.offset_all_coordinates().scale(-1,-1)
self.DRC_LVS()
def add_pins(self):
self.read_index = []
port_number = 0
for port in range(OPTS.num_rw_ports):
self.read_index.append("{}".format(port_number))
port_number += 1
for port in range(OPTS.num_w_ports):
port_number += 1
for port in range(OPTS.num_r_ports):
self.read_index.append("{}".format(port_number))
port_number += 1
""" Adding pins for Bank module"""
for port in range(self.total_read):
for bit in range(self.word_size):
@ -98,11 +85,13 @@ class bank(design.design):
self.add_pin("s_en{0}".format(self.read_index[port]), "INPUT")
for port in range(self.total_write):
self.add_pin("w_en{0}".format(port), "INPUT")
for pin in ["clk_buf_bar","clk_buf"]:
self.add_pin(pin,"INPUT")
for port in range(self.total_ports):
self.add_pin("clk_buf_bar{0}".format(port),"INPUT")
self.add_pin("clk_buf{0}".format(port),"INPUT")
self.add_pin("vdd","POWER")
self.add_pin("gnd","GROUND")
def route_layout(self):
""" Create routing amoung the modules """
self.route_central_bus()
@ -119,6 +108,7 @@ class bank(design.design):
self.route_bank_select()
self.route_vdd_gnd()
def create_modules(self):
""" Add modules. The order should not matter! """
@ -156,10 +146,10 @@ class bank(design.design):
self.place_row_decoder()
self.place_wordline_driver()
self.place_column_decoder()
self.place_bank_select()
def compute_sizes(self):
""" Computes the required sizes to create the bank """
@ -181,13 +171,25 @@ class bank(design.design):
# Number of control lines in the bus
self.num_control_lines = 4
# The order of the control signals on the control bus:
self.input_control_signals = ["clk_buf", "clk_buf_bar", "w_en0", "s_en0"]
self.input_control_signals = []
port_num = 0
for port in range(OPTS.num_rw_ports):
self.input_control_signals.append(["clk_buf{}".format(port_num), "clk_buf_bar{}".format(port_num), "w_en{}".format(port_num), "s_en{}".format(port_num)])
port_num += 1
for port in range(OPTS.num_w_ports):
self.input_control_signals.append(["clk_buf{}".format(port_num), "clk_buf_bar{}".format(port_num), "w_en{}".format(port_num)])
port_num += 1
for port in range(OPTS.num_r_ports):
self.input_control_signals.append(["clk_buf{}".format(port_num), "clk_buf_bar{}".format(port_num), "s_en{}".format(port_num)])
port_num += 1
# These will be outputs of the gaters if this is multibank, if not, normal signals.
if self.num_banks > 1:
self.control_signals = ["gated_"+str for str in self.input_control_signals]
else:
self.control_signals = self.input_control_signals
self.control_signals = []
for port in range(self.total_ports):
if self.num_banks > 1:
self.control_signals.append(["gated_"+str for str in self.input_control_signals[port]])
else:
self.control_signals.append(self.input_control_signals[port])
# The central bus is the column address (one hot) and row address (binary)
if self.col_addr_size>0:
self.num_col_addr_lines = 2**self.col_addr_size
@ -247,8 +249,8 @@ class bank(design.design):
for port in range(self.total_ports):
self.column_mux_array.append(self.mod_column_mux_array(columns=self.num_cols,
word_size=self.word_size,
bitcell_bl=self.read_bl_list[port],
bitcell_br=self.read_br_list[port]))
bitcell_bl=self.total_bl_list[port],
bitcell_br=self.total_br_list[port]))
self.add_mod(self.column_mux_array[port])
@ -292,6 +294,7 @@ class bank(design.design):
temp.append("gnd")
self.connect_inst(temp)
def place_bitcell_array(self):
""" Placing Bitcell Array """
self.bitcell_array_inst.place(vector(0,0))
@ -308,9 +311,10 @@ class bank(design.design):
for i in range(self.num_cols):
temp.append(self.read_bl_list[port]+"[{0}]".format(i))
temp.append(self.read_br_list[port]+"[{0}]".format(i))
temp.extend([self.prefix+"clk_buf_bar", "vdd"])
temp.extend([self.prefix+"clk_buf_bar{0}".format(self.read_index[port]), "vdd"])
self.connect_inst(temp)
def place_precharge_array(self):
""" Placing Precharge """
@ -320,6 +324,7 @@ class bank(design.design):
# The enclosure is for the well and the spacing is to the bitcell wells
y_offset = self.bitcell_array.height + self.m2_gap
self.precharge_array_inst[port].place(vector(0,y_offset))
def create_column_mux_array(self):
""" Creating Column Mux when words_per_row > 1 . """
@ -343,6 +348,7 @@ class bank(design.design):
temp.append("gnd")
self.connect_inst(temp)
def place_column_mux_array(self):
""" Placing Column Mux when words_per_row > 1 . """
if self.col_addr_size > 0:
@ -354,6 +360,7 @@ class bank(design.design):
for port in range(self.total_ports):
y_offset = self.column_mux_height
self.col_mux_array_inst[port].place(vector(0,y_offset).scale(-1,-1))
def create_sense_amp_array(self):
""" Creating Sense amp """
@ -373,9 +380,10 @@ class bank(design.design):
temp.append(self.read_bl_list[port]+"_out[{0}]".format(bit))
temp.append(self.read_br_list[port]+"_out[{0}]".format(bit))
temp.extend([self.prefix+"s_en{0}".format(port), "vdd", "gnd"])
temp.extend([self.prefix+"s_en{}".format(self.read_index[port]), "vdd", "gnd"])
self.connect_inst(temp)
def place_sense_amp_array(self):
""" Placing Sense amp """
@ -383,6 +391,7 @@ class bank(design.design):
for port in range(self.total_read):
y_offset = self.column_mux_height + self.sense_amp_array.height + self.m2_gap
self.sense_amp_array_inst[port].place(vector(0,y_offset).scale(-1,-1))
def create_write_driver_array(self):
""" Creating Write Driver """
@ -405,6 +414,7 @@ class bank(design.design):
temp.extend([self.prefix+"w_en{0}".format(port), "vdd", "gnd"])
self.connect_inst(temp)
def place_write_driver_array(self):
""" Placing Write Driver """
@ -413,7 +423,6 @@ class bank(design.design):
y_offset = self.sense_amp_array.height + self.column_mux_height \
+ self.m2_gap + self.write_driver_array.height
self.write_driver_array_inst[port].place(vector(0,y_offset).scale(-1,-1))
def create_row_decoder(self):
@ -432,6 +441,7 @@ class bank(design.design):
temp.extend(["vdd", "gnd"])
self.connect_inst(temp)
def place_row_decoder(self):
""" Place the hierarchical row decoder """
@ -460,11 +470,12 @@ class bank(design.design):
temp.append("dec_out{0}[{1}]".format(port,row))
for row in range(self.num_rows):
temp.append(self.total_wl_list[port]+"[{0}]".format(row))
temp.append(self.prefix+"clk_buf")
temp.append(self.prefix+"clk_buf{0}".format(port))
temp.append("vdd")
temp.append("gnd")
self.connect_inst(temp)
def place_wordline_driver(self):
""" Place the Wordline Driver """
@ -506,6 +517,7 @@ class bank(design.design):
temp.extend(["vdd", "gnd"])
self.connect_inst(temp)
def place_column_decoder(self):
"""
Place a 2:4 or 3:8 column address decoder.
@ -536,12 +548,13 @@ class bank(design.design):
mod=self.bank_select))
temp = []
temp.extend(self.input_control_signals)
temp.extend(self.input_control_signals[port])
temp.append("bank_sel{}".format(port))
temp.extend(self.control_signals)
temp.extend(self.control_signals[port])
temp.extend(["vdd", "gnd"])
self.connect_inst(temp)
def place_bank_select(self):
""" Place the bank select logic. """
@ -552,9 +565,9 @@ class bank(design.design):
for port in range(self.total_ports):
x_off = -(self.row_decoder.width + self.central_bus_width + self.wordline_driver.width)
if self.col_addr_size > 0:
y_off = min(self.col_decoder_inst[0].by(), self.col_mux_array_inst[0].by())
y_off = min(self.col_decoder_inst[port].by(), self.col_mux_array_inst[port].by())
else:
y_off = self.row_decoder_inst[0].by()
y_off = self.row_decoder_inst[port].by()
y_off -= (self.bank_select.height + drc["well_to_well"])
self.bank_select_pos = vector(x_off,y_off)
self.bank_select_inst[port].place(self.bank_select_pos)
@ -565,18 +578,30 @@ class bank(design.design):
for inst in self.insts:
self.copy_power_pins(inst,"vdd")
self.copy_power_pins(inst,"gnd")
def route_bank_select(self):
""" Route the bank select logic. """
for port in range(self.total_ports):
for input_name in self.input_control_signals+["bank_sel"]:
self.copy_layout_pin(self.bank_select_inst[port], input_name)
for gated_name in self.control_signals:
if self.port_id[port] == "rw":
bank_sel_signals = ["clk_buf", "clk_buf_bar", "w_en", "s_en", "bank_sel"]
gated_bank_sel_signals = ["gated_clk_buf", "gated_clk_buf_bar", "gated_w_en", "gated_s_en"]
elif self.port_id[port] == "w":
bank_sel_signals = ["clk_buf", "clk_buf_bar", "w_en", "bank_sel"]
gated_bank_sel_signals = ["gated_clk_buf", "gated_clk_buf_bar", "gated_w_en"]
else:
bank_sel_signals = ["clk_buf", "clk_buf_bar", "s_en", "bank_sel"]
gated_bank_sel_signals = ["gated_clk_buf", "gated_clk_buf_bar", "gated_s_en"]
copy_control_signals = self.input_control_signals[port]+["bank_sel{}".format(port)]
for signal in range(len(copy_control_signals)):
self.copy_layout_pin(self.bank_select_inst[port], bank_sel_signals[signal], copy_control_signals[signal])
for signal in range(len(gated_bank_sel_signals)):
# Connect the inverter output to the central bus
out_pos = self.bank_select_inst[port].get_pin(gated_name).rc()
bus_pos = vector(self.bus_xoffset[gated_name].x, out_pos.y)
out_pos = self.bank_select_inst[port].get_pin(gated_bank_sel_signals[signal]).rc()
name = self.control_signals[port][signal]
bus_pos = vector(self.bus_xoffset[name].x, out_pos.y)
self.add_path("metal3",[out_pos, bus_pos])
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=bus_pos,
@ -594,7 +619,8 @@ class bank(design.design):
After the modules are instantiated, find the dimensions for the
control bus, power ring, etc.
"""
# FIXME: calculate for multiport
#The minimum point is either the bottom of the address flops,
#the column decoder (if there is one).
write_driver_min_y_offset = self.write_driver_array_inst[0].by() - 3*self.m2_pitch
@ -628,7 +654,6 @@ class bank(design.design):
self.height = ur.y - ll.y
self.width = ur.x - ll.x
def route_central_bus(self):
""" Create the address, supply, and control signal central bus lines. """
@ -637,16 +662,16 @@ class bank(design.design):
# and control lines.
# The bank is at (0,0), so this is to the left of the y-axis.
# 2 pitches on the right for vias/jogs to access the inputs
control_bus_offset = vector(-self.m2_pitch * self.num_control_lines - self.m2_width, self.min_y_offset)
control_bus_length = self.max_y_offset - self.min_y_offset
self.bus_xoffset = self.create_bus(layer="metal2",
pitch=self.m2_pitch,
offset=control_bus_offset,
names=self.control_signals,
length=control_bus_length,
vertical=True,
make_pins=(self.num_banks==1))
for port in range(self.total_ports):
control_bus_offset = vector(-self.m2_pitch * self.num_control_lines - self.m2_width, self.min_y_offset)
control_bus_length = self.max_y_offset - self.min_y_offset
self.bus_xoffset = self.create_bus(layer="metal2",
pitch=self.m2_pitch,
offset=control_bus_offset,
names=self.control_signals[port],
length=control_bus_length,
vertical=True,
make_pins=(self.num_banks==1))
def route_precharge_to_bitcell_array(self):
@ -687,7 +712,8 @@ class bank(design.design):
vector(bitcell_bl.x,yoffset), bitcell_bl])
self.add_path("metal2",[col_mux_br, vector(col_mux_br.x,yoffset),
vector(bitcell_br.x,yoffset), bitcell_br])
def route_sense_amp_to_col_mux_or_bitcell_array(self):
""" Routing of BL and BR between sense_amp and column mux or bitcell array """
@ -711,61 +737,61 @@ class bank(design.design):
vector(connect_bl.x,yoffset), connect_bl])
self.add_path("metal2",[sense_amp_br, vector(sense_amp_br.x,yoffset),
vector(connect_br.x,yoffset), connect_br])
def route_sense_amp_out(self):
""" Add pins for the sense amp output """
# FIXME: Update for multiport
for bit in range(self.word_size):
data_pin = self.sense_amp_array_inst[0].get_pin("data[{}]".format(bit))
self.add_layout_pin_rect_center(text="dout0[{}]".format(bit),
layer=data_pin.layer,
offset=data_pin.center(),
height=data_pin.height(),
width=data_pin.width())
for port in range(self.total_read):
for bit in range(self.word_size):
data_pin = self.sense_amp_array_inst[port].get_pin("data[{}]".format(bit))
self.add_layout_pin_rect_center(text="dout{0}[{1}]".format(self.read_index[port],bit),
layer=data_pin.layer,
offset=data_pin.center(),
height=data_pin.height(),
width=data_pin.width())
def route_row_decoder(self):
""" Routes the row decoder inputs and supplies """
# FIXME: Update for multiport
# Create inputs for the row address lines
for row in range(self.row_addr_size):
addr_idx = row + self.col_addr_size
decoder_name = "addr[{}]".format(row)
addr_name = "addr0[{}]".format(addr_idx)
self.copy_layout_pin(self.row_decoder_inst[0], decoder_name, addr_name)
for port in range(self.total_ports):
for row in range(self.row_addr_size):
addr_idx = row + self.col_addr_size
decoder_name = "addr[{}]".format(row)
addr_name = "addr{0}[{1}]".format(port,addr_idx)
self.copy_layout_pin(self.row_decoder_inst[port], decoder_name, addr_name)
def route_write_driver(self):
""" Connecting write driver """
for row in range(self.word_size):
data_name = "data[{}]".format(row)
din_name = "din0[{}]".format(row)
self.copy_layout_pin(self.write_driver_array_inst[0], data_name, din_name)
for port in range(self.total_ports):
for row in range(self.word_size):
data_name = "data[{}]".format(row)
din_name = "din{0}[{1}]".format(port,row)
self.copy_layout_pin(self.write_driver_array_inst[port], data_name, din_name)
def route_wordline_driver(self):
""" Connecting Wordline driver output to Bitcell WL connection """
for port in range(self.total_ports):
for row in range(self.num_rows):
# The pre/post is to access the pin from "outside" the cell to avoid DRCs
decoder_out_pos = self.row_decoder_inst[port].get_pin("decode[{}]".format(row)).rc()
driver_in_pos = self.wordline_driver_inst[port].get_pin("in[{}]".format(row)).lc()
mid1 = decoder_out_pos.scale(0.5,1)+driver_in_pos.scale(0.5,0)
mid2 = decoder_out_pos.scale(0.5,0)+driver_in_pos.scale(0.5,1)
self.add_path("metal1", [decoder_out_pos, mid1, mid2, driver_in_pos])
for row in range(self.num_rows):
# The pre/post is to access the pin from "outside" the cell to avoid DRCs
decoder_out_pos = self.row_decoder_inst[0].get_pin("decode[{}]".format(row)).rc()
driver_in_pos = self.wordline_driver_inst[0].get_pin("in[{}]".format(row)).lc()
mid1 = decoder_out_pos.scale(0.5,1)+driver_in_pos.scale(0.5,0)
mid2 = decoder_out_pos.scale(0.5,0)+driver_in_pos.scale(0.5,1)
self.add_path("metal1", [decoder_out_pos, mid1, mid2, driver_in_pos])
# The mid guarantees we exit the input cell to the right.
driver_wl_pos = self.wordline_driver_inst[0].get_pin("wl[{}]".format(row)).rc()
bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.total_wl_list[0]+"[{}]".format(row)).lc()
mid1 = driver_wl_pos.scale(0.5,1)+bitcell_wl_pos.scale(0.5,0)
mid2 = driver_wl_pos.scale(0.5,0)+bitcell_wl_pos.scale(0.5,1)
self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos])
# The mid guarantees we exit the input cell to the right.
driver_wl_pos = self.wordline_driver_inst[port].get_pin("wl[{}]".format(row)).rc()
bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.total_wl_list[port]+"[{}]".format(row)).lc()
mid1 = driver_wl_pos.scale(0.5,1)+bitcell_wl_pos.scale(0.5,0)
mid2 = driver_wl_pos.scale(0.5,0)+bitcell_wl_pos.scale(0.5,1)
self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos])
def route_column_address_lines(self):
@ -773,49 +799,45 @@ class bank(design.design):
if not self.col_addr_size>0:
return
if self.col_addr_size == 1:
# Connect to sel[0] and sel[1]
decode_names = ["Zb", "Z"]
# The Address LSB
self.copy_layout_pin(self.col_decoder_inst[0], "A", "addr0[0]")
elif self.col_addr_size > 1:
decode_names = []
for i in range(self.num_col_addr_lines):
decode_names.append("out[{}]".format(i))
for i in range(self.col_addr_size):
decoder_name = "in[{}]".format(i)
addr_name = "addr0[{}]".format(i)
self.copy_layout_pin(self.col_decoder_inst[0], decoder_name, addr_name)
for port in range(self.total_ports):
if self.col_addr_size == 1:
# Connect to sel[0] and sel[1]
decode_names = ["Zb", "Z"]
# The Address LSB
self.copy_layout_pin(self.col_decoder_inst[port], "A", "addr{}[0]".format(port))
elif self.col_addr_size > 1:
decode_names = []
for i in range(self.num_col_addr_lines):
decode_names.append("out[{}]".format(i))
# This will do a quick "river route" on two layers.
# When above the top select line it will offset "inward" again to prevent conflicts.
# This could be done on a single layer, but we follow preferred direction rules for later routing.
top_y_offset = self.col_mux_array_inst[0].get_pin("sel[{}]".format(self.num_col_addr_lines-1)).cy()
for (decode_name,i) in zip(decode_names,range(self.num_col_addr_lines)):
mux_name = "sel[{}]".format(i)
mux_addr_pos = self.col_mux_array_inst[0].get_pin(mux_name).lc()
decode_out_pos = self.col_decoder_inst[0].get_pin(decode_name).center()
for i in range(self.col_addr_size):
decoder_name = "in[{}]".format(i)
addr_name = "addr{0}[{1}]".format(port,i)
self.copy_layout_pin(self.col_decoder_inst[port], decoder_name, addr_name)
# To get to the edge of the decoder and one track out
delta_offset = self.col_decoder_inst[0].rx() - decode_out_pos.x + self.m2_pitch
if decode_out_pos.y > top_y_offset:
mid1_pos = vector(decode_out_pos.x + delta_offset + i*self.m2_pitch,decode_out_pos.y)
else:
mid1_pos = vector(decode_out_pos.x + delta_offset + (self.num_col_addr_lines-i)*self.m2_pitch,decode_out_pos.y)
mid2_pos = vector(mid1_pos.x,mux_addr_pos.y)
#self.add_wire(("metal1","via1","metal2"),[decode_out_pos, mid1_pos, mid2_pos, mux_addr_pos])
self.add_path("metal1",[decode_out_pos, mid1_pos, mid2_pos, mux_addr_pos])
# This will do a quick "river route" on two layers.
# When above the top select line it will offset "inward" again to prevent conflicts.
# This could be done on a single layer, but we follow preferred direction rules for later routing.
top_y_offset = self.col_mux_array_inst[port].get_pin("sel[{}]".format(self.num_col_addr_lines-1)).cy()
for (decode_name,i) in zip(decode_names,range(self.num_col_addr_lines)):
mux_name = "sel[{}]".format(i)
mux_addr_pos = self.col_mux_array_inst[port].get_pin(mux_name).lc()
decode_out_pos = self.col_decoder_inst[port].get_pin(decode_name).center()
# To get to the edge of the decoder and one track out
delta_offset = self.col_decoder_inst[port].rx() - decode_out_pos.x + self.m2_pitch
if decode_out_pos.y > top_y_offset:
mid1_pos = vector(decode_out_pos.x + delta_offset + i*self.m2_pitch,decode_out_pos.y)
else:
mid1_pos = vector(decode_out_pos.x + delta_offset + (self.num_col_addr_lines-i)*self.m2_pitch,decode_out_pos.y)
mid2_pos = vector(mid1_pos.x,mux_addr_pos.y)
#self.add_wire(("metal1","via1","metal2"),[decode_out_pos, mid1_pos, mid2_pos, mux_addr_pos])
self.add_path("metal1",[decode_out_pos, mid1_pos, mid2_pos, mux_addr_pos])
def add_lvs_correspondence_points(self):
@ -869,30 +891,39 @@ class bank(design.design):
# From control signal to the module pin
# Connection from the central bus to the main control block crosses
# pre-decoder and this connection is in metal3
connection = []
connection.append((self.prefix+"clk_buf_bar", self.precharge_array_inst[0].get_pin("en").lc()))
connection.append((self.prefix+"w_en0", self.write_driver_array_inst[0].get_pin("en").lc()))
connection.append((self.prefix+"s_en0", self.sense_amp_array_inst[0].get_pin("en").lc()))
for (control_signal, pin_pos) in connection:
control_pos = vector(self.bus_xoffset[control_signal].x ,pin_pos.y)
self.add_path("metal1", [control_pos, pin_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=control_pos,
rotate=90)
# clk to wordline_driver
control_signal = self.prefix+"clk_buf"
pin_pos = self.wordline_driver_inst[0].get_pin("en").uc()
mid_pos = pin_pos + vector(0,self.m1_pitch)
control_x_offset = self.bus_xoffset[control_signal].x
control_pos = vector(control_x_offset + self.m1_width, mid_pos.y)
self.add_wire(("metal1","via1","metal2"),[pin_pos, mid_pos, control_pos])
control_via_pos = vector(control_x_offset, mid_pos.y)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=control_via_pos,
rotate=90)
write_inst = 0
read_inst = 0
# Control lines for RW ports
for port in range(self.total_ports):
connection = []
if (self.port_id[port] == "rw") or (self.port_id[port] == "r"):
connection.append((self.prefix+"clk_buf_bar{}".format(port), self.precharge_array_inst[read_inst].get_pin("en").lc()))
if (self.port_id[port] == "rw") or (self.port_id[port] == "w"):
connection.append((self.prefix+"w_en{}".format(port), self.write_driver_array_inst[write_inst].get_pin("en").lc()))
write_inst += 1
if (self.port_id[port] == "rw") or (self.port_id[port] == "r"):
connection.append((self.prefix+"s_en{}".format(port), self.sense_amp_array_inst[read_inst].get_pin("en").lc()))
read_inst += 1
for (control_signal, pin_pos) in connection:
control_pos = vector(self.bus_xoffset[control_signal].x ,pin_pos.y)
self.add_path("metal1", [control_pos, pin_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=control_pos,
rotate=90)
# clk to wordline_driver
control_signal = self.prefix+"clk_buf{}".format(port)
pin_pos = self.wordline_driver_inst[port].get_pin("en").uc()
mid_pos = pin_pos + vector(0,self.m1_pitch)
control_x_offset = self.bus_xoffset[control_signal].x
control_pos = vector(control_x_offset + self.m1_width, mid_pos.y)
self.add_wire(("metal1","via1","metal2"),[pin_pos, mid_pos, control_pos])
control_via_pos = vector(control_x_offset, mid_pos.y)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=control_via_pos,
rotate=90)
def analytical_delay(self, slew, load):

View File

@ -15,9 +15,11 @@ class bank_select(design.design):
banks are created in upper level SRAM module
"""
def __init__(self, name="bank_select"):
def __init__(self, name="bank_select", port="rw"):
design.design.__init__(self, name)
self.port = port
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
@ -38,10 +40,17 @@ class bank_select(design.design):
def add_pins(self):
# Number of control lines in the bus
self.num_control_lines = 4
if self.port == "rw":
self.num_control_lines = 4
else:
self.num_control_lines = 3
# The order of the control signals on the control bus:
# FIXME: Update for multiport (these names are not right)
self.input_control_signals = ["clk_buf", "clk_buf_bar", "w_en0", "s_en0"]
self.input_control_signals = ["clk_buf", "clk_buf_bar"]
if (self.port == "rw") or (self.port == "w"):
self.input_control_signals.append("w_en")
if (self.port == "rw") or (self.port == "r"):
self.input_control_signals.append("s_en")
# These will be outputs of the gaters if this is multibank
self.control_signals = ["gated_"+str for str in self.input_control_signals]
@ -53,16 +62,26 @@ class bank_select(design.design):
def add_modules(self):
""" Create modules for later instantiation """
from importlib import reload
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell()
height = self.bitcell.height + drc["poly_to_active"]
# 1x Inverter
self.inv = pinv()
self.add_mod(self.inv)
self.inv_sel = pinv(height=height)
self.add_mod(self.inv_sel)
# 4x Inverter
self.inv4x = pinv(4)
self.inv = self.inv4x = pinv(4)
self.add_mod(self.inv4x)
self.nor2 = pnor2()
self.nor2 = pnor2(height=height)
self.add_mod(self.nor2)
self.inv4x_nor = pinv(size=4, height=height)
self.add_mod(self.inv4x_nor)
self.nand2 = pnand2()
self.add_mod(self.nand2)
@ -83,7 +102,7 @@ class bank_select(design.design):
def create_modules(self):
self.bank_sel_inv=self.add_inst(name="bank_sel_inv",
mod=self.inv)
mod=self.inv_sel)
self.connect_inst(["bank_sel", "bank_sel_bar", "vdd", "gnd"])
self.logic_inst = []
@ -107,6 +126,14 @@ class bank_select(design.design):
"vdd",
"gnd"])
# They all get inverters on the output
self.inv_inst.append(self.add_inst(name=name_inv,
mod=self.inv4x_nor))
self.connect_inst([gated_name+"_temp_bar",
gated_name,
"vdd",
"gnd"])
# the rest are AND (nand2+inv) gates
else:
self.logic_inst.append(self.add_inst(name=name_nand,
@ -117,13 +144,13 @@ class bank_select(design.design):
"vdd",
"gnd"])
# They all get inverters on the output
self.inv_inst.append(self.add_inst(name=name_inv,
mod=self.inv4x))
self.connect_inst([gated_name+"_temp_bar",
gated_name,
"vdd",
"gnd"])
# They all get inverters on the output
self.inv_inst.append(self.add_inst(name=name_inv,
mod=self.inv4x))
self.connect_inst([gated_name+"_temp_bar",
gated_name,
"vdd",
"gnd"])
def place_modules(self):
@ -140,7 +167,11 @@ class bank_select(design.design):
input_name = self.input_control_signals[i]
y_offset = self.inv.height * i
if i == 0:
y_offset = 0
else:
y_offset = self.inv4x_nor.height + self.inv.height * (i-1)
if i%2:
y_offset += self.inv.height
mirror = "MX"

View File

@ -18,12 +18,19 @@ class control_logic(design.design):
Dynamically generated Control logic for the total SRAM circuit.
"""
def __init__(self, num_rows):
def __init__(self, num_rows, port_type="rw"):
""" Constructor """
design.design.__init__(self, "control_logic")
debug.info(1, "Creating {}".format(self.name))
name = "control_logic_" + port_type
design.design.__init__(self, name)
debug.info(1, "Creating {}".format(name))
self.num_rows = num_rows
self.port_type = port_type
if self.port_type == "rw":
self.num_control_signals = 2
else:
self.num_control_signals = 1
self.create_netlist()
if not OPTS.netlist_only:
@ -41,7 +48,7 @@ class control_logic(design.design):
self.place_modules()
self.route_all()
self.add_lvs_correspondence_points()
#self.add_lvs_correspondence_points()
self.DRC_LVS()
@ -61,7 +68,7 @@ class control_logic(design.design):
dff = dff_inv()
dff_height = dff.height
self.ctrl_dff_array = dff_inv_array(rows=2,columns=1)
self.ctrl_dff_array = dff_inv_array(rows=self.num_control_signals,columns=1)
self.add_mod(self.ctrl_dff_array)
self.nand2 = pnand2(height=dff_height)
@ -81,29 +88,50 @@ class control_logic(design.design):
self.inv8 = pinv(size=16, height=dff_height)
self.add_mod(self.inv8)
from importlib import reload
c = reload(__import__(OPTS.replica_bitline))
replica_bitline = getattr(c, OPTS.replica_bitline)
# FIXME: These should be tuned according to the size!
delay_stages = 4 # Must be non-inverting
delay_fanout = 3 # This can be anything >=2
bitcell_loads = int(math.ceil(self.num_rows / 5.0))
self.replica_bitline = replica_bitline(delay_stages, delay_fanout, bitcell_loads)
self.add_mod(self.replica_bitline)
if (self.port_type == "rw") or (self.port_type == "r"):
from importlib import reload
c = reload(__import__(OPTS.replica_bitline))
replica_bitline = getattr(c, OPTS.replica_bitline)
# FIXME: These should be tuned according to the size!
delay_stages = 4 # Must be non-inverting
delay_fanout = 3 # This can be anything >=2
bitcell_loads = int(math.ceil(self.num_rows / 5.0))
self.replica_bitline = replica_bitline(delay_stages, delay_fanout, bitcell_loads, name="replica_bitline_"+self.port_type)
self.add_mod(self.replica_bitline)
def setup_signal_busses(self):
""" Setup bus names, determine the size of the busses etc """
# List of input control signals
self.input_list =["csb","web0"]
self.dff_output_list =["cs_bar", "cs", "we_bar", "we"]
if self.port_type == "rw":
self.input_list = ["csb", "web"]
else:
self.input_list = ["csb"]
if self.port_type == "rw":
self.dff_output_list = ["cs_bar", "cs", "we_bar", "we"]
else:
self.dff_output_list = ["cs_bar", "cs"]
# list of output control signals (for making a vertical bus)
self.internal_bus_list = ["clk_buf", "clk_buf_bar", "we", "cs"]
if self.port_type == "rw":
self.internal_bus_list = ["clk_buf", "clk_buf_bar", "we", "cs"]
else:
self.internal_bus_list = ["clk_buf", "clk_buf_bar", "cs"]
# leave space for the bus plus one extra space
self.internal_bus_width = (len(self.internal_bus_list)+1)*self.m2_pitch
# Outputs to the bank
self.output_list = ["s_en0", "w_en0", "clk_buf_bar", "clk_buf"]
if self.port_type == "r":
self.output_list = ["s_en"]
elif self.port_type == "w":
self.output_list = ["w_en"]
else:
self.output_list = ["s_en", "w_en"]
self.output_list.append("clk_buf_bar")
self.output_list.append("clk_buf")
self.supply_list = ["vdd", "gnd"]
@ -118,14 +146,13 @@ class control_logic(design.design):
def create_modules(self):
""" Create all the modules """
self.create_dffs()
self.create_clk_row()
self.create_we_row()
# self.create_trien_row()
# self.create_trien_bar_row()
self.create_rbl_in_row()
self.create_sen_row()
self.create_rbl()
self.create_clk_row()
if (self.port_type == "rw") or (self.port_type == "w"):
self.create_we_row()
if (self.port_type == "rw") or (self.port_type == "r"):
self.create_rbl_in_row()
self.create_sen_row()
self.create_rbl()
def place_modules(self):
@ -134,38 +161,44 @@ class control_logic(design.design):
# and add the vdd/gnd pins
self.row_end_inst = []
# Add the control flops on the left of the bus
self.place_dffs()
row = 0
# Add the logic on the right of the bus
self.place_clk_row(row=0) # clk is a double-high cell
self.place_we_row(row=2)
# self.place_trien_row(row=3)
# self.place_trien_bar_row(row=4)
self.place_rbl_in_row(row=3)
self.place_sen_row(row=4)
self.place_rbl(row=5)
self.place_clk_row(row=row) # clk is a double-high cell
row += 2
if (self.port_type == "rw") or (self.port_type == "w"):
self.place_we_row(row=row)
pre_height = self.w_en_inst.uy()
control_center_y = self.w_en_inst.by()
row += 1
if (self.port_type == "rw") or (self.port_type == "r"):
self.place_rbl_in_row(row=row)
self.place_sen_row(row=row+1)
self.place_rbl(row=row+2)
pre_height = self.rbl_inst.uy()
control_center_y = self.rbl_inst.by()
# This offset is used for placement of the control logic in
# the SRAM level.
self.control_logic_center = vector(self.ctrl_dff_inst.rx(), self.rbl_inst.by())
# This offset is used for placement of the control logic in the SRAM level.
self.control_logic_center = vector(self.ctrl_dff_inst.rx(), control_center_y)
# Extra pitch on top and right
self.height = self.rbl_inst.uy() + self.m3_pitch
self.height = pre_height + self.m3_pitch
# Max of modules or logic rows
self.width = max(self.rbl_inst.rx(), max([inst.rx() for inst in self.row_end_inst])) + self.m2_pitch
if (self.port_type == "rw") or (self.port_type == "r"):
self.width = max(self.rbl_inst.rx(), max([inst.rx() for inst in self.row_end_inst])) + self.m2_pitch
else:
self.width = max([inst.rx() for inst in self.row_end_inst]) + self.m2_pitch
def route_all(self):
""" Routing between modules """
self.route_dffs()
#self.route_trien()
#self.route_trien_bar()
self.route_rbl_in()
self.route_wen()
self.route_sen()
if (self.port_type == "rw") or (self.port_type == "w"):
self.route_wen()
if (self.port_type == "rw") or (self.port_type == "r"):
self.route_rbl_in()
self.route_sen()
self.route_clk()
self.route_supply()
@ -202,7 +235,7 @@ class control_logic(design.design):
def create_rbl_in_row(self):
self.rbl_in_bar_inst=self.add_inst(name="nand3_rbl_in_bar",
self.rbl_in_bar_inst=self.add_inst(name="nand2_rbl_in_bar",
mod=self.nand2)
self.connect_inst(["clk_buf_bar", "cs", "rbl_in_bar", "vdd", "gnd"])
@ -238,7 +271,7 @@ class control_logic(design.design):
# input: input: pre_s_en_bar, output: s_en
self.s_en_inst=self.add_inst(name="inv_s_en",
mod=self.inv8)
self.connect_inst(["pre_s_en_bar", "s_en0", "vdd", "gnd"])
self.connect_inst(["pre_s_en_bar", "s_en", "vdd", "gnd"])
def place_sen_row(self,row):
"""
@ -262,7 +295,11 @@ class control_logic(design.design):
def route_dffs(self):
""" Route the input inverters """
dff_out_map = zip(["dout_bar[{}]".format(i) for i in range(3)], ["cs", "we"])
if self.port_type == "r":
control_inputs = ["cs"]
else:
control_inputs = ["cs", "we"]
dff_out_map = zip(["dout_bar[{}]".format(i) for i in range(2*self.num_control_signals - 1)], control_inputs)
self.connect_vertical_bus(dff_out_map, self.ctrl_dff_inst, self.rail_offsets)
# Connect the clock rail to the other clock rail
@ -275,7 +312,8 @@ class control_logic(design.design):
rotate=90)
self.copy_layout_pin(self.ctrl_dff_inst, "din[0]", "csb")
self.copy_layout_pin(self.ctrl_dff_inst, "din[1]", "web0")
if (self.port_type == "rw"):
self.copy_layout_pin(self.ctrl_dff_inst, "din[1]", "web")
def create_dffs(self):
@ -302,23 +340,30 @@ class control_logic(design.design):
def create_we_row(self):
# input: WE, CS output: w_en_bar
self.w_en_bar_inst=self.add_inst(name="nand3_w_en_bar",
mod=self.nand3)
self.connect_inst(["clk_buf_bar", "cs", "we", "w_en_bar", "vdd", "gnd"])
if self.port_type == "rw":
nand_mod = self.nand3
temp = ["clk_buf_bar", "cs", "we", "w_en_bar", "vdd", "gnd"]
else:
nand_mod = self.nand2
temp = ["clk_buf_bar", "cs", "w_en_bar", "vdd", "gnd"]
self.w_en_bar_inst = self.add_inst(name="nand3_w_en_bar",
mod=nand_mod)
self.connect_inst(temp)
# input: w_en_bar, output: pre_w_en
self.pre_w_en_inst=self.add_inst(name="inv_pre_w_en",
mod=self.inv1)
self.connect_inst(["w_en_bar", "pre_w_en", "vdd", "gnd"])
self.pre_w_en_inst = self.add_inst(name="inv_pre_w_en",
mod=self.inv1)
self.connect_inst(["w_en_bar", "pre_w_en", "vdd", "gnd"])
# BUFFER INVERTERS FOR W_EN
self.pre_w_en_bar_inst=self.add_inst(name="inv_pre_w_en_bar",
mod=self.inv2)
self.connect_inst(["pre_w_en", "pre_w_en_bar", "vdd", "gnd"])
self.pre_w_en_bar_inst = self.add_inst(name="inv_pre_w_en_bar",
mod=self.inv2)
self.connect_inst(["pre_w_en", "pre_w_en_bar", "vdd", "gnd"])
self.w_en_inst=self.add_inst(name="inv_w_en2",
mod=self.inv8)
self.connect_inst(["pre_w_en_bar", "w_en0", "vdd", "gnd"])
self.w_en_inst = self.add_inst(name="inv_w_en2",
mod=self.inv8)
self.connect_inst(["pre_w_en_bar", "w_en", "vdd", "gnd"])
def place_we_row(self,row):
@ -328,7 +373,10 @@ class control_logic(design.design):
w_en_bar_offset = vector(x_off, y_off)
self.w_en_bar_inst.place(offset=w_en_bar_offset,
mirror=mirror)
x_off += self.nand3.width
if self.port_type == "rw":
x_off += self.nand3.width
else:
x_off += self.nand2.width
pre_w_en_offset = vector(x_off, y_off)
self.pre_w_en_inst.place(offset=pre_w_en_offset,
@ -422,7 +470,10 @@ class control_logic(design.design):
def route_wen(self):
wen_map = zip(["A", "B", "C"], ["clk_buf_bar", "cs", "we"])
if self.port_type == "rw":
wen_map = zip(["A", "B", "C"], ["clk_buf_bar", "cs", "we"])
else:
wen_map = zip(["A", "B"], ["clk_buf_bar", "cs"])
self.connect_vertical_bus(wen_map, self.w_en_bar_inst, self.rail_offsets)
# Connect the NAND3 output to the inverter
@ -435,7 +486,7 @@ class control_logic(design.design):
self.add_path("metal1",[self.pre_w_en_inst.get_pin("Z").center(), self.pre_w_en_bar_inst.get_pin("A").center()])
self.add_path("metal1",[self.pre_w_en_bar_inst.get_pin("Z").center(), self.w_en_inst.get_pin("A").center()])
self.connect_output(self.w_en_inst, "Z", "w_en0")
self.connect_output(self.w_en_inst, "Z", "w_en")
def route_sen(self):
rbl_out_pos = self.rbl_inst.get_pin("out").bc()
@ -446,7 +497,7 @@ class control_logic(design.design):
self.add_path("metal1",[self.pre_s_en_bar_inst.get_pin("Z").center(), self.s_en_inst.get_pin("A").center()])
self.connect_output(self.s_en_inst, "Z", "s_en0")
self.connect_output(self.s_en_inst, "Z", "s_en")
def route_clk(self):
""" Route the clk and clk_buf_bar signal internally """
@ -498,9 +549,9 @@ class control_logic(design.design):
self.add_power_pin("gnd", pin_loc)
self.add_path("metal1", [row_loc, pin_loc])
self.copy_layout_pin(self.rbl_inst,"gnd")
self.copy_layout_pin(self.rbl_inst,"vdd")
if (self.port_type == "rw") or (self.port_type == "r"):
self.copy_layout_pin(self.rbl_inst,"gnd")
self.copy_layout_pin(self.rbl_inst,"vdd")
self.copy_layout_pin(self.ctrl_dff_inst,"gnd")
self.copy_layout_pin(self.ctrl_dff_inst,"vdd")

View File

@ -13,8 +13,12 @@ class delay_chain(design.design):
Usually, this will be constant, but it could have varied fanout.
"""
unique_id = 1
def __init__(self, fanout_list, name="delay_chain"):
"""init function"""
name = name+"_{}".format(delay_chain.unique_id)
delay_chain.unique_id += 1
design.design.__init__(self, name)
# Two fanouts are needed so that we can route the vdd/gnd connections

View File

@ -81,8 +81,8 @@ class replica_bitline(design.design):
""" Add the modules for later usage """
from importlib import reload
g = reload(__import__(OPTS.delay_chain))
self.mod_delay_chain = getattr(g, OPTS.delay_chain)
#g = reload(__import__(OPTS.delay_chain))
#self.mod_delay_chain = getattr(g, OPTS.delay_chain)
g = reload(__import__(OPTS.replica_bitcell))
self.mod_replica_bitcell = getattr(g, OPTS.replica_bitcell)
@ -95,7 +95,8 @@ class replica_bitline(design.design):
self.add_mod(self.rbl)
# FIXME: The FO and depth of this should be tuned
self.delay_chain = self.mod_delay_chain([self.delay_fanout]*self.delay_stages)
from delay_chain import delay_chain
self.delay_chain = delay_chain([self.delay_fanout]*self.delay_stages)
self.add_mod(self.delay_chain)
self.inv = pinv()
@ -110,12 +111,12 @@ class replica_bitline(design.design):
# This is the threshold detect inverter on the output of the RBL
self.rbl_inv_inst=self.add_inst(name="rbl_inv",
mod=self.inv)
self.connect_inst(["bl[0]", "out", "vdd", "gnd"])
self.connect_inst(["bl0[0]", "out", "vdd", "gnd"])
self.tx_inst=self.add_inst(name="rbl_access_tx",
mod=self.access_tx)
# D, G, S, B
self.connect_inst(["vdd", "delayed_en", "bl[0]", "vdd"])
self.connect_inst(["vdd", "delayed_en", "bl0[0]", "vdd"])
# add the well and poly contact
self.dc_inst=self.add_inst(name="delay_chain",
@ -124,26 +125,33 @@ class replica_bitline(design.design):
self.rbc_inst=self.add_inst(name="bitcell",
mod=self.replica_bitcell)
self.connect_inst(["bl[0]", "br[0]", "delayed_en", "vdd", "gnd"])
temp = []
for port in range(self.total_ports):
temp.append("bl{}[0]".format(port))
temp.append("br{}[0]".format(port))
for port in range(self.total_ports):
temp.append("delayed_en")
temp.append("vdd")
temp.append("gnd")
self.connect_inst(temp)
#self.connect_inst(["bl[0]", "br[0]", "delayed_en", "vdd", "gnd"])
self.rbl_inst=self.add_inst(name="load",
mod=self.rbl)
total_ports = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports
temp = []
temp.append("bl[0]")
temp.append("br[0]")
for port in range(total_ports - 1):
temp.append("gnd")
temp.append("gnd")
for port in range(self.total_ports):
temp.append("bl{}[0]".format(port))
temp.append("br{}[0]".format(port))
for wl in range(self.bitcell_loads):
for port in range(total_ports):
for port in range(self.total_ports):
temp.append("gnd")
temp.append("vdd")
temp.append("gnd")
self.connect_inst(temp)
self.wl_list = self.rbl.cell.list_all_wl_names()
self.bl_list = self.rbl.cell.list_write_bl_names()
def place_modules(self):
""" Add all of the module instances in the logical netlist """
@ -160,9 +168,6 @@ class replica_bitline(design.design):
mirror="MX")
self.rbl_inst.place(self.rbl_offset)
def route(self):
@ -178,15 +183,27 @@ class replica_bitline(design.design):
wl = self.wl_list[0]+"[{}]".format(row)
pin = self.rbl_inst.get_pin(wl)
# 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
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_extension = pin_right + vector(self.m1_pitch,0)
pin_extension1 = pin_right + vector(self.m3_pitch,0)
pin_extension2 = pin_extension1 + vertical_extension
if pin.layer != "metal1":
continue
self.add_path("metal1", [pin_right, pin_extension])
self.add_power_pin("gnd", pin_extension)
self.add_path("metal1", [pin_right, pin_extension1, pin_extension2])
self.add_power_pin("gnd", pin_extension2)
# 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)
pin_last = self.rbl_inst.get_pin(wl_last)
correct = vector(0.5*drc["minwidth_metal1"], 0)
self.add_path("metal1", [pin.rc()-correct, pin_last.rc()-correct])
def route_supplies(self):
""" Propagate all vdd/gnd pins up to this level for all modules """
@ -243,11 +260,22 @@ class replica_bitline(design.design):
# 3. Route the contact of previous route to the bitcell WL
# route bend of previous net to bitcell WL
wl_offset = self.rbc_inst.get_pin("wl").lc()
xmid_point= 0.5*(wl_offset.x+contact_offset.x)
wl_mid1 = vector(xmid_point,contact_offset.y)
wl_mid2 = vector(xmid_point,wl_offset.y)
self.add_path("metal1", [contact_offset, wl_mid1, wl_mid2, wl_offset])
wl_offset = self.rbc_inst.get_pin(self.wl_list[0]).lc()
wl_mid1 = wl_offset - vector(1.5*drc["minwidth_metal1"], 0)
wl_mid2 = vector(wl_mid1.x, contact_offset.y)
#xmid_point= 0.5*(wl_offset.x+contact_offset.x)
#wl_mid1 = vector(xmid_point,contact_offset.y)
#wl_mid2 = vector(xmid_point,wl_offset.y)
self.add_path("metal1", [wl_offset, wl_mid1, wl_mid2, contact_offset])
# 4. Short wodlines if multiport
wl = self.wl_list[0]
wl_last = self.wl_list[self.total_ports-1]
pin = self.rbc_inst.get_pin(wl)
pin_last = self.rbc_inst.get_pin(wl_last)
correct = vector(0.5*drc["minwidth_metal1"], 0)
self.add_path("metal1", [pin.lc()+correct, pin_last.lc()+correct])
# DRAIN ROUTE
# Route the drain to the vdd rail
@ -262,7 +290,7 @@ class replica_bitline(design.design):
# Route the connection of the source route to the RBL bitline (left)
# Via will go halfway down from the bitcell
bl_offset = self.rbc_inst.get_pin("bl").bc()
bl_offset = self.rbc_inst.get_pin(self.bl_list[0]).bc()
# Route down a pitch so we can use M2 routing
bl_down_offset = bl_offset - vector(0, self.m2_pitch)
self.add_path("metal2",[source_offset, bl_down_offset, bl_offset])

View File

@ -0,0 +1,82 @@
import debug
import design
from tech import drc, spice
from vector import vector
from globals import OPTS
from pbitcell import pbitcell
class replica_pbitcell(design.design):
"""
Creates a replica bitcell using pbitcell
"""
def __init__(self):
self.num_rw_ports = OPTS.num_rw_ports
self.num_w_ports = OPTS.num_w_ports
self.num_r_ports = OPTS.num_r_ports
self.total_ports = self.num_rw_ports + self.num_w_ports + self.num_r_ports
design.design.__init__(self, "replica_pbitcell")
debug.info(1, "create a replica bitcell using pbitcell with {0} rw ports, {1} w ports and {2} r ports".format(self.num_rw_ports,
self.num_w_ports,
self.num_r_ports))
self.create_netlist()
self.create_layout()
def create_netlist(self):
self.add_pins()
self.add_modules()
self.create_modules()
def create_layout(self):
self.place_pbitcell()
self.route_rbc_connections()
self.DRC_LVS()
def add_pins(self):
for port in range(self.total_ports):
self.add_pin("bl{}".format(port))
self.add_pin("br{}".format(port))
for port in range(self.total_ports):
self.add_pin("wl{}".format(port))
self.add_pin("vdd")
self.add_pin("gnd")
def add_modules(self):
self.prbc = pbitcell(replica_bitcell=True)
self.add_mod(self.prbc)
self.height = self.prbc.height
self.width = self.prbc.width
def create_modules(self):
self.prbc_inst = self.add_inst(name="pbitcell",
mod=self.prbc)
temp = []
for port in range(self.total_ports):
temp.append("bl{}".format(port))
temp.append("br{}".format(port))
for port in range(self.total_ports):
temp.append("wl{}".format(port))
temp.append("vdd")
temp.append("gnd")
self.connect_inst(temp)
def place_pbitcell(self):
offset = [0,0]
self.prbc_inst.place(offset=offset)
def route_rbc_connections(self):
for port in range(self.total_ports):
self.copy_layout_pin(self.prbc_inst, "bl{}".format(port))
self.copy_layout_pin(self.prbc_inst, "br{}".format(port))
for port in range(self.total_ports):
self.copy_layout_pin(self.prbc_inst, "wl{}".format(port))
self.copy_layout_pin(self.prbc_inst, "vdd")
self.copy_layout_pin(self.prbc_inst, "gnd")

View File

@ -50,8 +50,6 @@ class options(optparse.Values):
analytical_delay = True
# Purge the temp directory after a successful run (doesn't purge on errors, anyhow)
purge_temp = True
# Determines whether multi-port portion of unit tests are run or not
multiport_check = True
# These are the configuration parameters
num_rw_ports = 1
@ -66,9 +64,11 @@ class options(optparse.Values):
# These are the main configuration parameters that should be over-ridden
# in a configuration file.
#num_words = 0
#num_banks = 1
#word_size = 0
# You can manually specify banks, but it is better to auto-detect it.
num_banks = 1
# These are the default modules that can be over-riden
decoder = "hierarchical_decoder"
dff_array = "dff_array"

View File

@ -41,8 +41,9 @@ class ptx(design.design):
self.num_contacts = num_contacts
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
# We must always create ptx layout for pbitcell
# some transistor sizes in other netlist depend on pbitcell
self.create_layout()

View File

@ -1,6 +1,5 @@
word_size = 1
num_words = 16
num_banks = 1
tech_name = "freepdk45"
process_corners = ["TT"]

View File

@ -1,6 +1,5 @@
word_size = 1
num_words = 16
num_banks = 1
tech_name = "scn4m_subm"
process_corners = ["TT"]

View File

@ -34,9 +34,7 @@ class sram_1bank(sram_base):
self.bank_inst=self.create_bank(0)
self.control_logic_inst = [None] * self.total_ports
for port in range(self.total_ports):
self.control_logic_inst[port] = self.create_control_logic(port)
self.control_logic_inst = self.create_control_logic()
self.row_addr_dff_inst = self.create_row_addr_dff()
@ -59,60 +57,60 @@ class sram_1bank(sram_base):
# the sense amps/column mux and cell array)
# The x-coordinate is placed to allow a single clock wire (plus an extra pitch)
# up to the row address DFFs.
control_pos = vector(-self.control_logic.width - 2*self.m2_pitch,
self.bank.bank_center.y - self.control_logic.control_logic_center.y)
self.control_logic_inst[0].place(control_pos)
for port in range(self.total_ports):
control_pos = vector(-self.control_logic.width - 2*self.m2_pitch,
self.bank.bank_center.y - self.control_logic.control_logic_center.y)
self.control_logic_inst[port].place(control_pos)
# The row address bits are placed above the control logic aligned on the right.
row_addr_pos = vector(self.control_logic_inst[0].rx() - self.row_addr_dff.width,
self.control_logic_inst[0].uy())
self.row_addr_dff_inst.place(row_addr_pos)
# The row address bits are placed above the control logic aligned on the right.
row_addr_pos = vector(self.control_logic_inst[0].rx() - self.row_addr_dff.width,
self.control_logic_inst[0].uy())
self.row_addr_dff_inst[port].place(row_addr_pos)
# This is M2 pitch even though it is on M1 to help stem via spacings on the trunk
data_gap = -self.m2_pitch*(self.word_size+1)
# Add the column address below the bank under the control
# The column address flops are aligned with the data flops
if self.col_addr_dff:
col_addr_pos = vector(self.bank.bank_center.x - self.col_addr_dff.width - self.bank.central_bus_width,
data_gap - self.col_addr_dff.height)
self.col_addr_dff_inst.place(col_addr_pos)
# Add the data flops below the bank to the right of the center of bank:
# This relies on the center point of the bank:
# decoder in upper left, bank in upper right, sensing in lower right.
# These flops go below the sensing and leave a gap to channel route to the
# sense amps.
data_pos = vector(self.bank.bank_center.x,
data_gap - self.data_dff.height)
self.data_dff_inst.place(data_pos)
# two supply rails are already included in the bank, so just 2 here.
# self.width = self.bank.width + self.control_logic.width + 2*self.supply_rail_pitch
# self.height = self.bank.height
# This is M2 pitch even though it is on M1 to help stem via spacings on the trunk
data_gap = -self.m2_pitch*(self.word_size+1)
# Add the column address below the bank under the control
# The column address flops are aligned with the data flops
if self.col_addr_dff:
col_addr_pos = vector(self.bank.bank_center.x - self.col_addr_dff.width - self.bank.central_bus_width,
data_gap - self.col_addr_dff.height)
self.col_addr_dff_inst[port].place(col_addr_pos)
# Add the data flops below the bank to the right of the center of bank:
# This relies on the center point of the bank:
# decoder in upper left, bank in upper right, sensing in lower right.
# These flops go below the sensing and leave a gap to channel route to the
# sense amps.
data_pos = vector(self.bank.bank_center.x,
data_gap - self.data_dff.height)
self.data_dff_inst[port].place(data_pos)
# two supply rails are already included in the bank, so just 2 here.
# self.width = self.bank.width + self.control_logic.width + 2*self.supply_rail_pitch
# self.height = self.bank.height
def add_layout_pins(self):
"""
Add the top-level pins for a single bank SRAM with control.
"""
# Connect the control pins as inputs
for n in self.control_logic_inputs + ["clk"]:
self.copy_layout_pin(self.control_logic_inst[0], n)
for port in range(self.total_ports):
# Connect the control pins as inputs
for signal in self.control_logic_inputs[port] + ["clk"]:
self.copy_layout_pin(self.control_logic_inst[port], signal, signal+"{}".format(port))
for i in range(self.word_size):
dout_name = "dout0[{}]".format(i)
self.copy_layout_pin(self.bank_inst, dout_name, "DOUT0[{}]".format(i))
for bit in range(self.word_size):
self.copy_layout_pin(self.bank_inst, "dout{0}[{1}]".format(port,bit), "DOUT{0}[{1}]".format(port,bit))
# Lower address bits
for i in range(self.col_addr_size):
self.copy_layout_pin(self.col_addr_dff_inst, "din[{}]".format(i),"ADDR0[{}]".format(i))
# Upper address bits
for i in range(self.row_addr_size):
self.copy_layout_pin(self.row_addr_dff_inst, "din[{}]".format(i),"ADDR0[{}]".format(i+self.col_addr_size))
# Lower address bits
for bit in range(self.col_addr_size):
self.copy_layout_pin(self.col_addr_dff_inst[port], "din[{}]".format(bit),"ADDR{0}[{1}]".format(port,bit))
# Upper address bits
for bit in range(self.row_addr_size):
self.copy_layout_pin(self.row_addr_dff_inst[port], "din[{}]".format(bit),"ADDR{0}[{1}]".format(port,bit+self.col_addr_size))
for i in range(self.word_size):
din_name = "din[{}]".format(i)
self.copy_layout_pin(self.data_dff_inst, din_name, "DIN0[{}]".format(i))
for bit in range(self.word_size):
self.copy_layout_pin(self.data_dff_inst[port], "din[{}]".format(bit), "DIN{0}[{1}]".format(port,bit))
def route(self):
""" Route a single bank SRAM """
@ -134,102 +132,106 @@ class sram_1bank(sram_base):
""" Route the clock network """
# This is the actual input to the SRAM
self.copy_layout_pin(self.control_logic_inst[0], "clk")
for port in range(self.total_ports):
self.copy_layout_pin(self.control_logic_inst[port], "clk", "clk{}".format(port))
# Connect all of these clock pins to the clock in the central bus
# This is something like a "spine" clock distribution. The two spines
# are clk_buf and clk_buf_bar
bank_clk_buf_pin = self.bank_inst.get_pin("clk_buf")
bank_clk_buf_pos = bank_clk_buf_pin.center()
bank_clk_buf_bar_pin = self.bank_inst.get_pin("clk_buf_bar")
bank_clk_buf_bar_pos = bank_clk_buf_bar_pin.center()
# Connect all of these clock pins to the clock in the central bus
# This is something like a "spine" clock distribution. The two spines
# are clk_buf and clk_buf_bar
bank_clk_buf_pin = self.bank_inst.get_pin("clk_buf{}".format(port))
bank_clk_buf_pos = bank_clk_buf_pin.center()
bank_clk_buf_bar_pin = self.bank_inst.get_pin("clk_buf_bar{}".format(port))
bank_clk_buf_bar_pos = bank_clk_buf_bar_pin.center()
if self.col_addr_dff:
dff_clk_pin = self.col_addr_dff_inst.get_pin("clk")
dff_clk_pos = dff_clk_pin.center()
mid_pos = vector(bank_clk_buf_pos.x, dff_clk_pos.y)
self.add_wire(("metal3","via2","metal2"),[dff_clk_pos, mid_pos, bank_clk_buf_pos])
data_dff_clk_pin = self.data_dff_inst.get_pin("clk")
data_dff_clk_pos = data_dff_clk_pin.center()
mid_pos = vector(bank_clk_buf_pos.x, data_dff_clk_pos.y)
self.add_wire(("metal3","via2","metal2"),[data_dff_clk_pos, mid_pos, bank_clk_buf_pos])
if self.col_addr_dff:
dff_clk_pin = self.col_addr_dff_inst[port].get_pin("clk")
dff_clk_pos = dff_clk_pin.center()
mid_pos = vector(bank_clk_buf_pos.x, dff_clk_pos.y)
self.add_wire(("metal3","via2","metal2"),[dff_clk_pos, mid_pos, bank_clk_buf_pos])
data_dff_clk_pin = self.data_dff_inst[port].get_pin("clk")
data_dff_clk_pos = data_dff_clk_pin.center()
mid_pos = vector(bank_clk_buf_pos.x, data_dff_clk_pos.y)
self.add_wire(("metal3","via2","metal2"),[data_dff_clk_pos, mid_pos, bank_clk_buf_pos])
# This uses a metal2 track to the right of the control/row addr DFF
# to route vertically.
control_clk_buf_pin = self.control_logic_inst[0].get_pin("clk_buf")
control_clk_buf_pos = control_clk_buf_pin.rc()
row_addr_clk_pin = self.row_addr_dff_inst.get_pin("clk")
row_addr_clk_pos = row_addr_clk_pin.rc()
mid1_pos = vector(self.row_addr_dff_inst.rx() + self.m2_pitch,
row_addr_clk_pos.y)
mid2_pos = vector(mid1_pos.x,
control_clk_buf_pos.y)
# Note, the via to the control logic is taken care of when we route
# the control logic to the bank
self.add_wire(("metal3","via2","metal2"),[row_addr_clk_pos, mid1_pos, mid2_pos, control_clk_buf_pos])
# This uses a metal2 track to the right of the control/row addr DFF
# to route vertically.
control_clk_buf_pin = self.control_logic_inst[port].get_pin("clk_buf")
control_clk_buf_pos = control_clk_buf_pin.rc()
row_addr_clk_pin = self.row_addr_dff_inst[port].get_pin("clk")
row_addr_clk_pos = row_addr_clk_pin.rc()
mid1_pos = vector(self.row_addr_dff_inst[port].rx() + self.m2_pitch,
row_addr_clk_pos.y)
mid2_pos = vector(mid1_pos.x,
control_clk_buf_pos.y)
# Note, the via to the control logic is taken care of when we route
# the control logic to the bank
self.add_wire(("metal3","via2","metal2"),[row_addr_clk_pos, mid1_pos, mid2_pos, control_clk_buf_pos])
def route_control_logic(self):
""" Route the outputs from the control logic module """
for n in self.control_logic_outputs:
src_pin = self.control_logic_inst[0].get_pin(n)
dest_pin = self.bank_inst.get_pin(n)
self.connect_rail_from_left_m2m3(src_pin, dest_pin)
self.add_via_center(layers=("metal1","via1","metal2"),
offset=src_pin.rc(),
rotate=90)
for port in range(self.total_ports):
for signal in self.control_logic_outputs[port]:
src_pin = self.control_logic_inst[port].get_pin(signal)
dest_pin = self.bank_inst.get_pin(signal+"{}".format(port))
self.connect_rail_from_left_m2m3(src_pin, dest_pin)
self.add_via_center(layers=("metal1","via1","metal2"),
offset=src_pin.rc(),
rotate=90)
def route_row_addr_dff(self):
""" Connect the output of the row flops to the bank pins """
for i in range(self.row_addr_size):
flop_name = "dout[{}]".format(i)
bank_name = "addr0[{}]".format(i+self.col_addr_size)
flop_pin = self.row_addr_dff_inst.get_pin(flop_name)
bank_pin = self.bank_inst.get_pin(bank_name)
flop_pos = flop_pin.center()
bank_pos = bank_pin.center()
mid_pos = vector(bank_pos.x,flop_pos.y)
self.add_wire(("metal3","via2","metal2"),[flop_pos, mid_pos,bank_pos])
self.add_via_center(layers=("metal2","via2","metal3"),
offset=flop_pos,
rotate=90)
for port in range(self.total_ports):
for bit in range(self.row_addr_size):
flop_name = "dout[{}]".format(bit)
bank_name = "addr{0}[{1}]".format(port,bit+self.col_addr_size)
flop_pin = self.row_addr_dff_inst[port].get_pin(flop_name)
bank_pin = self.bank_inst.get_pin(bank_name)
flop_pos = flop_pin.center()
bank_pos = bank_pin.center()
mid_pos = vector(bank_pos.x,flop_pos.y)
self.add_wire(("metal3","via2","metal2"),[flop_pos, mid_pos,bank_pos])
self.add_via_center(layers=("metal2","via2","metal3"),
offset=flop_pos,
rotate=90)
def route_col_addr_dff(self):
""" Connect the output of the row flops to the bank pins """
for port in range(self.total_ports):
bus_names = ["addr[{}]".format(x) for x in range(self.col_addr_size)]
col_addr_bus_offsets = self.create_horizontal_bus(layer="metal1",
pitch=self.m1_pitch,
offset=self.col_addr_dff_inst[port].ul() + vector(0, self.m1_pitch),
names=bus_names,
length=self.col_addr_dff_inst[port].width)
bus_names = ["addr[{}]".format(x) for x in range(self.col_addr_size)]
col_addr_bus_offsets = self.create_horizontal_bus(layer="metal1",
pitch=self.m1_pitch,
offset=self.col_addr_dff_inst.ul() + vector(0, self.m1_pitch),
names=bus_names,
length=self.col_addr_dff_inst.width)
dff_names = ["dout[{}]".format(x) for x in range(self.col_addr_size)]
data_dff_map = zip(dff_names, bus_names)
self.connect_horizontal_bus(data_dff_map, self.col_addr_dff_inst, col_addr_bus_offsets)
bank_names = ["addr0[{}]".format(x) for x in range(self.col_addr_size)]
data_bank_map = zip(bank_names, bus_names)
self.connect_horizontal_bus(data_bank_map, self.bank_inst, col_addr_bus_offsets)
dff_names = ["dout[{}]".format(x) for x in range(self.col_addr_size)]
data_dff_map = zip(dff_names, bus_names)
self.connect_horizontal_bus(data_dff_map, self.col_addr_dff_inst[port], col_addr_bus_offsets)
bank_names = ["addr{0}[{1}]".format(port,x) for x in range(self.col_addr_size)]
data_bank_map = zip(bank_names, bus_names)
self.connect_horizontal_bus(data_bank_map, self.bank_inst, col_addr_bus_offsets)
def route_data_dff(self):
""" Connect the output of the data flops to the write driver """
# This is where the channel will start (y-dimension at least)
offset = self.data_dff_inst.ul() + vector(0, self.m1_pitch)
for port in range(self.total_write):
offset = self.data_dff_inst[port].ul() + vector(0, self.m1_pitch)
dff_names = ["dout[{}]".format(x) for x in range(self.word_size)]
bank_names = ["din0[{}]".format(x) for x in range(self.word_size)]
dff_names = ["dout[{}]".format(x) for x in range(self.word_size)]
bank_names = ["din{0}[{1}]".format(port,x) for x in range(self.word_size)]
route_map = list(zip(bank_names, dff_names))
dff_pins = {key: self.data_dff_inst.get_pin(key) for key in dff_names }
bank_pins = {key: self.bank_inst.get_pin(key) for key in bank_names }
# Combine the dff and bank pins into a single dictionary of pin name to pin.
all_pins = {**dff_pins, **bank_pins}
self.create_horizontal_channel_route(route_map, all_pins, offset)
route_map = list(zip(bank_names, dff_names))
dff_pins = {key: self.data_dff_inst[port].get_pin(key) for key in dff_names }
bank_pins = {key: self.bank_inst.get_pin(key) for key in bank_names }
# Combine the dff and bank pins into a single dictionary of pin name to pin.
all_pins = {**dff_pins, **bank_pins}
self.create_horizontal_channel_route(route_map, all_pins, offset)
@ -240,7 +242,7 @@ class sram_1bank(sram_base):
will show these as ports in the extracted netlist.
"""
for n in self.control_logic_outputs:
for n in self.control_logic_outputs[0]:
pin = self.control_logic_inst[0].get_pin(n)
self.add_label(text=n,
layer=pin.layer,

View File

@ -19,26 +19,11 @@ class sram_base(design):
self.sram_config = sram_config
sram_config.set_local_config(self)
self.total_write = OPTS.num_rw_ports + OPTS.num_w_ports
self.total_read = OPTS.num_rw_ports + OPTS.num_r_ports
self.total_ports = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports
self.bank_insts = []
def add_pins(self):
""" Add pins for entire SRAM. """
self.read_index = []
port_number = 0
for port in range(OPTS.num_rw_ports):
self.read_index.append("{}".format(port_number))
port_number += 1
for port in range(OPTS.num_w_ports):
port_number += 1
for port in range(OPTS.num_r_ports):
self.read_index.append("{}".format(port_number))
port_number += 1
for port in range(self.total_write):
for bit in range(self.word_size):
self.add_pin("DIN{0}[{1}]".format(port,bit),"INPUT")
@ -47,15 +32,26 @@ class sram_base(design):
for bit in range(self.addr_size):
self.add_pin("ADDR{0}[{1}]".format(port,bit),"INPUT")
# These are used to create the physical pins too
self.control_logic_inputs=self.control_logic.get_inputs()
self.control_logic_outputs=self.control_logic.get_outputs()
# These are used to create the physical pins
self.control_logic_inputs = []
self.control_logic_outputs = []
for port in range(self.total_ports):
if self.port_id[port] == "rw":
self.control_logic_inputs.append(self.control_logic_rw.get_inputs())
self.control_logic_outputs.append(self.control_logic_rw.get_outputs())
elif self.port_id[port] == "w":
self.control_logic_inputs.append(self.control_logic_w.get_inputs())
self.control_logic_outputs.append(self.control_logic_w.get_outputs())
else:
self.control_logic_inputs.append(self.control_logic_r.get_inputs())
self.control_logic_outputs.append(self.control_logic_r.get_outputs())
#self.add_pin_list(self.control_logic_inputs,"INPUT")
self.add_pin("csb","INPUT")
for port in range(self.total_write):
for port in range(self.total_ports):
self.add_pin("csb{}".format(port),"INPUT")
for port in range(self.num_rw_ports):
self.add_pin("web{}".format(port),"INPUT")
self.add_pin("clk","INPUT")
for port in range(self.total_ports):
self.add_pin("clk{}".format(port),"INPUT")
for port in range(self.total_read):
for bit in range(self.word_size):
@ -75,6 +71,7 @@ class sram_base(design):
# This is for the lib file if we don't create layout
self.width=0
self.height=0
def create_layout(self):
""" Layout creation """
@ -151,65 +148,67 @@ class sram_base(design):
"Bank is too small compared to control logic.")
def add_busses(self):
""" Add the horizontal and vertical busses """
# Vertical bus
# The order of the control signals on the control bus:
self.control_bus_names = ["clk_buf", "clk_buf_bar", "w_en0", "s_en0"]
self.vert_control_bus_positions = self.create_vertical_bus(layer="metal2",
pitch=self.m2_pitch,
offset=self.vertical_bus_offset,
names=self.control_bus_names,
length=self.vertical_bus_height)
self.control_bus_names = []
for port in range(self.total_ports):
self.control_bus_names[port] = ["clk_buf{}".format(port), "clk_buf_bar{}".format(port)]
if (self.port_id[port] == "rw") or (self.port_id[port] == "w"):
self.control_bus_names[port].append("w_en{}".format(port))
if (self.port_id[port] == "rw") or (self.port_id[port] == "r"):
self.control_bus_names[port].append("s_en{}".format(port))
self.vert_control_bus_positions = self.create_vertical_bus(layer="metal2",
pitch=self.m2_pitch,
offset=self.vertical_bus_offset,
names=self.control_bus_names[port],
length=self.vertical_bus_height)
self.addr_bus_names=["A[{}]".format(i) for i in range(self.addr_size)]
self.vert_control_bus_positions.update(self.create_vertical_pin_bus(layer="metal2",
pitch=self.m2_pitch,
offset=self.addr_bus_offset,
names=self.addr_bus_names,
length=self.addr_bus_height))
self.addr_bus_names=["A{0}[{1}]".format(port,i) for i in range(self.addr_size)]
self.vert_control_bus_positions.update(self.create_vertical_pin_bus(layer="metal2",
pitch=self.m2_pitch,
offset=self.addr_bus_offset,
names=self.addr_bus_names,
length=self.addr_bus_height))
self.bank_sel_bus_names = ["bank_sel[{}]".format(i) for i in range(self.num_banks)]
self.vert_control_bus_positions.update(self.create_vertical_pin_bus(layer="metal2",
pitch=self.m2_pitch,
offset=self.bank_sel_bus_offset,
names=self.bank_sel_bus_names,
length=self.vertical_bus_height))
self.bank_sel_bus_names = ["bank_sel{0}[{1}]".format(port,i) for i in range(self.num_banks)]
self.vert_control_bus_positions.update(self.create_vertical_pin_bus(layer="metal2",
pitch=self.m2_pitch,
offset=self.bank_sel_bus_offset,
names=self.bank_sel_bus_names,
length=self.vertical_bus_height))
# Horizontal data bus
self.data_bus_names = ["DATA[{}]".format(i) for i in range(self.word_size)]
self.data_bus_positions = self.create_horizontal_pin_bus(layer="metal3",
pitch=self.m3_pitch,
offset=self.data_bus_offset,
names=self.data_bus_names,
length=self.data_bus_width)
# Horizontal control logic bus
# vdd/gnd in bus go along whole SRAM
# FIXME: Fatten these wires?
self.horz_control_bus_positions = self.create_horizontal_bus(layer="metal1",
pitch=self.m1_pitch,
offset=self.supply_bus_offset,
names=["vdd"],
length=self.supply_bus_width)
# The gnd rail must not be the entire width since we protrude the right-most vdd rail up for
# the decoder in 4-bank SRAMs
self.horz_control_bus_positions.update(self.create_horizontal_bus(layer="metal1",
pitch=self.m1_pitch,
offset=self.supply_bus_offset+vector(0,self.m1_pitch),
names=["gnd"],
length=self.supply_bus_width))
self.horz_control_bus_positions.update(self.create_horizontal_bus(layer="metal1",
pitch=self.m1_pitch,
offset=self.control_bus_offset,
names=self.control_bus_names,
length=self.control_bus_width))
# Horizontal data bus
self.data_bus_names = ["DATA{0}[{1}]".format(port,i) for i in range(self.word_size)]
self.data_bus_positions = self.create_horizontal_pin_bus(layer="metal3",
pitch=self.m3_pitch,
offset=self.data_bus_offset,
names=self.data_bus_names,
length=self.data_bus_width)
# Horizontal control logic bus
# vdd/gnd in bus go along whole SRAM
# FIXME: Fatten these wires?
self.horz_control_bus_positions = self.create_horizontal_bus(layer="metal1",
pitch=self.m1_pitch,
offset=self.supply_bus_offset,
names=["vdd"],
length=self.supply_bus_width)
# The gnd rail must not be the entire width since we protrude the right-most vdd rail up for
# the decoder in 4-bank SRAMs
self.horz_control_bus_positions.update(self.create_horizontal_bus(layer="metal1",
pitch=self.m1_pitch,
offset=self.supply_bus_offset+vector(0,self.m1_pitch),
names=["gnd"],
length=self.supply_bus_width))
self.horz_control_bus_positions.update(self.create_horizontal_bus(layer="metal1",
pitch=self.m1_pitch,
offset=self.control_bus_offset,
names=self.control_bus_names[port],
length=self.control_bus_width))
def route_vdd_gnd(self):
@ -250,33 +249,41 @@ class sram_base(design):
self.msb_decoder = self.bank.decoder.pre2_4
self.add_mod(self.msb_decoder)
def add_modules(self):
""" Create all the modules that will be used """
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell()
c = reload(__import__(OPTS.control_logic))
self.mod_control_logic = getattr(c, OPTS.control_logic)
#c = reload(__import__(OPTS.control_logic))
#self.mod_control_logic = getattr(c, OPTS.control_logic)
from control_logic import control_logic
# Create the control logic module
self.control_logic = self.mod_control_logic(num_rows=self.num_rows)
self.add_mod(self.control_logic)
# Create the control logic module for each port type
if OPTS.num_rw_ports>0:
self.control_logic = self.control_logic_rw = control_logic(num_rows=self.num_rows, port_type="rw")
self.add_mod(self.control_logic_rw)
if OPTS.num_w_ports>0:
self.control_logic_w = control_logic(num_rows=self.num_rows, port_type="w")
self.add_mod(self.control_logic_w)
if OPTS.num_r_ports>0:
self.control_logic_r = control_logic(num_rows=self.num_rows, port_type="r")
self.add_mod(self.control_logic_r)
# Create the address and control flops (but not the clk)
from dff_array import dff_array
self.row_addr_dff = dff_array(name="row_addr_dff", rows=self.row_addr_size*self.total_ports, columns=1)
self.row_addr_dff = dff_array(name="row_addr_dff", rows=self.row_addr_size, columns=1)
self.add_mod(self.row_addr_dff)
if self.col_addr_size > 0:
self.col_addr_dff = dff_array(name="col_addr_dff", rows=1, columns=self.col_addr_size*self.total_ports)
self.col_addr_dff = dff_array(name="col_addr_dff", rows=1, columns=self.col_addr_size)
self.add_mod(self.col_addr_dff)
else:
self.col_addr_dff = None
self.data_dff = dff_array(name="data_dff", rows=1, columns=self.word_size*self.total_write)
self.data_dff = dff_array(name="data_dff", rows=1, columns=self.word_size)
self.add_mod(self.data_dff)
# Create the bank module (up to four are instantiated)
@ -295,7 +302,6 @@ class sram_base(design):
self.supply_rail_pitch = self.bank.supply_rail_pitch
def create_bank(self,bank_num):
""" Create a bank """
self.bank_insts.append(self.add_inst(name="bank{0}".format(bank_num),
@ -318,7 +324,10 @@ class sram_base(design):
temp.append("s_en{0}".format(self.read_index[port]))
for port in range(self.total_write):
temp.append("w_en{0}".format(port))
temp.extend(["clk_buf_bar","clk_buf" , "vdd", "gnd"])
for port in range(self.total_ports):
temp.append("clk_buf_bar{0}".format(port))
temp.append("clk_buf{0}".format(port))
temp.extend(["vdd", "gnd"])
self.connect_inst(temp)
return self.bank_insts[-1]
@ -357,68 +366,87 @@ class sram_base(design):
def create_row_addr_dff(self):
""" Add all address flops for the main decoder """
inst = self.add_inst(name="row_address",
mod=self.row_addr_dff)
# inputs, outputs/output/bar
inputs = []
outputs = []
insts = []
for port in range(self.total_ports):
for i in range(self.row_addr_size):
inputs.append("ADDR{}[{}]".format(port,i+self.col_addr_size))
outputs.append("A{}[{}]".format(port,i+self.col_addr_size))
insts.append(self.add_inst(name="row_address{}".format(port),
mod=self.row_addr_dff))
# inputs, outputs/output/bar
inputs = []
outputs = []
for bit in range(self.row_addr_size):
inputs.append("ADDR{}[{}]".format(port,bit+self.col_addr_size))
outputs.append("A{}[{}]".format(port,bit+self.col_addr_size))
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port), "vdd", "gnd"])
return insts
self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"])
return inst
def create_col_addr_dff(self):
""" Add and place all address flops for the column decoder """
inst = self.add_inst(name="col_address",
mod=self.col_addr_dff)
# inputs, outputs/output/bar
inputs = []
outputs = []
insts = []
for port in range(self.total_ports):
for i in range(self.col_addr_size):
inputs.append("ADDR{}[{}]".format(port,i))
outputs.append("A{}[{}]".format(port,i))
insts.append(self.add_inst(name="col_address{}".format(port),
mod=self.col_addr_dff))
# inputs, outputs/output/bar
inputs = []
outputs = []
for bit in range(self.col_addr_size):
inputs.append("ADDR{}[{}]".format(port,bit))
outputs.append("A{}[{}]".format(port,bit))
self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"])
return inst
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port), "vdd", "gnd"])
return insts
def create_data_dff(self):
""" Add and place all data flops """
inst = self.add_inst(name="data_dff",
mod=self.data_dff)
# inputs, outputs/output/bar
inputs = []
outputs = []
insts = []
for port in range(self.total_write):
for i in range(self.word_size):
inputs.append("DIN{}[{}]".format(port,i))
outputs.append("BANK_DIN{}[{}]".format(port,i))
insts.append(self.add_inst(name="data_dff{}".format(port),
mod=self.data_dff))
# inputs, outputs/output/bar
inputs = []
outputs = []
for bit in range(self.word_size):
inputs.append("DIN{}[{}]".format(port,bit))
outputs.append("BANK_DIN{}[{}]".format(port,bit))
self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"])
return inst
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port), "vdd", "gnd"])
def create_control_logic(self, port):
return insts
def create_control_logic(self):
""" Add and place control logic """
inst = self.add_inst(name="control",
mod=self.control_logic)
self.connect_inst(["csb", "web{}".format(port), "clk",
"s_en{}".format(port), "w_en{}".format(port), "clk_buf_bar", "clk_buf",
"vdd", "gnd"])
insts = []
for port in range(self.total_ports):
if self.port_id[port] == "rw":
mod = self.control_logic_rw
elif self.port_id[port] == "w":
mod = self.control_logic_w
else:
mod = self.control_logic_r
insts.append(self.add_inst(name="control{}".format(port),
mod=mod))
temp = ["csb{}".format(port)]
if self.port_id[port] == "rw":
temp.append("web{}".format(port))
temp.append("clk{}".format(port))
if (self.port_id[port] == "rw") or (self.port_id[port] == "r"):
temp.append("s_en{}".format(port))
if (self.port_id[port] == "rw") or (self.port_id[port] == "w"):
temp.append("w_en{}".format(port))
temp.extend(["clk_buf_bar{}".format(port), "clk_buf{}".format(port), "vdd", "gnd"])
self.connect_inst(temp)
#self.connect_inst(self.control_logic_inputs + self.control_logic_outputs + ["vdd", "gnd"])
return inst
return insts
def connect_rail_from_left_m2m3(self, src_pin, dest_pin):
@ -429,14 +457,14 @@ class sram_base(design):
self.add_via_center(layers=("metal2","via2","metal3"),
offset=src_pin.rc(),
rotate=90)
def connect_rail_from_left_m2m1(self, src_pin, dest_pin):
""" Helper routine to connect an unrotated/mirrored oriented instance to the rails """
in_pos = src_pin.rc()
out_pos = vector(dest_pin.cx(), in_pos.y)
self.add_wire(("metal2","via1","metal1"),[in_pos, out_pos, out_pos - vector(0,self.m2_pitch)])
def sp_write(self, sp_name):
# Write the entire spice of the object to the file
@ -462,6 +490,7 @@ class sram_base(design):
del usedMODS
sp.close()
def analytical_delay(self,slew,load):
""" LH and HL are the same in analytical model. """
return self.bank.analytical_delay(slew,load)

View File

@ -18,24 +18,24 @@ class precharge_test(openram_test):
import precharge
import tech
# check precharge in single port
debug.info(2, "Checking precharge for handmade bitcell")
tx = precharge.precharge(name="precharge_driver", size=1)
self.local_check(tx)
if OPTS.multiport_check:
debug.info(2, "Checking precharge for pbitcell")
OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 1
tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(tx)
tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="bl1", bitcell_br="br1")
self.local_check(tx)
tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="bl2", bitcell_br="br2")
self.local_check(tx)
# check precharge in multi-port
OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 1
debug.info(2, "Checking precharge for pbitcell (innermost connections)")
tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(tx)
debug.info(2, "Checking precharge for pbitcell (outermost connections)")
tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="bl2", bitcell_br="br2")
self.local_check(tx)
globals.end_openram()

View File

@ -0,0 +1,45 @@
#!/usr/bin/env python3
"""
Run a regression test on a replica pbitcell
"""
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
class replica_pbitcell_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
import replica_pbitcell
import tech
OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 0
OPTS.num_w_ports = 0
debug.info(2, "Checking replica bitcell using pbitcell (small cell)")
tx = replica_pbitcell.replica_pbitcell()
self.local_check(tx)
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 1
debug.info(2, "Checking replica bitcell using pbitcell (large cell)")
tx = replica_pbitcell.replica_pbitcell()
self.local_check(tx)
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()

View File

@ -19,25 +19,25 @@ class single_level_column_mux_test(openram_test):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
import single_level_column_mux
import tech
# check single level column mux in single port
debug.info(2, "Checking column mux")
tx = single_level_column_mux.single_level_column_mux(tx_size=8)
self.local_check(tx)
if OPTS.multiport_check:
debug.info(2, "Checking column mux for pbitcell")
OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 1
tx = single_level_column_mux.single_level_column_mux(tx_size=8, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(tx)
tx = single_level_column_mux.single_level_column_mux(tx_size=8, bitcell_bl="bl1", bitcell_br="br1")
self.local_check(tx)
tx = single_level_column_mux.single_level_column_mux(tx_size=8, bitcell_bl="bl2", bitcell_br="br2")
self.local_check(tx)
# check single level column mux in multi-port
OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 1
debug.info(2, "Checking column mux for pbitcell (innermost connections)")
tx = single_level_column_mux.single_level_column_mux(tx_size=8, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(tx)
debug.info(2, "Checking column mux for pbitcell (outermost connections)")
tx = single_level_column_mux.single_level_column_mux(tx_size=8, bitcell_bl="bl2", bitcell_br="br2")
self.local_check(tx)
globals.end_openram()

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

@ -28,6 +28,7 @@ class hierarchical_decoder_test(openram_test):
# a = hierarchical_decoder.hierarchical_decoder(rows=8)
# self.local_check(a)
# check hierarchical decoder for single port
debug.info(1, "Testing 16 row sample for hierarchical_decoder")
a = hierarchical_decoder.hierarchical_decoder(rows=16)
self.local_check(a)
@ -43,6 +44,28 @@ class hierarchical_decoder_test(openram_test):
debug.info(1, "Testing 512 row sample for hierarchical_decoder")
a = hierarchical_decoder.hierarchical_decoder(rows=512)
self.local_check(a)
# check hierarchical decoder for multi-port
OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0
OPTS.num_r_ports = 0
debug.info(1, "Testing 16 row sample for hierarchical_decoder (multi-port case)")
a = hierarchical_decoder.hierarchical_decoder(rows=16)
self.local_check(a)
debug.info(1, "Testing 32 row sample for hierarchical_decoder (multi-port case)")
a = hierarchical_decoder.hierarchical_decoder(rows=32)
self.local_check(a)
debug.info(1, "Testing 128 row sample for hierarchical_decoder (multi-port case)")
a = hierarchical_decoder.hierarchical_decoder(rows=128)
self.local_check(a)
debug.info(1, "Testing 512 row sample for hierarchical_decoder (multi-port case)")
a = hierarchical_decoder.hierarchical_decoder(rows=512)
self.local_check(a)
globals.end_openram()

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

@ -18,10 +18,21 @@ class hierarchical_predecode2x4_test(openram_test):
import hierarchical_predecode2x4 as pre
import tech
# checking hierarchical precode 2x4 for single port
debug.info(1, "Testing sample for hierarchy_predecode2x4")
a = pre.hierarchical_predecode2x4()
self.local_check(a)
# checking hierarchical precode 2x4 for multi-port
OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0
OPTS.num_r_ports = 0
debug.info(1, "Testing sample for hierarchy_predecode2x4 (multi-port case)")
a = pre.hierarchical_predecode2x4()
self.local_check(a)
globals.end_openram()
# instantiate a copdsay of the class to actually run the test

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

@ -18,9 +18,20 @@ class hierarchical_predecode3x8_test(openram_test):
import hierarchical_predecode3x8 as pre
import tech
# checking hierarchical precode 3x8 for single port
debug.info(1, "Testing sample for hierarchy_predecode3x8")
a = pre.hierarchical_predecode3x8()
self.local_check(a)
# checking hierarchical precode 3x8 for multi-port
OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0
OPTS.num_r_ports = 0
debug.info(1, "Testing sample for hierarchy_predecode3x8 (multi-port case)")
a = pre.hierarchical_predecode3x8()
self.local_check(a)
globals.end_openram()

View File

@ -16,6 +16,7 @@ class single_level_column_mux_test(openram_test):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
import single_level_column_mux_array
# check single level column mux array in single port
debug.info(1, "Testing sample for 2-way column_mux_array")
a = single_level_column_mux_array.single_level_column_mux_array(columns=16, word_size=8)
self.local_check(a)
@ -28,32 +29,27 @@ class single_level_column_mux_test(openram_test):
a = single_level_column_mux_array.single_level_column_mux_array(columns=32, word_size=4)
self.local_check(a)
if OPTS.multiport_check:
debug.info(2, "Checking column mux array for pbitcell")
OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 1
debug.info(1, "Testing sample for 2-way column_mux_array")
a = single_level_column_mux_array.single_level_column_mux_array(columns=16, word_size=8, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(a)
# check single level column mux array in multi-port
OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 1
debug.info(1, "Testing sample for 2-way column_mux_array in multi-port")
a = single_level_column_mux_array.single_level_column_mux_array(columns=16, word_size=8, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(a)
debug.info(1, "Testing sample for 4-way column_mux_array")
a = single_level_column_mux_array.single_level_column_mux_array(columns=16, word_size=4, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(a)
debug.info(1, "Testing sample for 4-way column_mux_array in multi-port")
a = single_level_column_mux_array.single_level_column_mux_array(columns=16, word_size=4, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(a)
debug.info(1, "Testing sample for 8-way column_mux_array")
a = single_level_column_mux_array.single_level_column_mux_array(columns=32, word_size=4, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(a)
debug.info(1, "Testing sample for 8-way column_mux_array")
a = single_level_column_mux_array.single_level_column_mux_array(columns=32, word_size=4, bitcell_bl="bl1", bitcell_br="br1")
self.local_check(a)
debug.info(1, "Testing sample for 8-way column_mux_array")
a = single_level_column_mux_array.single_level_column_mux_array(columns=32, word_size=4, bitcell_bl="bl2", bitcell_br="br2")
self.local_check(a)
debug.info(1, "Testing sample for 8-way column_mux_array in multi-port (innermost connections)")
a = single_level_column_mux_array.single_level_column_mux_array(columns=32, word_size=4, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(a)
debug.info(1, "Testing sample for 8-way column_mux_array in multi-port (outermost connections)")
a = single_level_column_mux_array.single_level_column_mux_array(columns=32, word_size=4, bitcell_bl="bl2", bitcell_br="br2")
self.local_check(a)
globals.end_openram()

View File

@ -18,25 +18,24 @@ class precharge_test(openram_test):
import precharge_array
import tech
# check precharge array in single port
debug.info(2, "Checking 3 column precharge")
pc = precharge_array.precharge_array(columns=3)
self.local_check(pc)
if OPTS.multiport_check:
debug.info(2, "Checking precharge array for pbitcell")
OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 1
pc = precharge_array.precharge_array(columns=3, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(pc)
pc = precharge_array.precharge_array(columns=3, bitcell_bl="bl1", bitcell_br="br1")
self.local_check(pc)
pc = precharge_array.precharge_array(columns=3, bitcell_bl="bl2", bitcell_br="br2")
self.local_check(pc)
# check precharge array in multi-port
OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 1
debug.info(2, "Checking 3 column precharge array for pbitcell (innermost connections)")
pc = precharge_array.precharge_array(columns=3, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(pc)
debug.info(2, "Checking 3 column precharge array for pbitcell (outermost connections)")
pc = precharge_array.precharge_array(columns=3, bitcell_bl="bl2", bitcell_br="br2")
self.local_check(pc)
globals.end_openram()

View File

@ -20,19 +20,20 @@ class wordline_driver_test(openram_test):
import wordline_driver
import tech
# check wordline driver for single port
debug.info(2, "Checking driver")
tx = wordline_driver.wordline_driver(rows=8)
self.local_check(tx)
if OPTS.multiport_check:
OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0
OPTS.num_r_ports = 0
debug.info(2, "Checking driver (multi-port case)")
tx = wordline_driver.wordline_driver(rows=8)
self.local_check(tx)
# check wordline driver for multi-port
OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0
OPTS.num_r_ports = 0
debug.info(2, "Checking driver (multi-port case)")
tx = wordline_driver.wordline_driver(rows=8)
self.local_check(tx)
globals.end_openram()

View File

@ -17,6 +17,7 @@ class sense_amp_test(openram_test):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
import sense_amp_array
# check sense amp array for single port
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2")
a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=2)
self.local_check(a)
@ -25,19 +26,19 @@ class sense_amp_test(openram_test):
a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=4)
self.local_check(a)
if OPTS.multiport_check:
OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0
OPTS.num_r_ports = 0
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2 (multi-port case)")
a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=2)
self.local_check(a)
# check sense amp array for multi-port
OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0
OPTS.num_r_ports = 0
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2 (multi-port case)")
a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=2)
self.local_check(a)
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=4 (multi-port case)")
a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=4)
self.local_check(a)
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=4 (multi-port case)")
a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=4)
self.local_check(a)
globals.end_openram()

View File

@ -17,6 +17,7 @@ class write_driver_test(openram_test):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
import write_driver_array
# check write driver array for single port
debug.info(2, "Testing write_driver_array for columns=8, word_size=8")
a = write_driver_array.write_driver_array(columns=8, word_size=8)
self.local_check(a)
@ -25,19 +26,19 @@ class write_driver_test(openram_test):
a = write_driver_array.write_driver_array(columns=16, word_size=8)
self.local_check(a)
if OPTS.multiport_check:
OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0
OPTS.num_r_ports = 0
debug.info(2, "Testing write_driver_array for columns=8, word_size=8 (multi-port case)")
a = write_driver_array.write_driver_array(columns=8, word_size=8)
self.local_check(a)
# check write driver array for multi-port
OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0
OPTS.num_r_ports = 0
debug.info(2, "Testing write_driver_array for columns=8, word_size=8 (multi-port case)")
a = write_driver_array.write_driver_array(columns=8, word_size=8)
self.local_check(a)
debug.info(2, "Testing write_driver_array for columns=16, word_size=8 (multi-port case)")
a = write_driver_array.write_driver_array(columns=16, word_size=8)
self.local_check(a)
debug.info(2, "Testing write_driver_array for columns=16, word_size=8 (multi-port case)")
a = write_driver_array.write_driver_array(columns=16, word_size=8)
self.local_check(a)
globals.end_openram()

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

@ -17,6 +17,44 @@ class replica_bitline_test(openram_test):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
import replica_bitline
# check replica bitline in single port
stages=4
fanout=4
rows=13
debug.info(2, "Testing RBL with {0} FO4 stages, {1} rows".format(stages,rows))
a = replica_bitline.replica_bitline(stages,fanout,rows)
self.local_check(a)
stages=8
rows=100
debug.info(2, "Testing RBL with {0} FO4 stages, {1} rows".format(stages,rows))
a = replica_bitline.replica_bitline(stages,fanout,rows)
self.local_check(a)
# check replica bitline in multi-port
OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell = "replica_pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0
OPTS.num_r_ports = 0
stages=4
fanout=4
rows=13
debug.info(2, "Testing RBL with {0} FO4 stages, {1} rows".format(stages,rows))
a = replica_bitline.replica_bitline(stages,fanout,rows)
self.local_check(a)
stages=8
rows=100
debug.info(2, "Testing RBL with {0} FO4 stages, {1} rows".format(stages,rows))
a = replica_bitline.replica_bitline(stages,fanout,rows)
self.local_check(a)
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 1
OPTS.num_r_ports = 1
stages=4
fanout=4
rows=13

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

@ -18,9 +18,38 @@ class control_logic_test(openram_test):
import control_logic
import tech
# check control logic for single port
debug.info(1, "Testing sample for control_logic")
a = control_logic.control_logic(num_rows=128)
self.local_check(a)
# check control logic for multi-port
OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell = "replica_pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0
OPTS.num_r_ports = 0
debug.info(1, "Testing sample for control_logic for multiport")
a = control_logic.control_logic(num_rows=128)
self.local_check(a)
# Check port specific control logic
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 1
OPTS.num_r_ports = 1
debug.info(1, "Testing sample for control_logic for multiport, only write control logic")
a = control_logic.control_logic(num_rows=128, port_type="rw")
self.local_check(a)
debug.info(1, "Testing sample for control_logic for multiport, only write control logic")
a = control_logic.control_logic(num_rows=128, port_type="w")
self.local_check(a)
debug.info(1, "Testing sample for control_logic for multiport, only read control logic")
a = control_logic.control_logic(num_rows=128, port_type="r")
self.local_check(a)
globals.end_openram()

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

@ -17,8 +17,25 @@ class bank_select_test(openram_test):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
import bank_select
debug.info(1, "No column mux")
a = bank_select.bank_select()
debug.info(1, "No column mux, rw control logic")
a = bank_select.bank_select(port="rw")
self.local_check(a)
OPTS.bitcell = "pbitcell"
debug.info(1, "No column mux, rw control logic")
a = bank_select.bank_select(port="rw")
self.local_check(a)
OPTS.num_rw_ports = 0
OPTS.num_w_ports = 1
OPTS.num_r_ports = 1
debug.info(1, "No column mux, w control logic")
a = bank_select.bank_select(port="w")
self.local_check(a)
debug.info(1, "No column mux, r control logic")
a = bank_select.bank_select(port="r")
self.local_check(a)
globals.end_openram()

View File

@ -0,0 +1,61 @@
#!/usr/bin/env python3
"""
Run a regression test on various srams
"""
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
class multi_bank_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
from bank import bank
from sram_config import sram_config
OPTS.bitcell = "pbitcell"
# testing layout of bank using pbitcell with 1 RW port (a 6T-cell equivalent)
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0
OPTS.num_r_ports = 0
c = sram_config(word_size=4,
num_words=16)
c.num_banks=2
c.words_per_row=1
debug.info(1, "No column mux")
a = bank(c, name="bank1_multi")
self.local_check(a)
c.num_words=32
c.words_per_row=2
debug.info(1, "Two way column mux")
a = bank(c, name="bank2_multi")
self.local_check(a)
c.num_words=64
c.words_per_row=4
debug.info(1, "Four way column mux")
a = bank(c, name="bank3_multi")
self.local_check(a)
c.word_size=2
c.num_words=128
c.words_per_row=8
debug.info(1, "Eight way column mux")
a = bank(c, name="bank4_multi")
self.local_check(a)
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()

View File

@ -52,18 +52,14 @@ class psingle_bank_test(openram_test):
a = bank(c, name="bank1_1rw_0w_0r_single")
self.local_check(a)
# testing bank using pbitcell in various port combinations
# layout for multiple ports does not work yet
"""
# multiport can't generate layout yet on the bank level
OPTS.netlist_only = True
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 1
OPTS.num_r_ports = 1
debug.info(1, "No column mux")
name = "bank1_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports)
a = bank(c, name=name)
self.local_check(a)
c.num_words=16
c.words_per_row=1
OPTS.num_rw_ports = c.num_rw_ports = 2
OPTS.num_w_ports = c.num_w_ports = 2
@ -139,7 +135,7 @@ class psingle_bank_test(openram_test):
self.local_check(a)
"""
#globals.end_openram()
globals.end_openram()
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":

View File

@ -11,7 +11,7 @@ import globals
from globals import OPTS
import debug
@unittest.skip("SKIPPING 20_psram_1bank_test, multiport layout not complete")
#@unittest.skip("SKIPPING 20_psram_1bank_test, multiport layout not complete")
class sram_1bank_test(openram_test):
def runTest(self):
@ -19,8 +19,9 @@ class sram_1bank_test(openram_test):
from sram import sram
from sram_config import sram_config
OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell="replica_pbitcell"
# testing layout of bank using pbitcell with 1 RW port (a 6T-cell equivalent)
# testing layout of sram using pbitcell with 1 RW port (a 6T-cell equivalent)
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0
OPTS.num_r_ports = 0
@ -33,17 +34,79 @@ class sram_1bank_test(openram_test):
debug.info(1, "Single bank, no column mux with control logic")
a = sram(c, "sram1")
self.local_check(a, final_verification=True)
c.num_words=32
c.words_per_row=2
debug.info(1, "Single bank two way column mux with control logic")
a = sram(c, "sram2")
self.local_check(a, final_verification=True)
"""
c.num_words=64
c.words_per_row=4
debug.info(1, "Single bank, four way column mux with control logic")
a = sram(c, "sram3")
self.local_check(a, final_verification=True)
c.word_size=2
c.num_words=128
c.words_per_row=8
debug.info(1, "Single bank, eight way column mux with control logic")
a = sram(c, "sram4")
self.local_check(a, final_verification=True)
# testing sram using pbitcell in various port combinations
# layout for multiple ports does not work yet
"""
OPTS.rw_ports = 1
OPTS.w_ports = 1
OPTS.r_ports = 1
OPTS.netlist_only = True
c.num_words=16
c.words_per_row=1
OPTS.num_rw_ports = 2
OPTS.num_w_ports = 2
OPTS.num_r_ports = 2
debug.info(1, "Single bank, no column mux with control logic")
a = sram(c, "sram1")
self.local_check(a, final_verification=True)
"""
OPTS.num_rw_ports = 0
OPTS.num_w_ports = 2
OPTS.num_r_ports = 2
debug.info(1, "Single bank, no column mux with control logic")
a = sram(c, "sram1")
self.local_check(a, final_verification=True)
OPTS.num_rw_ports = 2
OPTS.num_w_ports = 0
OPTS.num_r_ports = 2
debug.info(1, "Single bank, no column mux with control logic")
a = sram(c, "sram1")
self.local_check(a, final_verification=True)
OPTS.num_rw_ports = 2
OPTS.num_w_ports = 2
OPTS.num_r_ports = 0
debug.info(1, "Single bank, no column mux with control logic")
a = sram(c, "sram1")
self.local_check(a, final_verification=True)
OPTS.num_rw_ports = 2
OPTS.num_w_ports = 0
OPTS.num_r_ports = 0
debug.info(1, "Single bank, no column mux with control logic")
a = sram(c, "sram1")
self.local_check(a, final_verification=True)
# testing with various column muxes
OPTS.num_rw_ports = c.num_rw_ports = 2
OPTS.num_w_ports = c.num_w_ports = 2
OPTS.num_r_ports = c.num_r_ports = 2
c.num_words=32
c.words_per_row=2
debug.info(1, "Single bank two way column mux with control logic")
@ -63,7 +126,7 @@ class sram_1bank_test(openram_test):
a = sram(c, "sram4")
self.local_check(a, final_verification=True)
"""
#globals.end_openram()
globals.end_openram()
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":

View File

@ -48,31 +48,33 @@ class timing_sram_test(openram_test):
import tech
loads = [tech.spice["msflop_in_cap"]*4]
slews = [tech.spice["rise_time"]*2]
data = d.analyze(probe_address, probe_data, slews, loads)
data, port_data = d.analyze(probe_address, probe_data, slews, loads)
#Combine info about port into all data
data.update(port_data[0])
#Assumes single rw port (6t sram)
if OPTS.tech_name == "freepdk45":
golden_data = {'delay_hl0': [2.5829000000000004],
'delay_lh0': [0.2255964],
golden_data = {'delay_hl': [2.5829000000000004],
'delay_lh': [0.2255964],
'leakage_power': 0.0019498999999999996,
'min_period': 4.844,
'read0_power0': [0.055371399999999994],
'read1_power0': [0.0520225],
'slew_hl0': [0.0794261],
'slew_lh0': [0.0236264],
'write0_power0': [0.06545659999999999],
'write1_power0': [0.057846299999999996]}
'read0_power': [0.055371399999999994],
'read1_power': [0.0520225],
'slew_hl': [0.0794261],
'slew_lh': [0.0236264],
'write0_power': [0.06545659999999999],
'write1_power': [0.057846299999999996]}
elif OPTS.tech_name == "scn4m_subm":
golden_data = {'delay_hl0': [3.452],
'delay_lh0': [1.3792000000000002],
golden_data = {'delay_hl': [3.452],
'delay_lh': [1.3792000000000002],
'leakage_power': 0.0257065,
'min_period': 4.688,
'read0_power0': [15.0755],
'read1_power0': [14.4526],
'slew_hl0': [0.6137363],
'slew_lh0': [0.3381045],
'write0_power0': [16.9203],
'write1_power0': [15.367]}
'read0_power': [15.0755],
'read1_power': [14.4526],
'slew_hl': [0.6137363],
'slew_lh': [0.3381045],
'write0_power': [16.9203],
'write1_power': [15.367]}
else:
self.assertTrue(False) # other techs fail
# Check if no too many or too few results

View File

@ -48,30 +48,32 @@ class timing_sram_test(openram_test):
import tech
loads = [tech.spice["msflop_in_cap"]*4]
slews = [tech.spice["rise_time"]*2]
data = d.analyze(probe_address, probe_data, slews, loads)
data, port_data = d.analyze(probe_address, probe_data, slews, loads)
#Combine info about port into all data
data.update(port_data[0])
if OPTS.tech_name == "freepdk45":
golden_data = {'delay_hl0': [2.584251],
'delay_lh0': [0.22870469999999998],
golden_data = {'delay_hl': [2.584251],
'delay_lh': [0.22870469999999998],
'leakage_power': 0.0009567935,
'min_period': 4.844,
'read0_power0': [0.0547588],
'read1_power0': [0.051159970000000006],
'slew_hl0': [0.08164099999999999],
'slew_lh0': [0.025474979999999998],
'write0_power0': [0.06513271999999999],
'write1_power0': [0.058057000000000004]}
'read0_power': [0.0547588],
'read1_power': [0.051159970000000006],
'slew_hl': [0.08164099999999999],
'slew_lh': [0.025474979999999998],
'write0_power': [0.06513271999999999],
'write1_power': [0.058057000000000004]}
elif OPTS.tech_name == "scn4m_subm":
golden_data = {'delay_hl0': [3.644147],
'delay_lh0': [1.629815],
golden_data = {'delay_hl': [3.644147],
'delay_lh': [1.629815],
'leakage_power': 0.0009299118999999999,
'min_period': 4.688,
'read0_power0': [16.28732],
'read1_power0': [15.75155],
'slew_hl0': [0.6722473],
'slew_lh0': [0.3386347],
'write0_power0': [18.545450000000002],
'write1_power0': [16.81084]}
'read0_power': [16.28732],
'read1_power': [15.75155],
'slew_hl': [0.6722473],
'slew_lh': [0.3386347],
'write0_power': [18.545450000000002],
'write1_power': [16.81084]}
else:
self.assertTrue(False) # other techs fail

View File

@ -0,0 +1,64 @@
#!/usr/bin/env python3
"""
Run a regression test on various srams
"""
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 22_psram_func_test")
class psram_func_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
OPTS.spice_name="hspice"
OPTS.analytical_delay = False
OPTS.netlist_only = True
OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell="replica_pbitcell"
# This is a hack to reload the characterizer __init__ with the spice version
from importlib import reload
import characterizer
reload(characterizer)
from characterizer import functional
if not OPTS.spice_exe:
debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1)
from sram import sram
from sram_config import sram_config
c = sram_config(word_size=4,
num_words=32,
num_banks=1)
c.words_per_row=2
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 1
OPTS.num_r_ports = 1
debug.info(1, "Functional test for 1bit, 16word SRAM, with 1 bank. Multiport with {}RW {}W {}R.".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports))
s = sram(c, name="sram1")
tempspice = OPTS.openram_temp + "temp.sp"
s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, tempspice, corner)
f.num_cycles = 5
(fail,error) = f.run()
self.assertTrue(fail,error)
globals.end_openram()
# instantiate a copdsay 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()

View File

@ -11,49 +11,41 @@ import globals
from globals import OPTS
import debug
@unittest.skip("SKIPPING 22_sram_func_test")
#@unittest.skip("SKIPPING 22_sram_func_test")
class sram_func_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
OPTS.spice_name="hspice"
OPTS.analytical_delay = False
# This is a hack to reload the characterizer __init__ with the spice version
from importlib import reload
import characterizer
reload(characterizer)
from characterizer import delay
from characterizer import functional
if not OPTS.spice_exe:
debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1)
import sram
debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
s = sram.sram(word_size=1,
num_words=16,
num_banks=1,
name="sram_func_test")
from sram import sram
from sram_config import sram_config
c = sram_config(word_size=4,
num_words=32,
num_banks=1)
c.words_per_row=2
debug.info(1, "Functional test for 1bit, 16word SRAM, with 1 bank")
s = sram(c, name="sram1")
tempspice = OPTS.openram_temp + "temp.sp"
s.sp_write(tempspice)
probe_address = "1" * s.addr_size
probe_data = s.word_size - 1
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(s,tempspice,corner)
d.set_probe(probe_address,probe_data)
f = functional(s.s, tempspice, corner)
f.num_cycles = 10
(fail, error) = f.run()
# This will exit if it doesn't find a feasible period
import tech
d.load = tech.spice["msflop_in_cap"]*4
d.slew = tech.spice["rise_time"]*2
feasible_period = d.find_feasible_period()
self.assertTrue(fail,error)
os.remove(tempspice)
reload(characterizer)
globals.end_openram()
# instantiate a copdsay of the class to actually run the test

View File

@ -0,0 +1,64 @@
#!/usr/bin/env python3
"""
Run a regression test on various srams
"""
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 22_psram_func_test")
class psram_func_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
OPTS.spice_name="ngspice"
OPTS.analytical_delay = False
OPTS.netlist_only = True
OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell="replica_pbitcell"
# This is a hack to reload the characterizer __init__ with the spice version
from importlib import reload
import characterizer
reload(characterizer)
from characterizer import functional
if not OPTS.spice_exe:
debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1)
from sram import sram
from sram_config import sram_config
c = sram_config(word_size=4,
num_words=32,
num_banks=1)
c.words_per_row=2
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 1
OPTS.num_r_ports = 1
debug.info(1, "Functional test for 1bit, 16word SRAM, with 1 bank. Multiport with {}RW {}W {}R.".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports))
s = sram(c, name="sram1")
tempspice = OPTS.openram_temp + "temp.sp"
s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, tempspice, corner)
f.num_cycles = 5
(fail,error) = f.run()
self.assertTrue(fail,error)
globals.end_openram()
# instantiate a copdsay 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()

View File

@ -0,0 +1,56 @@
#!/usr/bin/env python3
"""
Run a regression test on various srams
"""
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 22_sram_func_test")
class sram_func_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
OPTS.spice_name="ngspice"
OPTS.analytical_delay = False
# This is a hack to reload the characterizer __init__ with the spice version
from importlib import reload
import characterizer
reload(characterizer)
from characterizer import functional
if not OPTS.spice_exe:
debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1)
from sram import sram
from sram_config import sram_config
c = sram_config(word_size=4,
num_words=32,
num_banks=1)
c.words_per_row=2
debug.info(1, "Functional test for 1bit, 16word SRAM, with 1 bank")
s = sram(c, name="sram1")
tempspice = OPTS.openram_temp + "temp.sp"
s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, tempspice, corner)
f.num_cycles = 10
(fail, error) = f.run()
self.assertTrue(fail,error)
globals.end_openram()
# instantiate a copdsay 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()

View File

@ -1,6 +1,5 @@
word_size = 1
num_words = 16
num_banks = 1
tech_name = "freepdk45"
process_corners = ["TT"]

View File

@ -1,6 +1,5 @@
word_size = 1
num_words = 16
num_banks = 1
tech_name = "scn3me_subm"
process_corners = ["TT"]

View File

@ -1,6 +1,5 @@
word_size = 1
num_words = 16
num_banks = 1
tech_name = "scn4m_subm"
process_corners = ["TT"]

View File

@ -29,17 +29,19 @@ class openram_test(unittest.TestCase):
tempgds = OPTS.openram_temp + "temp.gds"
a.sp_write(tempspice)
a.gds_write(tempgds)
# cannot write gds in netlist_only mode
if not OPTS.netlist_only:
a.gds_write(tempgds)
import verify
result=verify.run_drc(a.name, tempgds)
if result != 0:
self.fail("DRC failed: {}".format(a.name))
import verify
result=verify.run_drc(a.name, tempgds)
if result != 0:
self.fail("DRC failed: {}".format(a.name))
result=verify.run_lvs(a.name, tempgds, tempspice, final_verification)
if result != 0:
self.fail("LVS mismatch: {}".format(a.name))
result=verify.run_lvs(a.name, tempgds, tempspice, final_verification)
if result != 0:
self.fail("LVS mismatch: {}".format(a.name))
if OPTS.purge_temp:
self.cleanup()

View File

@ -1,8 +0,0 @@
word_size = 128
num_words = 1024
num_banks = 2
tech_name = "freepdk45"
process_corners = ["TT"]
supply_voltages = [1.0]
temperatures = [25]

View File

@ -1,8 +0,0 @@
word_size = 128
num_words = 1024
num_banks = 4
tech_name = "freepdk45"
process_corners = ["TT"]
supply_voltages = [1.0]
temperatures = [25]

View File

@ -1,8 +0,0 @@
word_size = 64
num_words = 1024
num_banks = 2
tech_name = "freepdk45"
process_corners = ["TT"]
supply_voltages = [1.0]
temperatures = [25]

View File

@ -1,6 +1,5 @@
word_size = 32
num_words = 1024
num_banks = 1
tech_name = "freepdk45"
process_corners = ["TT"]

View File

@ -1,6 +1,5 @@
word_size = 32
num_words = 2048
num_banks = 1
tech_name = "freepdk45"
process_corners = ["TT"]

View File

@ -1,6 +1,5 @@
word_size = 32
num_words = 256
num_banks = 1
tech_name = "freepdk45"
process_corners = ["TT"]

View File

@ -1,6 +1,5 @@
word_size = 32
num_words = 512
num_banks = 1
tech_name = "freepdk45"
process_corners = ["TT"]

View File

@ -1,6 +1,5 @@
word_size = 64
num_words = 1024
num_banks = 1
tech_name = "freepdk45"
process_corners = ["TT"]

View File

@ -1,6 +1,5 @@
word_size = 8
num_words = 1024
num_banks = 4
tech_name = "freepdk45"
process_corners = ["TT"]

View File

@ -1,6 +1,5 @@
word_size = 8
num_words = 256
num_banks = 1
tech_name = "freepdk45"
process_corners = ["TT"]

View File

@ -1,6 +1,5 @@
word_size = 8
num_words = 512
num_banks = 4
tech_name = "freepdk45"
process_corners = ["TT"]

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,347 +0,0 @@
library (sram_1rw_128b_1024w_1bank_freepdk45_TT_1p0V_25C_lib){
delay_model : "table_lookup";
time_unit : "1ns" ;
voltage_unit : "1v" ;
current_unit : "1mA" ;
resistance_unit : "1kohm" ;
capacitive_load_unit(1 ,fF) ;
leakage_power_unit : "1mW" ;
pulling_resistance_unit :"1kohm" ;
operating_conditions(OC){
process : 1.0 ;
voltage : 1.0 ;
temperature : 25;
}
input_threshold_pct_fall : 50.0 ;
output_threshold_pct_fall : 50.0 ;
input_threshold_pct_rise : 50.0 ;
output_threshold_pct_rise : 50.0 ;
slew_lower_threshold_pct_fall : 10.0 ;
slew_upper_threshold_pct_fall : 90.0 ;
slew_lower_threshold_pct_rise : 10.0 ;
slew_upper_threshold_pct_rise : 90.0 ;
nom_voltage : 1.0;
nom_temperature : 25;
nom_process : 1.0;
default_cell_leakage_power : 0.0 ;
default_leakage_power_density : 0.0 ;
default_input_pin_cap : 1.0 ;
default_inout_pin_cap : 1.0 ;
default_output_pin_cap : 0.0 ;
default_max_transition : 0.5 ;
default_fanout_load : 1.0 ;
default_max_fanout : 4.0 ;
default_connection_class : universal ;
lu_table_template(CELL_TABLE){
variable_1 : input_net_transition;
variable_2 : total_output_net_capacitance;
index_1("0.00125, 0.005, 0.04");
index_2("0.052275, 0.2091, 1.6728");
}
lu_table_template(CONSTRAINT_TABLE){
variable_1 : related_pin_transition;
variable_2 : constrained_pin_transition;
index_1("0.00125, 0.005, 0.04");
index_2("0.00125, 0.005, 0.04");
}
default_operating_conditions : OC;
type (DATA){
base_type : array;
data_type : bit;
bit_width : 128;
bit_from : 0;
bit_to : 127;
}
type (ADDR){
base_type : array;
data_type : bit;
bit_width : 10;
bit_from : 0;
bit_to : 9;
}
cell (sram_1rw_128b_1024w_1bank_freepdk45){
memory(){
type : ram;
address_width : 10;
word_width : 128;
}
interface_timing : true;
dont_use : true;
map_only : true;
dont_touch : true;
area : 146602.501987;
leakage_power () {
when : "CSb";
value : 0.56084648;
}
cell_leakage_power : 0;
bus(DATA){
bus_type : DATA;
direction : inout;
max_capacitance : 1.6728;
min_capacitance : 0.052275;
three_state : "!OEb & !clk";
memory_write(){
address : ADDR;
clocked_on : clk;
}
memory_read(){
address : ADDR;
}
pin(DATA[127:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
timing(){
timing_sense : non_unate;
related_pin : "clk";
timing_type : falling_edge;
cell_rise(CELL_TABLE) {
values("3.107, 3.109, 3.117",\
"3.109, 3.11, 3.118",\
"3.114, 3.115, 3.123");
}
cell_fall(CELL_TABLE) {
values("0.27, 0.274, 0.297",\
"0.271, 0.274, 0.298",\
"0.277, 0.28, 0.303");
}
rise_transition(CELL_TABLE) {
values("0.023, 0.024, 0.034",\
"0.023, 0.024, 0.034",\
"0.023, 0.024, 0.034");
}
fall_transition(CELL_TABLE) {
values("0.055, 0.057, 0.077",\
"0.055, 0.057, 0.077",\
"0.055, 0.058, 0.077");
}
}
}
}
bus(ADDR){
bus_type : ADDR;
direction : input;
capacitance : 0.2091;
max_transition : 0.04;
pin(ADDR[9:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
}
pin(CSb){
direction : input;
capacitance : 0.2091;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
pin(OEb){
direction : input;
capacitance : 0.2091;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
pin(WEb){
direction : input;
capacitance : 0.2091;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
pin(clk){
clock : true;
direction : input;
capacitance : 0.2091;
internal_power(){
when : "!CSb & clk & !WEb";
rise_power(scalar){
values("0.359934198778");
}
fall_power(scalar){
values("0.359934198778");
}
}
internal_power(){
when : "!CSb & !clk & WEb";
rise_power(scalar){
values("0.377816169333");
}
fall_power(scalar){
values("0.377816169333");
}
}
internal_power(){
when : "CSb";
rise_power(scalar){
values("0");
}
fall_power(scalar){
values("0");
}
}
timing(){
timing_type :"min_pulse_width";
related_pin : clk;
rise_constraint(scalar) {
values("2.969");
}
fall_constraint(scalar) {
values("2.969");
}
}
timing(){
timing_type :"minimum_period";
related_pin : clk;
rise_constraint(scalar) {
values("5.938");
}
fall_constraint(scalar) {
values("5.938");
}
}
}
}
}

View File

@ -1,347 +0,0 @@
library (sram_1rw_128b_1024w_4bank_freepdk45_TT_1p0V_25C_lib){
delay_model : "table_lookup";
time_unit : "1ns" ;
voltage_unit : "1v" ;
current_unit : "1mA" ;
resistance_unit : "1kohm" ;
capacitive_load_unit(1 ,fF) ;
leakage_power_unit : "1mW" ;
pulling_resistance_unit :"1kohm" ;
operating_conditions(OC){
process : 1.0 ;
voltage : 1.0 ;
temperature : 25;
}
input_threshold_pct_fall : 50.0 ;
output_threshold_pct_fall : 50.0 ;
input_threshold_pct_rise : 50.0 ;
output_threshold_pct_rise : 50.0 ;
slew_lower_threshold_pct_fall : 10.0 ;
slew_upper_threshold_pct_fall : 90.0 ;
slew_lower_threshold_pct_rise : 10.0 ;
slew_upper_threshold_pct_rise : 90.0 ;
nom_voltage : 1.0;
nom_temperature : 25;
nom_process : 1.0;
default_cell_leakage_power : 0.0 ;
default_leakage_power_density : 0.0 ;
default_input_pin_cap : 1.0 ;
default_inout_pin_cap : 1.0 ;
default_output_pin_cap : 0.0 ;
default_max_transition : 0.5 ;
default_fanout_load : 1.0 ;
default_max_fanout : 4.0 ;
default_connection_class : universal ;
lu_table_template(CELL_TABLE){
variable_1 : input_net_transition;
variable_2 : total_output_net_capacitance;
index_1("0.00125, 0.005, 0.04");
index_2("0.052275, 0.2091, 1.6728");
}
lu_table_template(CONSTRAINT_TABLE){
variable_1 : related_pin_transition;
variable_2 : constrained_pin_transition;
index_1("0.00125, 0.005, 0.04");
index_2("0.00125, 0.005, 0.04");
}
default_operating_conditions : OC;
type (DATA){
base_type : array;
data_type : bit;
bit_width : 128;
bit_from : 0;
bit_to : 127;
}
type (ADDR){
base_type : array;
data_type : bit;
bit_width : 10;
bit_from : 0;
bit_to : 9;
}
cell (sram_1rw_128b_1024w_4bank_freepdk45){
memory(){
type : ram;
address_width : 10;
word_width : 128;
}
interface_timing : true;
dont_use : true;
map_only : true;
dont_touch : true;
area : 178744.321438;
leakage_power () {
when : "CSb";
value : 1.2037325;
}
cell_leakage_power : 0;
bus(DATA){
bus_type : DATA;
direction : inout;
max_capacitance : 1.6728;
min_capacitance : 0.052275;
three_state : "!OEb & !clk";
memory_write(){
address : ADDR;
clocked_on : clk;
}
memory_read(){
address : ADDR;
}
pin(DATA[127:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
timing(){
timing_sense : non_unate;
related_pin : "clk";
timing_type : falling_edge;
cell_rise(CELL_TABLE) {
values("0.177, 0.178, 0.186",\
"0.177, 0.178, 0.186",\
"0.183, 0.184, 0.192");
}
cell_fall(CELL_TABLE) {
values("0.158, 0.159, 0.168",\
"0.159, 0.16, 0.168",\
"0.164, 0.165, 0.174");
}
rise_transition(CELL_TABLE) {
values("0.08, 0.081, 0.091",\
"0.08, 0.081, 0.091",\
"0.081, 0.082, 0.091");
}
fall_transition(CELL_TABLE) {
values("0.077, 0.079, 0.093",\
"0.077, 0.079, 0.093",\
"0.078, 0.079, 0.093");
}
}
}
}
bus(ADDR){
bus_type : ADDR;
direction : input;
capacitance : 0.2091;
max_transition : 0.04;
pin(ADDR[9:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
}
pin(CSb){
direction : input;
capacitance : 0.2091;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
pin(OEb){
direction : input;
capacitance : 0.2091;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
pin(WEb){
direction : input;
capacitance : 0.2091;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
pin(clk){
clock : true;
direction : input;
capacitance : 0.2091;
internal_power(){
when : "!CSb & clk & !WEb";
rise_power(scalar){
values("0.719680893333");
}
fall_power(scalar){
values("0.719680893333");
}
}
internal_power(){
when : "!CSb & !clk & WEb";
rise_power(scalar){
values("0.767111023611");
}
fall_power(scalar){
values("0.767111023611");
}
}
internal_power(){
when : "CSb";
rise_power(scalar){
values("0");
}
fall_power(scalar){
values("0");
}
}
timing(){
timing_type :"min_pulse_width";
related_pin : clk;
rise_constraint(scalar) {
values("1.0155");
}
fall_constraint(scalar) {
values("1.0155");
}
}
timing(){
timing_type :"minimum_period";
related_pin : clk;
rise_constraint(scalar) {
values("2.031");
}
fall_constraint(scalar) {
values("2.031");
}
}
}
}
}

View File

@ -1,347 +0,0 @@
library (sram_1rw_32b_1024w_1bank_freepdk45_TT_1p0V_25C_lib){
delay_model : "table_lookup";
time_unit : "1ns" ;
voltage_unit : "1v" ;
current_unit : "1mA" ;
resistance_unit : "1kohm" ;
capacitive_load_unit(1 ,fF) ;
leakage_power_unit : "1mW" ;
pulling_resistance_unit :"1kohm" ;
operating_conditions(OC){
process : 1.0 ;
voltage : 1.0 ;
temperature : 25;
}
input_threshold_pct_fall : 50.0 ;
output_threshold_pct_fall : 50.0 ;
input_threshold_pct_rise : 50.0 ;
output_threshold_pct_rise : 50.0 ;
slew_lower_threshold_pct_fall : 10.0 ;
slew_upper_threshold_pct_fall : 90.0 ;
slew_lower_threshold_pct_rise : 10.0 ;
slew_upper_threshold_pct_rise : 90.0 ;
nom_voltage : 1.0;
nom_temperature : 25;
nom_process : 1.0;
default_cell_leakage_power : 0.0 ;
default_leakage_power_density : 0.0 ;
default_input_pin_cap : 1.0 ;
default_inout_pin_cap : 1.0 ;
default_output_pin_cap : 0.0 ;
default_max_transition : 0.5 ;
default_fanout_load : 1.0 ;
default_max_fanout : 4.0 ;
default_connection_class : universal ;
lu_table_template(CELL_TABLE){
variable_1 : input_net_transition;
variable_2 : total_output_net_capacitance;
index_1("0.00125, 0.005, 0.04");
index_2("0.052275, 0.2091, 1.6728");
}
lu_table_template(CONSTRAINT_TABLE){
variable_1 : related_pin_transition;
variable_2 : constrained_pin_transition;
index_1("0.00125, 0.005, 0.04");
index_2("0.00125, 0.005, 0.04");
}
default_operating_conditions : OC;
type (DATA){
base_type : array;
data_type : bit;
bit_width : 32;
bit_from : 0;
bit_to : 31;
}
type (ADDR){
base_type : array;
data_type : bit;
bit_width : 10;
bit_from : 0;
bit_to : 9;
}
cell (sram_1rw_32b_1024w_1bank_freepdk45){
memory(){
type : ram;
address_width : 10;
word_width : 32;
}
interface_timing : true;
dont_use : true;
map_only : true;
dont_touch : true;
area : 42051.1147875;
leakage_power () {
when : "CSb";
value : 0.15279765;
}
cell_leakage_power : 0;
bus(DATA){
bus_type : DATA;
direction : inout;
max_capacitance : 1.6728;
min_capacitance : 0.052275;
three_state : "!OEb & !clk";
memory_write(){
address : ADDR;
clocked_on : clk;
}
memory_read(){
address : ADDR;
}
pin(DATA[31:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
timing(){
timing_sense : non_unate;
related_pin : "clk";
timing_type : falling_edge;
cell_rise(CELL_TABLE) {
values("1.158, 1.159, 1.167",\
"1.158, 1.161, 1.167",\
"1.164, 1.165, 1.171");
}
cell_fall(CELL_TABLE) {
values("0.171, 0.173, 0.186",\
"0.172, 0.173, 0.186",\
"0.177, 0.179, 0.192");
}
rise_transition(CELL_TABLE) {
values("0.02, 0.021, 0.032",\
"0.02, 0.021, 0.032",\
"0.02, 0.021, 0.031");
}
fall_transition(CELL_TABLE) {
values("0.065, 0.063, 0.058",\
"0.065, 0.063, 0.058",\
"0.066, 0.064, 0.058");
}
}
}
}
bus(ADDR){
bus_type : ADDR;
direction : input;
capacitance : 0.2091;
max_transition : 0.04;
pin(ADDR[9:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
}
pin(CSb){
direction : input;
capacitance : 0.2091;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
pin(OEb){
direction : input;
capacitance : 0.2091;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
pin(WEb){
direction : input;
capacitance : 0.2091;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
pin(clk){
clock : true;
direction : input;
capacitance : 0.2091;
internal_power(){
when : "!CSb & clk & !WEb";
rise_power(scalar){
values("0.177355641117");
}
fall_power(scalar){
values("0.177355641117");
}
}
internal_power(){
when : "!CSb & !clk & WEb";
rise_power(scalar){
values("0.193822578894");
}
fall_power(scalar){
values("0.193822578894");
}
}
internal_power(){
when : "CSb";
rise_power(scalar){
values("0");
}
fall_power(scalar){
values("0");
}
}
timing(){
timing_type :"min_pulse_width";
related_pin : clk;
rise_constraint(scalar) {
values("1.094");
}
fall_constraint(scalar) {
values("1.094");
}
}
timing(){
timing_type :"minimum_period";
related_pin : clk;
rise_constraint(scalar) {
values("2.188");
}
fall_constraint(scalar) {
values("2.188");
}
}
}
}
}

View File

@ -1,347 +0,0 @@
library (sram_1rw_32b_2048w_1bank_freepdk45_TT_1p0V_25C_lib){
delay_model : "table_lookup";
time_unit : "1ns" ;
voltage_unit : "1v" ;
current_unit : "1mA" ;
resistance_unit : "1kohm" ;
capacitive_load_unit(1 ,fF) ;
leakage_power_unit : "1mW" ;
pulling_resistance_unit :"1kohm" ;
operating_conditions(OC){
process : 1.0 ;
voltage : 1.0 ;
temperature : 25;
}
input_threshold_pct_fall : 50.0 ;
output_threshold_pct_fall : 50.0 ;
input_threshold_pct_rise : 50.0 ;
output_threshold_pct_rise : 50.0 ;
slew_lower_threshold_pct_fall : 10.0 ;
slew_upper_threshold_pct_fall : 90.0 ;
slew_lower_threshold_pct_rise : 10.0 ;
slew_upper_threshold_pct_rise : 90.0 ;
nom_voltage : 1.0;
nom_temperature : 25;
nom_process : 1.0;
default_cell_leakage_power : 0.0 ;
default_leakage_power_density : 0.0 ;
default_input_pin_cap : 1.0 ;
default_inout_pin_cap : 1.0 ;
default_output_pin_cap : 0.0 ;
default_max_transition : 0.5 ;
default_fanout_load : 1.0 ;
default_max_fanout : 4.0 ;
default_connection_class : universal ;
lu_table_template(CELL_TABLE){
variable_1 : input_net_transition;
variable_2 : total_output_net_capacitance;
index_1("0.00125, 0.005, 0.04");
index_2("0.052275, 0.2091, 1.6728");
}
lu_table_template(CONSTRAINT_TABLE){
variable_1 : related_pin_transition;
variable_2 : constrained_pin_transition;
index_1("0.00125, 0.005, 0.04");
index_2("0.00125, 0.005, 0.04");
}
default_operating_conditions : OC;
type (DATA){
base_type : array;
data_type : bit;
bit_width : 32;
bit_from : 0;
bit_to : 31;
}
type (ADDR){
base_type : array;
data_type : bit;
bit_width : 11;
bit_from : 0;
bit_to : 10;
}
cell (sram_1rw_32b_2048w_1bank_freepdk45){
memory(){
type : ram;
address_width : 11;
word_width : 32;
}
interface_timing : true;
dont_use : true;
map_only : true;
dont_touch : true;
area : 116044.35785;
leakage_power () {
when : "CSb";
value : 0.306155;
}
cell_leakage_power : 0;
bus(DATA){
bus_type : DATA;
direction : inout;
max_capacitance : 1.6728;
min_capacitance : 0.052275;
three_state : "!OEb & !clk";
memory_write(){
address : ADDR;
clocked_on : clk;
}
memory_read(){
address : ADDR;
}
pin(DATA[31:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
timing(){
timing_sense : non_unate;
related_pin : "clk";
timing_type : falling_edge;
cell_rise(CELL_TABLE) {
values("1.22, 1.223, 1.23",\
"1.222, 1.221, 1.238",\
"1.232, 1.234, 1.237");
}
cell_fall(CELL_TABLE) {
values("0.235, 0.237, 0.251",\
"0.235, 0.237, 0.252",\
"0.241, 0.243, 0.257");
}
rise_transition(CELL_TABLE) {
values("0.02, 0.021, 0.032",\
"0.02, 0.022, 0.032",\
"0.02, 0.022, 0.032");
}
fall_transition(CELL_TABLE) {
values("0.131, 0.13, 0.072",\
"0.132, 0.13, 0.072",\
"0.132, 0.131, 0.074");
}
}
}
}
bus(ADDR){
bus_type : ADDR;
direction : input;
capacitance : 0.2091;
max_transition : 0.04;
pin(ADDR[10:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
}
pin(CSb){
direction : input;
capacitance : 0.2091;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
pin(OEb){
direction : input;
capacitance : 0.2091;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
pin(WEb){
direction : input;
capacitance : 0.2091;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
pin(clk){
clock : true;
direction : input;
capacitance : 0.2091;
internal_power(){
when : "!CSb & clk & !WEb";
rise_power(scalar){
values("0.37352892");
}
fall_power(scalar){
values("0.37352892");
}
}
internal_power(){
when : "!CSb & !clk & WEb";
rise_power(scalar){
values("0.392384140556");
}
fall_power(scalar){
values("0.392384140556");
}
}
internal_power(){
when : "CSb";
rise_power(scalar){
values("0");
}
fall_power(scalar){
values("0");
}
}
timing(){
timing_type :"min_pulse_width";
related_pin : clk;
rise_constraint(scalar) {
values("1.172");
}
fall_constraint(scalar) {
values("1.172");
}
}
timing(){
timing_type :"minimum_period";
related_pin : clk;
rise_constraint(scalar) {
values("2.344");
}
fall_constraint(scalar) {
values("2.344");
}
}
}
}
}

View File

@ -1,347 +0,0 @@
library (sram_1rw_32b_256w_1bank_freepdk45_TT_1p0V_25C_lib){
delay_model : "table_lookup";
time_unit : "1ns" ;
voltage_unit : "1v" ;
current_unit : "1mA" ;
resistance_unit : "1kohm" ;
capacitive_load_unit(1 ,fF) ;
leakage_power_unit : "1mW" ;
pulling_resistance_unit :"1kohm" ;
operating_conditions(OC){
process : 1.0 ;
voltage : 1.0 ;
temperature : 25;
}
input_threshold_pct_fall : 50.0 ;
output_threshold_pct_fall : 50.0 ;
input_threshold_pct_rise : 50.0 ;
output_threshold_pct_rise : 50.0 ;
slew_lower_threshold_pct_fall : 10.0 ;
slew_upper_threshold_pct_fall : 90.0 ;
slew_lower_threshold_pct_rise : 10.0 ;
slew_upper_threshold_pct_rise : 90.0 ;
nom_voltage : 1.0;
nom_temperature : 25;
nom_process : 1.0;
default_cell_leakage_power : 0.0 ;
default_leakage_power_density : 0.0 ;
default_input_pin_cap : 1.0 ;
default_inout_pin_cap : 1.0 ;
default_output_pin_cap : 0.0 ;
default_max_transition : 0.5 ;
default_fanout_load : 1.0 ;
default_max_fanout : 4.0 ;
default_connection_class : universal ;
lu_table_template(CELL_TABLE){
variable_1 : input_net_transition;
variable_2 : total_output_net_capacitance;
index_1("0.00125, 0.005, 0.04");
index_2("0.052275, 0.2091, 1.6728");
}
lu_table_template(CONSTRAINT_TABLE){
variable_1 : related_pin_transition;
variable_2 : constrained_pin_transition;
index_1("0.00125, 0.005, 0.04");
index_2("0.00125, 0.005, 0.04");
}
default_operating_conditions : OC;
type (DATA){
base_type : array;
data_type : bit;
bit_width : 32;
bit_from : 0;
bit_to : 31;
}
type (ADDR){
base_type : array;
data_type : bit;
bit_width : 8;
bit_from : 0;
bit_to : 7;
}
cell (sram_1rw_32b_256w_1bank_freepdk45){
memory(){
type : ram;
address_width : 8;
word_width : 32;
}
interface_timing : true;
dont_use : true;
map_only : true;
dont_touch : true;
area : 12335.4213125;
leakage_power () {
when : "CSb";
value : 0.040298101;
}
cell_leakage_power : 0;
bus(DATA){
bus_type : DATA;
direction : inout;
max_capacitance : 1.6728;
min_capacitance : 0.052275;
three_state : "!OEb & !clk";
memory_write(){
address : ADDR;
clocked_on : clk;
}
memory_read(){
address : ADDR;
}
pin(DATA[31:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
timing(){
timing_sense : non_unate;
related_pin : "clk";
timing_type : falling_edge;
cell_rise(CELL_TABLE) {
values("1.116, 1.117, 1.124",\
"1.116, 1.117, 1.124",\
"1.122, 1.123, 1.13");
}
cell_fall(CELL_TABLE) {
values("0.118, 0.119, 0.132",\
"0.118, 0.12, 0.133",\
"0.124, 0.125, 0.138");
}
rise_transition(CELL_TABLE) {
values("0.02, 0.021, 0.031",\
"0.02, 0.021, 0.031",\
"0.02, 0.021, 0.031");
}
fall_transition(CELL_TABLE) {
values("0.028, 0.03, 0.046",\
"0.028, 0.03, 0.046",\
"0.029, 0.03, 0.046");
}
}
}
}
bus(ADDR){
bus_type : ADDR;
direction : input;
capacitance : 0.2091;
max_transition : 0.04;
pin(ADDR[7:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
}
pin(CSb){
direction : input;
capacitance : 0.2091;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
pin(OEb){
direction : input;
capacitance : 0.2091;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
pin(WEb){
direction : input;
capacitance : 0.2091;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
pin(clk){
clock : true;
direction : input;
capacitance : 0.2091;
internal_power(){
when : "!CSb & clk & !WEb";
rise_power(scalar){
values("0.0644972321667");
}
fall_power(scalar){
values("0.0644972321667");
}
}
internal_power(){
when : "!CSb & !clk & WEb";
rise_power(scalar){
values("0.0770882050833");
}
fall_power(scalar){
values("0.0770882050833");
}
}
internal_power(){
when : "CSb";
rise_power(scalar){
values("0");
}
fall_power(scalar){
values("0");
}
}
timing(){
timing_type :"min_pulse_width";
related_pin : clk;
rise_constraint(scalar) {
values("1.0545");
}
fall_constraint(scalar) {
values("1.0545");
}
}
timing(){
timing_type :"minimum_period";
related_pin : clk;
rise_constraint(scalar) {
values("2.109");
}
fall_constraint(scalar) {
values("2.109");
}
}
}
}
}

View File

@ -1,347 +0,0 @@
library (sram_1rw_32b_512w_1bank_freepdk45_TT_1p0V_25C_lib){
delay_model : "table_lookup";
time_unit : "1ns" ;
voltage_unit : "1v" ;
current_unit : "1mA" ;
resistance_unit : "1kohm" ;
capacitive_load_unit(1 ,fF) ;
leakage_power_unit : "1mW" ;
pulling_resistance_unit :"1kohm" ;
operating_conditions(OC){
process : 1.0 ;
voltage : 1.0 ;
temperature : 25;
}
input_threshold_pct_fall : 50.0 ;
output_threshold_pct_fall : 50.0 ;
input_threshold_pct_rise : 50.0 ;
output_threshold_pct_rise : 50.0 ;
slew_lower_threshold_pct_fall : 10.0 ;
slew_upper_threshold_pct_fall : 90.0 ;
slew_lower_threshold_pct_rise : 10.0 ;
slew_upper_threshold_pct_rise : 90.0 ;
nom_voltage : 1.0;
nom_temperature : 25;
nom_process : 1.0;
default_cell_leakage_power : 0.0 ;
default_leakage_power_density : 0.0 ;
default_input_pin_cap : 1.0 ;
default_inout_pin_cap : 1.0 ;
default_output_pin_cap : 0.0 ;
default_max_transition : 0.5 ;
default_fanout_load : 1.0 ;
default_max_fanout : 4.0 ;
default_connection_class : universal ;
lu_table_template(CELL_TABLE){
variable_1 : input_net_transition;
variable_2 : total_output_net_capacitance;
index_1("0.00125, 0.005, 0.04");
index_2("0.052275, 0.2091, 1.6728");
}
lu_table_template(CONSTRAINT_TABLE){
variable_1 : related_pin_transition;
variable_2 : constrained_pin_transition;
index_1("0.00125, 0.005, 0.04");
index_2("0.00125, 0.005, 0.04");
}
default_operating_conditions : OC;
type (DATA){
base_type : array;
data_type : bit;
bit_width : 32;
bit_from : 0;
bit_to : 31;
}
type (ADDR){
base_type : array;
data_type : bit;
bit_width : 9;
bit_from : 0;
bit_to : 8;
}
cell (sram_1rw_32b_512w_1bank_freepdk45){
memory(){
type : ram;
address_width : 9;
word_width : 32;
}
interface_timing : true;
dont_use : true;
map_only : true;
dont_touch : true;
area : 22454.71095;
leakage_power () {
when : "CSb";
value : 0.077704284;
}
cell_leakage_power : 0;
bus(DATA){
bus_type : DATA;
direction : inout;
max_capacitance : 1.6728;
min_capacitance : 0.052275;
three_state : "!OEb & !clk";
memory_write(){
address : ADDR;
clocked_on : clk;
}
memory_read(){
address : ADDR;
}
pin(DATA[31:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
timing(){
timing_sense : non_unate;
related_pin : "clk";
timing_type : falling_edge;
cell_rise(CELL_TABLE) {
values("1.128, 1.129, 1.136",\
"1.128, 1.129, 1.136",\
"1.134, 1.135, 1.142");
}
cell_fall(CELL_TABLE) {
values("0.136, 0.138, 0.15",\
"0.137, 0.139, 0.151",\
"0.142, 0.144, 0.157");
}
rise_transition(CELL_TABLE) {
values("0.02, 0.021, 0.031",\
"0.02, 0.021, 0.031",\
"0.02, 0.021, 0.031");
}
fall_transition(CELL_TABLE) {
values("0.034, 0.036, 0.05",\
"0.035, 0.036, 0.05",\
"0.035, 0.036, 0.05");
}
}
}
}
bus(ADDR){
bus_type : ADDR;
direction : input;
capacitance : 0.2091;
max_transition : 0.04;
pin(ADDR[8:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
}
pin(CSb){
direction : input;
capacitance : 0.2091;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
pin(OEb){
direction : input;
capacitance : 0.2091;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
pin(WEb){
direction : input;
capacitance : 0.2091;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
pin(clk){
clock : true;
direction : input;
capacitance : 0.2091;
internal_power(){
when : "!CSb & clk & !WEb";
rise_power(scalar){
values("0.0998806242278");
}
fall_power(scalar){
values("0.0998806242278");
}
}
internal_power(){
when : "!CSb & !clk & WEb";
rise_power(scalar){
values("0.114319477006");
}
fall_power(scalar){
values("0.114319477006");
}
}
internal_power(){
when : "CSb";
rise_power(scalar){
values("0");
}
fall_power(scalar){
values("0");
}
}
timing(){
timing_type :"min_pulse_width";
related_pin : clk;
rise_constraint(scalar) {
values("1.094");
}
fall_constraint(scalar) {
values("1.094");
}
}
timing(){
timing_type :"minimum_period";
related_pin : clk;
rise_constraint(scalar) {
values("2.188");
}
fall_constraint(scalar) {
values("2.188");
}
}
}
}
}

View File

@ -1,347 +0,0 @@
library (sram_1rw_64b_1024w_1bank_freepdk45_TT_1p0V_25C_lib){
delay_model : "table_lookup";
time_unit : "1ns" ;
voltage_unit : "1v" ;
current_unit : "1mA" ;
resistance_unit : "1kohm" ;
capacitive_load_unit(1 ,fF) ;
leakage_power_unit : "1mW" ;
pulling_resistance_unit :"1kohm" ;
operating_conditions(OC){
process : 1.0 ;
voltage : 1.0 ;
temperature : 25;
}
input_threshold_pct_fall : 50.0 ;
output_threshold_pct_fall : 50.0 ;
input_threshold_pct_rise : 50.0 ;
output_threshold_pct_rise : 50.0 ;
slew_lower_threshold_pct_fall : 10.0 ;
slew_upper_threshold_pct_fall : 90.0 ;
slew_lower_threshold_pct_rise : 10.0 ;
slew_upper_threshold_pct_rise : 90.0 ;
nom_voltage : 1.0;
nom_temperature : 25;
nom_process : 1.0;
default_cell_leakage_power : 0.0 ;
default_leakage_power_density : 0.0 ;
default_input_pin_cap : 1.0 ;
default_inout_pin_cap : 1.0 ;
default_output_pin_cap : 0.0 ;
default_max_transition : 0.5 ;
default_fanout_load : 1.0 ;
default_max_fanout : 4.0 ;
default_connection_class : universal ;
lu_table_template(CELL_TABLE){
variable_1 : input_net_transition;
variable_2 : total_output_net_capacitance;
index_1("0.00125, 0.005, 0.04");
index_2("0.052275, 0.2091, 1.6728");
}
lu_table_template(CONSTRAINT_TABLE){
variable_1 : related_pin_transition;
variable_2 : constrained_pin_transition;
index_1("0.00125, 0.005, 0.04");
index_2("0.00125, 0.005, 0.04");
}
default_operating_conditions : OC;
type (DATA){
base_type : array;
data_type : bit;
bit_width : 64;
bit_from : 0;
bit_to : 63;
}
type (ADDR){
base_type : array;
data_type : bit;
bit_width : 10;
bit_from : 0;
bit_to : 9;
}
cell (sram_1rw_64b_1024w_1bank_freepdk45){
memory(){
type : ram;
address_width : 10;
word_width : 64;
}
interface_timing : true;
dont_use : true;
map_only : true;
dont_touch : true;
area : 76901.5771875;
leakage_power () {
when : "CSb";
value : 0.30184115;
}
cell_leakage_power : 0;
bus(DATA){
bus_type : DATA;
direction : inout;
max_capacitance : 1.6728;
min_capacitance : 0.052275;
three_state : "!OEb & !clk";
memory_write(){
address : ADDR;
clocked_on : clk;
}
memory_read(){
address : ADDR;
}
pin(DATA[63:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
timing(){
timing_sense : non_unate;
related_pin : "clk";
timing_type : falling_edge;
cell_rise(CELL_TABLE) {
values("1.836, 1.837, 1.844",\
"1.837, 1.838, 1.846",\
"1.843, 1.843, 1.851");
}
cell_fall(CELL_TABLE) {
values("0.208, 0.211, 0.227",\
"0.209, 0.211, 0.228",\
"0.214, 0.217, 0.233");
}
rise_transition(CELL_TABLE) {
values("0.021, 0.022, 0.032",\
"0.021, 0.022, 0.032",\
"0.021, 0.022, 0.032");
}
fall_transition(CELL_TABLE) {
values("0.049, 0.05, 0.063",\
"0.049, 0.05, 0.063",\
"0.049, 0.05, 0.064");
}
}
}
}
bus(ADDR){
bus_type : ADDR;
direction : input;
capacitance : 0.2091;
max_transition : 0.04;
pin(ADDR[9:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
}
pin(CSb){
direction : input;
capacitance : 0.2091;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
pin(OEb){
direction : input;
capacitance : 0.2091;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
pin(WEb){
direction : input;
capacitance : 0.2091;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
pin(clk){
clock : true;
direction : input;
capacitance : 0.2091;
internal_power(){
when : "!CSb & clk & !WEb";
rise_power(scalar){
values("0.269265398756");
}
fall_power(scalar){
values("0.269265398756");
}
}
internal_power(){
when : "!CSb & !clk & WEb";
rise_power(scalar){
values("0.293634058756");
}
fall_power(scalar){
values("0.293634058756");
}
}
internal_power(){
when : "CSb";
rise_power(scalar){
values("0");
}
fall_power(scalar){
values("0");
}
}
timing(){
timing_type :"min_pulse_width";
related_pin : clk;
rise_constraint(scalar) {
values("1.797");
}
fall_constraint(scalar) {
values("1.797");
}
}
timing(){
timing_type :"minimum_period";
related_pin : clk;
rise_constraint(scalar) {
values("3.594");
}
fall_constraint(scalar) {
values("3.594");
}
}
}
}
}

View File

@ -1,347 +0,0 @@
library (sram_1rw_8b_256w_1bank_freepdk45_TT_1p0V_25C_lib){
delay_model : "table_lookup";
time_unit : "1ns" ;
voltage_unit : "1v" ;
current_unit : "1mA" ;
resistance_unit : "1kohm" ;
capacitive_load_unit(1 ,fF) ;
leakage_power_unit : "1mW" ;
pulling_resistance_unit :"1kohm" ;
operating_conditions(OC){
process : 1.0 ;
voltage : 1.0 ;
temperature : 25;
}
input_threshold_pct_fall : 50.0 ;
output_threshold_pct_fall : 50.0 ;
input_threshold_pct_rise : 50.0 ;
output_threshold_pct_rise : 50.0 ;
slew_lower_threshold_pct_fall : 10.0 ;
slew_upper_threshold_pct_fall : 90.0 ;
slew_lower_threshold_pct_rise : 10.0 ;
slew_upper_threshold_pct_rise : 90.0 ;
nom_voltage : 1.0;
nom_temperature : 25;
nom_process : 1.0;
default_cell_leakage_power : 0.0 ;
default_leakage_power_density : 0.0 ;
default_input_pin_cap : 1.0 ;
default_inout_pin_cap : 1.0 ;
default_output_pin_cap : 0.0 ;
default_max_transition : 0.5 ;
default_fanout_load : 1.0 ;
default_max_fanout : 4.0 ;
default_connection_class : universal ;
lu_table_template(CELL_TABLE){
variable_1 : input_net_transition;
variable_2 : total_output_net_capacitance;
index_1("0.00125, 0.005, 0.04");
index_2("0.052275, 0.2091, 1.6728");
}
lu_table_template(CONSTRAINT_TABLE){
variable_1 : related_pin_transition;
variable_2 : constrained_pin_transition;
index_1("0.00125, 0.005, 0.04");
index_2("0.00125, 0.005, 0.04");
}
default_operating_conditions : OC;
type (DATA){
base_type : array;
data_type : bit;
bit_width : 8;
bit_from : 0;
bit_to : 7;
}
type (ADDR){
base_type : array;
data_type : bit;
bit_width : 8;
bit_from : 0;
bit_to : 7;
}
cell (sram_1rw_8b_256w_1bank_freepdk45){
memory(){
type : ram;
address_width : 8;
word_width : 8;
}
interface_timing : true;
dont_use : true;
map_only : true;
dont_touch : true;
area : 4498.9233125;
leakage_power () {
when : "CSb";
value : 0.011168618;
}
cell_leakage_power : 0;
bus(DATA){
bus_type : DATA;
direction : inout;
max_capacitance : 1.6728;
min_capacitance : 0.052275;
three_state : "!OEb & !clk";
memory_write(){
address : ADDR;
clocked_on : clk;
}
memory_read(){
address : ADDR;
}
pin(DATA[7:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
timing(){
timing_sense : non_unate;
related_pin : "clk";
timing_type : falling_edge;
cell_rise(CELL_TABLE) {
values("0.556, 0.557, 0.564",\
"0.556, 0.557, 0.564",\
"0.562, 0.563, 0.57");
}
cell_fall(CELL_TABLE) {
values("0.088, 0.089, 0.098",\
"0.088, 0.09, 0.099",\
"0.094, 0.095, 0.104");
}
rise_transition(CELL_TABLE) {
values("0.02, 0.021, 0.031",\
"0.02, 0.021, 0.031",\
"0.02, 0.021, 0.031");
}
fall_transition(CELL_TABLE) {
values("0.03, 0.03, 0.041",\
"0.031, 0.03, 0.041",\
"0.031, 0.031, 0.041");
}
}
}
}
bus(ADDR){
bus_type : ADDR;
direction : input;
capacitance : 0.2091;
max_transition : 0.04;
pin(ADDR[7:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
}
pin(CSb){
direction : input;
capacitance : 0.2091;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
pin(OEb){
direction : input;
capacitance : 0.2091;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
pin(WEb){
direction : input;
capacitance : 0.2091;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
pin(clk){
clock : true;
direction : input;
capacitance : 0.2091;
internal_power(){
when : "!CSb & clk & !WEb";
rise_power(scalar){
values("0.0382237081278");
}
fall_power(scalar){
values("0.0382237081278");
}
}
internal_power(){
when : "!CSb & !clk & WEb";
rise_power(scalar){
values("0.0443502652111");
}
fall_power(scalar){
values("0.0443502652111");
}
}
internal_power(){
when : "CSb";
rise_power(scalar){
values("0");
}
fall_power(scalar){
values("0");
}
}
timing(){
timing_type :"min_pulse_width";
related_pin : clk;
rise_constraint(scalar) {
values("0.5275");
}
fall_constraint(scalar) {
values("0.5275");
}
}
timing(){
timing_type :"minimum_period";
related_pin : clk;
rise_constraint(scalar) {
values("1.055");
}
fall_constraint(scalar) {
values("1.055");
}
}
}
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -1,138 +0,0 @@
[globals/init_openram]: Initializing OpenRAM...
[globals/setup_paths]: Temporary files saved in /tmp/openram_mrg_12899_temp/
[globals/read_config]: Configuration file is /soe/mrg/OpenRAM/lib/freepdk45/configs/sram_1rw_128b_1024w_1bank_freepdk45.py
[globals/read_config]: Output saved in ./
[globals/import_tech]: Technology path is /soe/mrg/OpenRAM/technology/freepdk45/
|==============================================================================|
|========= OpenRAM Compiler =========|
|========= =========|
|========= VLSI Design and Automation Lab =========|
|========= University of California Santa Cruz CE Department =========|
|========= =========|
|========= VLSI Computer Architecture Research Group =========|
|========= Oklahoma State University ECE Department =========|
|========= =========|
|========= Usage help: openram-user-group@ucsc.edu =========|
|========= Development help: openram-dev-group@ucsc.edu =========|
|========= Temp dir: /tmp/openram_mrg_12899_temp/ =========|
|==============================================================================|
Output files are sram_1rw_128b_1024w_1bank_freepdk45.(sp|gds|v|lib|lef)
Technology: freepdk45
Word size: 128
Words: 1024
Banks: 1
[globals/get_tool]: Using DRC: /bsoe/software/mentor/calibre/aoi_cal_2017.3_29.23/bin/calibre
[globals/get_tool]: Using LVS: /bsoe/software/mentor/calibre/aoi_cal_2017.3_29.23/bin/calibre
[globals/get_tool]: Using PEX: /bsoe/software/mentor/calibre/aoi_cal_2017.3_29.23/bin/calibre
** Start: 2018-02-24 16:26:13.838687 seconds
[sram/compute_sizes]: Words per row: 4
[control_logic/__init__]: Creating control_logic
[ms_flop_array/__init__]: Creating msf_control
[verify.calibre/run_drc]: msf_control Geometries: 1768 Checks: 167 Errors: 0
[bitcell_array/__init__]: Creating bitline_load 52 x 1
[verify.calibre/run_drc]: bitline_load Geometries: 15917 Checks: 167 Errors: 0
[verify.calibre/run_drc]: delay_chain Geometries: 906 Checks: 167 Errors: 0
[verify.calibre/run_drc]: replica_bitline Geometries: 17508 Checks: 167 Errors: 0
[verify.calibre/run_drc]: control_logic Geometries: 21120 Checks: 167 Errors: 0
[bitcell_array/__init__]: Creating bitcell_array 256 x 512
[verify.calibre/run_drc]: bitcell_array Geometries: 39847938 Checks: 167 Errors: 0
[precharge_array/__init__]: Creating precharge_array
[verify.calibre/run_drc]: precharge Geometries: 86 Checks: 167 Errors: 0
[verify.calibre/run_drc]: precharge_array Geometries: 89090 Checks: 167 Errors: 0
[single_level_column_mux_array/__init__]: Creating columnmux_array
[verify.calibre/run_drc]: columnmux_array Geometries: 48389 Checks: 167 Errors: 0
[sense_amp_array/__init__]: Creating sense_amp_array
[verify.calibre/run_drc]: sense_amp_array Geometries: 31747 Checks: 167 Errors: 0
[write_driver_array/__init__]: Creating write_driver_array
[verify.calibre/run_drc]: write_driver_array Geometries: 41475 Checks: 167 Errors: 0
[verify.calibre/run_drc]: pre2x4 Geometries: 969 Checks: 167 Errors: 0
[verify.calibre/run_drc]: pre3x8 Geometries: 2251 Checks: 167 Errors: 0
[verify.calibre/run_drc]: hierarchical_decoder_256rows Geometries: 70385 Checks: 167 Errors: 0
[ms_flop_array/__init__]: Creating msf_address
[verify.calibre/run_drc]: msf_address Geometries: 5877 Checks: 167 Errors: 0
[ms_flop_array/__init__]: Creating msf_data_in
[verify.calibre/run_drc]: msf_data_in Geometries: 75270 Checks: 167 Errors: 0
[tri_gate_array/__init__]: Creating tri_gate_array
[verify.calibre/run_drc]: tri_gate_array Geometries: 22788 Checks: 167 Errors: 0
[verify.calibre/run_drc]: wordline_driver Geometries: 70146 Checks: 167 Errors: 0
[verify.calibre/run_drc]: bank Geometries: 40382617 Checks: 167 Errors: 0
[verify.calibre/run_drc]: sram_1rw_128b_1024w_1bank_freepdk45 Geometries: 40410068 Checks: 167 Errors: 0
** SRAM creation: 3506.7 seconds
SP: Writing to ./sram_1rw_128b_1024w_1bank_freepdk45.sp
** Spice writing: 0.6 seconds
[globals/get_tool]: Using spice: /bsoe/software/synopsys/xa/bin/xa
LIB: Characterizing...
Performing simulation-based characterization with xa
Trimming netlist to speed up characterization.
[characterizer.lib/prepare_tables]: Loads: [ 0.052275 0.2091 1.6728 ]
[characterizer.lib/prepare_tables]: Slews: [ 0.00125 0.005 0.04 ]
[characterizer.lib/characterize_corners]: Corner: ('TT', 1.0, 25)
[characterizer.lib/characterize_corners]: Writing to ./sram_1rw_128b_1024w_1bank_freepdk45_TT_1p0V_25C.lib
[characterizer.trim_spice/__init__]: Trimming non-critical cells to speed-up characterization: /tmp/openram_mrg_12899_temp/reduced.sp.
[characterizer.trim_spice/trim]: Keeping 1111111111 address
[characterizer.trim_spice/trim]: Keeping 127 data bit
[characterizer.trim_spice/trim]: Keeping bl[511] (trimming other BLs)
[characterizer.trim_spice/trim]: Keeping wl[255] (trimming other WLs)
[characterizer.delay/find_feasible_period]: Trying feasible period: 5.0ns
[characterizer.delay/find_feasible_period]: Trying feasible period: 10.0ns
[characterizer.delay/find_feasible_period]: Found feasible_period: 10.0ns feasible_delay 3.1226964ns/0.30308602ns slew 0.034041887ns/0.077321978ns
[characterizer.delay/find_min_period]: MinPeriod Search: 5.0ns (ub: 10.0 lb: 0.0)
[characterizer.delay/find_min_period]: MinPeriod Search: 7.5ns (ub: 10.0 lb: 5.0)
[characterizer.delay/find_min_period]: MinPeriod Search: 6.25ns (ub: 7.5 lb: 5.0)
[characterizer.delay/find_min_period]: MinPeriod Search: 5.625ns (ub: 6.25 lb: 5.0)
[characterizer.delay/find_min_period]: MinPeriod Search: 5.9375ns (ub: 6.25 lb: 5.625)
[characterizer.delay/find_min_period]: MinPeriod Search: 5.78125ns (ub: 5.9375 lb: 5.625)
[characterizer.delay/analyze]: Min Period: 5.9375n with a delay of 3.1226964 / 0.30308602
[characterizer.setup_hold/analyze]: Clock slew: 0.00125 Data slew: 0.00125
[characterizer.setup_hold/analyze]: Setup Time for low_to_high transition: 0.0085449219
[characterizer.setup_hold/analyze]: Setup Time for high_to_low transition: 0.0085449219
[characterizer.setup_hold/analyze]: Hold Time for low_to_high transition: 0.0024414063
[characterizer.setup_hold/analyze]: Hold Time for high_to_low transition: -0.0036621094
[characterizer.setup_hold/analyze]: Clock slew: 0.00125 Data slew: 0.005
[characterizer.setup_hold/analyze]: Setup Time for low_to_high transition: 0.014648437
[characterizer.setup_hold/analyze]: Setup Time for high_to_low transition: 0.0085449219
[characterizer.setup_hold/analyze]: Hold Time for low_to_high transition: 0.0024414062
[characterizer.setup_hold/analyze]: Hold Time for high_to_low transition: -0.0036621094
[characterizer.setup_hold/analyze]: Clock slew: 0.00125 Data slew: 0.04
[characterizer.setup_hold/analyze]: Setup Time for low_to_high transition: 0.020751953
[characterizer.setup_hold/analyze]: Setup Time for high_to_low transition: 0.014648437
[characterizer.setup_hold/analyze]: Hold Time for low_to_high transition: -0.0036621094
[characterizer.setup_hold/analyze]: Hold Time for high_to_low transition: -0.015869141
[characterizer.setup_hold/analyze]: Clock slew: 0.005 Data slew: 0.00125
[characterizer.setup_hold/analyze]: Setup Time for low_to_high transition: 0.0085449219
[characterizer.setup_hold/analyze]: Setup Time for high_to_low transition: 0.0085449219
[characterizer.setup_hold/analyze]: Hold Time for low_to_high transition: 0.0024414063
[characterizer.setup_hold/analyze]: Hold Time for high_to_low transition: -0.0036621094
[characterizer.setup_hold/analyze]: Clock slew: 0.005 Data slew: 0.005
[characterizer.setup_hold/analyze]: Setup Time for low_to_high transition: 0.014648437
[characterizer.setup_hold/analyze]: Setup Time for high_to_low transition: 0.0085449219
[characterizer.setup_hold/analyze]: Hold Time for low_to_high transition: 0.0024414062
[characterizer.setup_hold/analyze]: Hold Time for high_to_low transition: -0.0036621094
[characterizer.setup_hold/analyze]: Clock slew: 0.005 Data slew: 0.04
[characterizer.setup_hold/analyze]: Setup Time for low_to_high transition: 0.020751953
[characterizer.setup_hold/analyze]: Setup Time for high_to_low transition: 0.014648437
[characterizer.setup_hold/analyze]: Hold Time for low_to_high transition: -0.0036621094
[characterizer.setup_hold/analyze]: Hold Time for high_to_low transition: -0.015869141
[characterizer.setup_hold/analyze]: Clock slew: 0.04 Data slew: 0.00125
[characterizer.setup_hold/analyze]: Setup Time for low_to_high transition: 0.0085449219
[characterizer.setup_hold/analyze]: Setup Time for high_to_low transition: 0.0085449219
[characterizer.setup_hold/analyze]: Hold Time for low_to_high transition: 0.0024414063
[characterizer.setup_hold/analyze]: Hold Time for high_to_low transition: -0.0036621094
[characterizer.setup_hold/analyze]: Clock slew: 0.04 Data slew: 0.005
[characterizer.setup_hold/analyze]: Setup Time for low_to_high transition: 0.014648437
[characterizer.setup_hold/analyze]: Setup Time for high_to_low transition: 0.0085449219
[characterizer.setup_hold/analyze]: Hold Time for low_to_high transition: 0.0024414062
[characterizer.setup_hold/analyze]: Hold Time for high_to_low transition: -0.0036621094
[characterizer.setup_hold/analyze]: Clock slew: 0.04 Data slew: 0.04
[characterizer.setup_hold/analyze]: Setup Time for low_to_high transition: 0.020751953
[characterizer.setup_hold/analyze]: Setup Time for high_to_low transition: 0.014648437
[characterizer.setup_hold/analyze]: Hold Time for low_to_high transition: -0.0036621094
[characterizer.setup_hold/analyze]: Hold Time for high_to_low transition: -0.015869141
** Characterization: 16788.8 seconds
GDS: Writing to ./sram_1rw_128b_1024w_1bank_freepdk45.gds
** GDS: 9.0 seconds
LEF: Writing to ./sram_1rw_128b_1024w_1bank_freepdk45.lef
** LEF: 24.4 seconds
Verilog: Writing to ./sram_1rw_128b_1024w_1bank_freepdk45.v
** Verilog: 0.0 seconds
** End: 20330.3 seconds

View File

@ -1,62 +0,0 @@
[globals/init_openram]: Initializing OpenRAM...
[globals/setup_paths]: Temporary files saved in /tmp/openram_mrg_18643_temp/
[globals/read_config]: Configuration file is /soe/mrg/OpenRAM/lib/freepdk45/configs/sram_1rw_128b_1024w_2bank_freepdk45.py
[globals/read_config]: Output saved in ./
[globals/import_tech]: Technology path is /soe/mrg/OpenRAM/technology/freepdk45/
|==============================================================================|
|========= OpenRAM Compiler =========|
|========= =========|
|========= VLSI Design and Automation Lab =========|
|========= University of California Santa Cruz CE Department =========|
|========= =========|
|========= VLSI Computer Architecture Research Group =========|
|========= Oklahoma State University ECE Department =========|
|========= =========|
|========= Usage help: openram-user-group@ucsc.edu =========|
|========= Development help: openram-dev-group@ucsc.edu =========|
|========= Temp dir: /tmp/openram_mrg_18643_temp/ =========|
|==============================================================================|
Output files are sram_1rw_128b_1024w_2bank_freepdk45.(sp|gds|v|lib|lef)
Technology: freepdk45
Word size: 128
Words: 1024
Banks: 2
[globals/get_tool]: Using DRC: /bsoe/software/mentor/calibre/aoi_cal_2017.3_29.23/bin/calibre
[globals/get_tool]: Using LVS: /bsoe/software/mentor/calibre/aoi_cal_2017.3_29.23/bin/calibre
[globals/get_tool]: Using PEX: /bsoe/software/mentor/calibre/aoi_cal_2017.3_29.23/bin/calibre
** Start: 2018-02-23 19:17:15.047539 seconds
[sram/compute_sizes]: Words per row: 2
[control_logic/__init__]: Creating control_logic
[ms_flop_array/__init__]: Creating msf_control
[verify.calibre/run_drc]: msf_control Geometries: 1768 Checks: 167 Errors: 0
[bitcell_array/__init__]: Creating bitline_load 52 x 1
[verify.calibre/run_drc]: bitline_load Geometries: 15917 Checks: 167 Errors: 0
[verify.calibre/run_drc]: delay_chain Geometries: 906 Checks: 167 Errors: 0
[verify.calibre/run_drc]: replica_bitline Geometries: 17508 Checks: 167 Errors: 0
[verify.calibre/run_drc]: control_logic Geometries: 21120 Checks: 167 Errors: 0
[bitcell_array/__init__]: Creating bitcell_array 256 x 256
[verify.calibre/run_drc]: bitcell_array Geometries: 19924226 Checks: 167 Errors: 0
[precharge_array/__init__]: Creating precharge_array
[verify.calibre/run_drc]: precharge Geometries: 86 Checks: 167 Errors: 0
[verify.calibre/run_drc]: precharge_array Geometries: 44546 Checks: 167 Errors: 0
[single_level_column_mux_array/__init__]: Creating columnmux_array
[verify.calibre/run_drc]: columnmux_array Geometries: 24323 Checks: 167 Errors: 0
[sense_amp_array/__init__]: Creating sense_amp_array
[verify.calibre/run_drc]: sense_amp_array Geometries: 31747 Checks: 167 Errors: 0
[write_driver_array/__init__]: Creating write_driver_array
[verify.calibre/run_drc]: write_driver_array Geometries: 41475 Checks: 167 Errors: 0
[verify.calibre/run_drc]: pre2x4 Geometries: 969 Checks: 167 Errors: 0
[verify.calibre/run_drc]: pre3x8 Geometries: 2251 Checks: 167 Errors: 0
[verify.calibre/run_drc]: hierarchical_decoder_256rows Geometries: 70385 Checks: 167 Errors: 0
[ms_flop_array/__init__]: Creating msf_address
[verify.calibre/run_drc]: msf_address Geometries: 5290 Checks: 167 Errors: 0
[ms_flop_array/__init__]: Creating msf_data_in
[verify.calibre/run_drc]: msf_data_in Geometries: 75270 Checks: 167 Errors: 0
[tri_gate_array/__init__]: Creating tri_gate_array
[verify.calibre/run_drc]: tri_gate_array Geometries: 22788 Checks: 167 Errors: 0
[verify.calibre/run_drc]: wordline_driver Geometries: 70146 Checks: 167 Errors: 0
[verify.calibre/run_drc]: bank Geometries: 20381520 Checks: 167 Errors: 0
[ms_flop_array/__init__]: Creating msb_address
[verify.calibre/run_drc]: msb_address Geometries: 594 Checks: 167 Errors: 0
ERROR: file calibre.py: line 131: sram_1rw_128b_1024w_2bank_freepdk45 Geometries: 40824902 Checks: 167 Errors: 1
ERROR: file design.py: line 87: DRC failed for sram_1rw_128b_1024w_2bank_freepdk45

View File

@ -1,139 +0,0 @@
[globals/init_openram]: Initializing OpenRAM...
[globals/setup_paths]: Temporary files saved in /tmp/openram_mrg_5959_temp/
[globals/read_config]: Configuration file is /soe/mrg/OpenRAM/lib/freepdk45/configs/sram_1rw_128b_1024w_4bank_freepdk45.py
[globals/read_config]: Output saved in ./
[globals/import_tech]: Technology path is /soe/mrg/OpenRAM/technology/freepdk45/
|==============================================================================|
|========= OpenRAM Compiler =========|
|========= =========|
|========= VLSI Design and Automation Lab =========|
|========= University of California Santa Cruz CE Department =========|
|========= =========|
|========= VLSI Computer Architecture Research Group =========|
|========= Oklahoma State University ECE Department =========|
|========= =========|
|========= Usage help: openram-user-group@ucsc.edu =========|
|========= Development help: openram-dev-group@ucsc.edu =========|
|========= Temp dir: /tmp/openram_mrg_5959_temp/ =========|
|==============================================================================|
Output files are sram_1rw_128b_1024w_4bank_freepdk45.(sp|gds|v|lib|lef)
Technology: freepdk45
Word size: 128
Words: 1024
Banks: 4
[globals/get_tool]: Using DRC: /bsoe/software/mentor/calibre/aoi_cal_2017.3_29.23/bin/calibre
[globals/get_tool]: Using LVS: /bsoe/software/mentor/calibre/aoi_cal_2017.3_29.23/bin/calibre
[globals/get_tool]: Using PEX: /bsoe/software/mentor/calibre/aoi_cal_2017.3_29.23/bin/calibre
** Start: 2018-02-23 19:35:43.956230 seconds
[sram/compute_sizes]: Words per row: 2
[control_logic/__init__]: Creating control_logic
[ms_flop_array/__init__]: Creating msf_control
[verify.calibre/run_drc]: msf_control Geometries: 1768 Checks: 167 Errors: 0
[bitcell_array/__init__]: Creating bitline_load 26 x 1
[verify.calibre/run_drc]: bitline_load Geometries: 7961 Checks: 167 Errors: 0
[verify.calibre/run_drc]: delay_chain Geometries: 906 Checks: 167 Errors: 0
[verify.calibre/run_drc]: replica_bitline Geometries: 9383 Checks: 167 Errors: 0
[verify.calibre/run_drc]: control_logic Geometries: 12956 Checks: 167 Errors: 0
[bitcell_array/__init__]: Creating bitcell_array 128 x 256
[verify.calibre/run_drc]: bitcell_array Geometries: 9962498 Checks: 167 Errors: 0
[precharge_array/__init__]: Creating precharge_array
[verify.calibre/run_drc]: precharge Geometries: 86 Checks: 167 Errors: 0
[verify.calibre/run_drc]: precharge_array Geometries: 44546 Checks: 167 Errors: 0
[single_level_column_mux_array/__init__]: Creating columnmux_array
[verify.calibre/run_drc]: columnmux_array Geometries: 24323 Checks: 167 Errors: 0
[sense_amp_array/__init__]: Creating sense_amp_array
[verify.calibre/run_drc]: sense_amp_array Geometries: 31747 Checks: 167 Errors: 0
[write_driver_array/__init__]: Creating write_driver_array
[verify.calibre/run_drc]: write_driver_array Geometries: 41475 Checks: 167 Errors: 0
[verify.calibre/run_drc]: pre2x4 Geometries: 969 Checks: 167 Errors: 0
[verify.calibre/run_drc]: pre3x8 Geometries: 2251 Checks: 167 Errors: 0
[verify.calibre/run_drc]: hierarchical_decoder_128rows Geometries: 65237 Checks: 167 Errors: 0
[ms_flop_array/__init__]: Creating msf_address
[verify.calibre/run_drc]: msf_address Geometries: 4703 Checks: 167 Errors: 0
[ms_flop_array/__init__]: Creating msf_data_in
[verify.calibre/run_drc]: msf_data_in Geometries: 75270 Checks: 167 Errors: 0
[tri_gate_array/__init__]: Creating tri_gate_array
[verify.calibre/run_drc]: tri_gate_array Geometries: 22788 Checks: 167 Errors: 0
[verify.calibre/run_drc]: wordline_driver Geometries: 35074 Checks: 167 Errors: 0
[verify.calibre/run_drc]: bank Geometries: 10340523 Checks: 167 Errors: 0
[ms_flop_array/__init__]: Creating msb_address
[verify.calibre/run_drc]: msb_address Geometries: 1181 Checks: 167 Errors: 0
[verify.calibre/run_drc]: sram_1rw_128b_1024w_4bank_freepdk45 Geometries: 42826713 Checks: 167 Errors: 0
** SRAM creation: 439.1 seconds
SP: Writing to ./sram_1rw_128b_1024w_4bank_freepdk45.sp
** Spice writing: 0.2 seconds
[globals/get_tool]: Using spice: /bsoe/software/synopsys/xa/bin/xa
LIB: Characterizing...
Performing simulation-based characterization with xa
Trimming netlist to speed up characterization.
[characterizer.lib/prepare_tables]: Loads: [ 0.052275 0.2091 1.6728 ]
[characterizer.lib/prepare_tables]: Slews: [ 0.00125 0.005 0.04 ]
[characterizer.lib/characterize_corners]: Corner: ('TT', 1.0, 25)
[characterizer.lib/characterize_corners]: Writing to ./sram_1rw_128b_1024w_4bank_freepdk45_TT_1p0V_25C.lib
[characterizer.trim_spice/__init__]: Trimming non-critical cells to speed-up characterization: /tmp/openram_mrg_5959_temp/reduced.sp.
[characterizer.trim_spice/trim]: Keeping 1111111111 address
[characterizer.trim_spice/trim]: Keeping 127 data bit
[characterizer.trim_spice/trim]: Keeping bl[254] (trimming other BLs)
[characterizer.trim_spice/trim]: Keeping wl[511] (trimming other WLs)
[characterizer.delay/find_feasible_period]: Trying feasible period: 5.0ns
[characterizer.delay/find_feasible_period]: Found feasible_period: 5.0ns feasible_delay 0.19175762ns/0.17403244ns slew 0.091382364ns/0.093018754ns
[characterizer.delay/find_min_period]: MinPeriod Search: 2.5ns (ub: 5.0 lb: 0.0)
[characterizer.delay/find_min_period]: MinPeriod Search: 1.25ns (ub: 2.5 lb: 0.0)
[characterizer.delay/find_min_period]: MinPeriod Search: 1.875ns (ub: 2.5 lb: 1.25)
[characterizer.delay/find_min_period]: MinPeriod Search: 2.1875ns (ub: 2.5 lb: 1.875)
[characterizer.delay/find_min_period]: MinPeriod Search: 2.03125ns (ub: 2.1875 lb: 1.875)
[characterizer.delay/find_min_period]: MinPeriod Search: 1.953125ns (ub: 2.03125 lb: 1.875)
[characterizer.delay/analyze]: Min Period: 2.03125n with a delay of 0.19175762 / 0.17403244
[characterizer.setup_hold/analyze]: Clock slew: 0.00125 Data slew: 0.00125
[characterizer.setup_hold/analyze]: Setup Time for low_to_high transition: 0.0085449219
[characterizer.setup_hold/analyze]: Setup Time for high_to_low transition: 0.0085449219
[characterizer.setup_hold/analyze]: Hold Time for low_to_high transition: 0.0024414063
[characterizer.setup_hold/analyze]: Hold Time for high_to_low transition: -0.0036621094
[characterizer.setup_hold/analyze]: Clock slew: 0.00125 Data slew: 0.005
[characterizer.setup_hold/analyze]: Setup Time for low_to_high transition: 0.014648437
[characterizer.setup_hold/analyze]: Setup Time for high_to_low transition: 0.0085449219
[characterizer.setup_hold/analyze]: Hold Time for low_to_high transition: 0.0024414062
[characterizer.setup_hold/analyze]: Hold Time for high_to_low transition: -0.0036621094
[characterizer.setup_hold/analyze]: Clock slew: 0.00125 Data slew: 0.04
[characterizer.setup_hold/analyze]: Setup Time for low_to_high transition: 0.020751953
[characterizer.setup_hold/analyze]: Setup Time for high_to_low transition: 0.014648437
[characterizer.setup_hold/analyze]: Hold Time for low_to_high transition: -0.0036621094
[characterizer.setup_hold/analyze]: Hold Time for high_to_low transition: -0.015869141
[characterizer.setup_hold/analyze]: Clock slew: 0.005 Data slew: 0.00125
[characterizer.setup_hold/analyze]: Setup Time for low_to_high transition: 0.0085449219
[characterizer.setup_hold/analyze]: Setup Time for high_to_low transition: 0.0085449219
[characterizer.setup_hold/analyze]: Hold Time for low_to_high transition: 0.0024414063
[characterizer.setup_hold/analyze]: Hold Time for high_to_low transition: -0.0036621094
[characterizer.setup_hold/analyze]: Clock slew: 0.005 Data slew: 0.005
[characterizer.setup_hold/analyze]: Setup Time for low_to_high transition: 0.014648437
[characterizer.setup_hold/analyze]: Setup Time for high_to_low transition: 0.0085449219
[characterizer.setup_hold/analyze]: Hold Time for low_to_high transition: 0.0024414062
[characterizer.setup_hold/analyze]: Hold Time for high_to_low transition: -0.0036621094
[characterizer.setup_hold/analyze]: Clock slew: 0.005 Data slew: 0.04
[characterizer.setup_hold/analyze]: Setup Time for low_to_high transition: 0.020751953
[characterizer.setup_hold/analyze]: Setup Time for high_to_low transition: 0.014648437
[characterizer.setup_hold/analyze]: Hold Time for low_to_high transition: -0.0036621094
[characterizer.setup_hold/analyze]: Hold Time for high_to_low transition: -0.015869141
[characterizer.setup_hold/analyze]: Clock slew: 0.04 Data slew: 0.00125
[characterizer.setup_hold/analyze]: Setup Time for low_to_high transition: 0.0085449219
[characterizer.setup_hold/analyze]: Setup Time for high_to_low transition: 0.0085449219
[characterizer.setup_hold/analyze]: Hold Time for low_to_high transition: 0.0024414063
[characterizer.setup_hold/analyze]: Hold Time for high_to_low transition: -0.0036621094
[characterizer.setup_hold/analyze]: Clock slew: 0.04 Data slew: 0.005
[characterizer.setup_hold/analyze]: Setup Time for low_to_high transition: 0.014648437
[characterizer.setup_hold/analyze]: Setup Time for high_to_low transition: 0.0085449219
[characterizer.setup_hold/analyze]: Hold Time for low_to_high transition: 0.0024414062
[characterizer.setup_hold/analyze]: Hold Time for high_to_low transition: -0.0036621094
[characterizer.setup_hold/analyze]: Clock slew: 0.04 Data slew: 0.04
[characterizer.setup_hold/analyze]: Setup Time for low_to_high transition: 0.020751953
[characterizer.setup_hold/analyze]: Setup Time for high_to_low transition: 0.014648437
[characterizer.setup_hold/analyze]: Hold Time for low_to_high transition: -0.0036621094
[characterizer.setup_hold/analyze]: Hold Time for high_to_low transition: -0.015869141
** Characterization: 35039.9 seconds
GDS: Writing to ./sram_1rw_128b_1024w_4bank_freepdk45.gds
** GDS: 5.3 seconds
LEF: Writing to ./sram_1rw_128b_1024w_4bank_freepdk45.lef
** LEF: 36.1 seconds
Verilog: Writing to ./sram_1rw_128b_1024w_4bank_freepdk45.v
** Verilog: 0.0 seconds
** End: 35521.6 seconds

Some files were not shown because too many files have changed in this diff Show More