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) hierarchy_design.__init__(self,name)
self.setup_drc_constants() 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.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) 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.contact_to_gate = drc["contact_to_gate"]
self.well_enclose_active = drc["well_enclosure_active"] self.well_enclose_active = drc["well_enclosure_active"]
self.implant_enclose_active = drc["implant_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): def analytical_power(self, proc, vdd, temp, load):
""" Get total power of a module """ """ 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""" """Adds an instance of a mod to this module"""
self.insts.append(geometry.instance(name, mod, offset, mirror, rotate)) self.insts.append(geometry.instance(name, mod, offset, mirror, rotate))
debug.info(3, "adding instance {}".format(self.insts[-1])) 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] return self.insts[-1]
def get_inst(self, name): 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 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_rw_ports = OPTS.num_rw_ports
self.num_w_ports = OPTS.num_w_ports self.num_w_ports = OPTS.num_w_ports
self.num_r_ports = OPTS.num_r_ports self.num_r_ports = OPTS.num_r_ports
self.total_ports = self.num_rw_ports + self.num_w_ports + self.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! # This is not a pgate because pgates depend on the bitcell height!
design.design.__init__(self, name) 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, 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 # We must always create the bitcell layout because
# some transistor sizes in the other netlists depend on it # some transistor sizes in the other netlists depend on it
self.create_layout() self.create_layout()
def create_netlist(self): def create_netlist(self):
self.add_pins() self.add_pins()
@ -70,7 +75,13 @@ class pbitcell(design.design):
self.route_read_access() self.route_read_access()
self.extend_well() 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() self.DRC_LVS()
def add_pins(self): def add_pins(self):
@ -121,6 +132,11 @@ class pbitcell(design.design):
self.add_pin("vdd") self.add_pin("vdd")
self.add_pin("gnd") self.add_pin("gnd")
if self.replica_bitcell:
self.Q_bar = "vdd"
else:
self.Q_bar = "Q_bar"
def add_modules(self): def add_modules(self):
""" """
@ -229,6 +245,10 @@ class pbitcell(design.design):
# calculation for row line tiling # calculation for row line tiling
self.rail_tile_height = drc["active_to_body_active"] + contact.well.width 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 self.rowline_tile_height = drc["minwidth_metal1"] + contact.m1m2.width
# calculations related to inverter connections # calculations related to inverter connections
@ -292,7 +312,7 @@ class pbitcell(design.design):
# topmost position = height of the inverter + height of vdd # 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.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 # calculations for the cell dimensions
array_vdd_overlap = 0.5*contact.well.width array_vdd_overlap = 0.5*contact.well.width
@ -309,20 +329,20 @@ class pbitcell(design.design):
# create active for nmos # create active for nmos
self.inverter_nmos_left = self.add_inst(name="inverter_nmos_left", self.inverter_nmos_left = self.add_inst(name="inverter_nmos_left",
mod=self.inverter_nmos) 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", self.inverter_nmos_right = self.add_inst(name="inverter_nmos_right",
mod=self.inverter_nmos) 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 # create active for pmos
self.inverter_pmos_left = self.add_inst(name="inverter_pmos_left", self.inverter_pmos_left = self.add_inst(name="inverter_pmos_left",
mod=self.inverter_pmos) 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", self.inverter_pmos_right = self.add_inst(name="inverter_pmos_right",
mod=self.inverter_pmos) 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): 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_left.place([left_inverter_xpos, inverter_pmos_ypos])
self.inverter_pmos_right.place([right_inverter_xpos, inverter_pmos_ypos]) self.inverter_pmos_right.place([right_inverter_xpos, inverter_pmos_ypos])
def route_storage(self): def route_storage(self):
""" """
Routes inputs and outputs of inverters to cross couple them Routes inputs and outputs of inverters to cross couple them
@ -391,13 +412,13 @@ class pbitcell(design.design):
height=contact.well.second_layer_width) height=contact.well.second_layer_width)
vdd_ypos = self.inverter_nmos.active_height + self.inverter_gap + self.inverter_pmos.active_height \ 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_position = vector(self.leftmost_xpos, vdd_ypos)
self.vdd = self.add_layout_pin(text="vdd", self.vdd = self.add_layout_pin(text="vdd",
layer="metal1", layer="metal1",
offset=self.vdd_position, offset=self.vdd_position,
width=self.width, width=self.width,
height=drc["minwidth_metal1"]) height=contact.well.second_layer_width)
# Connect inverters to rails # Connect inverters to rails
# connect inverter nmos to gnd # 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), self.readwrite_nmos_right[k] = self.add_inst(name="readwrite_nmos_right{}".format(k),
mod=self.readwrite_nmos) 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): 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), self.write_nmos_right[k] = self.add_inst(name="write_nmos_right{}".format(k),
mod=self.write_nmos) 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): def place_write_ports(self):
@ -845,7 +866,7 @@ class pbitcell(design.design):
# add read-access transistors # add read-access transistors
self.read_access_nmos_left[k] = self.add_inst(name="read_access_nmos_left{}".format(k), self.read_access_nmos_left[k] = self.add_inst(name="read_access_nmos_left{}".format(k),
mod=self.read_nmos) 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), self.read_access_nmos_right[k] = self.add_inst(name="read_access_nmos_right{}".format(k),
mod=self.read_nmos) mod=self.read_nmos)
@ -1153,7 +1174,7 @@ class pbitcell(design.design):
well_type="p") well_type="p")
# connect nimplants to vdd # 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"), self.add_contact_center(layers=("active", "contact", "metal1"),
offset=offset, offset=offset,
rotate=90, rotate=90,
@ -1215,3 +1236,10 @@ class pbitcell(design.design):
""" Creates a list of br pin names asscociated with write ports""" """ Creates a list of br pin names asscociated with write ports"""
br_pins = self.rw_br_names + self.w_br_names br_pins = self.rw_br_names + self.w_br_names
return br_pins 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 .lib import *
from .delay import * from .delay import *
from .setup_hold import * from .setup_hold import *
from .functional import *
from .simulation import *
debug.info(1,"Initializing characterizer...") debug.info(1,"Initializing characterizer...")

View File

@ -34,12 +34,61 @@ class delay():
self.num_rows = self.sram.num_rows self.num_rows = self.sram.num_rows
self.num_banks = self.sram.num_banks self.num_banks = self.sram.num_banks
self.sp_file = spfile 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 # These are the member variables for a simulation
self.period = 0 self.period = 0
self.set_load_slew(0,0) self.set_load_slew(0,0)
self.set_corner(corner) 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): def set_corner(self,corner):
""" Set the corner values """ """ Set the corner values """
self.corner = corner self.corner = corner
@ -78,15 +127,16 @@ class delay():
# instantiate the sram # instantiate the sram
self.sf.write("\n* Instantiation of the SRAM\n") self.sf.write("\n* Instantiation of the SRAM\n")
self.stim.inst_sram(abits=self.addr_size, self.stim.inst_sram(sram=self.sram,
dbits=self.word_size, port_signal_names=(self.addr_name,self.din_name,self.dout_name),
port_info=(self.total_port_num,self.readwrite_port_num,self.read_ports,self.write_ports), port_info=(self.total_port_num,self.write_ports,self.read_ports),
abits=self.addr_size,
dbits=self.word_size,
sram_name=self.name) sram_name=self.name)
self.sf.write("\n* SRAM output loads\n") self.sf.write("\n* SRAM output loads\n")
for port in self.read_ports: for port in self.read_ports:
for i in range(self.word_size): 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): def write_delay_stimulus(self):
@ -121,14 +171,15 @@ class delay():
self.sf.write("\n* Generation of control signals\n") self.sf.write("\n* Generation of control signals\n")
self.gen_control() self.gen_control()
self.sf.write("\n* Generation of global clock signal\n") self.sf.write("\n* Generation of Port clock signal\n")
self.stim.gen_pulse(sig_name="CLK", for port in range(self.total_port_num):
v1=0, self.stim.gen_pulse(sig_name="CLK{0}".format(port),
v2=self.vdd_voltage, v1=0,
offset=self.period, v2=self.vdd_voltage,
period=self.period, offset=self.period,
t_rise=self.slew, period=self.period,
t_fall=self.slew) t_rise=self.slew,
t_fall=self.slew)
self.write_delay_measures() self.write_delay_measures()
@ -165,22 +216,23 @@ class delay():
self.sf.write("\n* Generation of data and address signals\n") self.sf.write("\n* Generation of data and address signals\n")
for write_port in self.write_ports: for write_port in self.write_ports:
for i in range(self.word_size): 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) v_val=0)
for port in range(self.total_port_num): for port in range(self.total_port_num):
for i in range(self.addr_size): 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) v_val=0)
# generate control signals # generate control signals
self.sf.write("\n* Generation of control signals\n") self.sf.write("\n* Generation of control signals\n")
for port in range(self.total_port_num): for port in range(self.total_port_num):
self.stim.gen_constant(sig_name="CSB{0}".format(port), v_val=self.vdd_voltage) 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.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.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() self.write_power_measures()
@ -189,87 +241,85 @@ class delay():
self.sf.close() 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): def write_delay_measures_read_port(self, port):
""" """
Write the measure statements to quantify the delay and power results for a read port. Write the measure statements to quantify the delay and power results for a read port.
""" """
# add measure statements for delays/slews
# Trigger on the clk of the appropriate cycle for dname in self.delay_meas_names:
trig_name = "clk" meas_values = self.get_delay_meas_values(dname, port)
#Target name should be an input to the function or a member variable. That way, the ports can be singled out for testing self.stim.gen_meas_delay(*meas_values)
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 power # add measure statements for power
t_initial = self.cycle_times[self.measure_cycles["read0_{0}".format(port)]] for pname in self.power_meas_names:
t_final = self.cycle_times[self.measure_cycles["read0_{0}".format(port)]+1] if "read" not in pname:
self.stim.gen_meas_power(meas_name="READ0_POWER{0}".format(port), continue
t_initial=t_initial, #Different naming schemes are used for the measure cycle dict and measurement names.
t_final=t_final) #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_initial = self.cycle_times[self.measure_cycles["read1_{0}".format(port)]]
t_final = self.cycle_times[self.measure_cycles["read1_{0}".format(port)]+1] 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), elif '0' in pname:
t_initial=t_initial, t_initial = self.cycle_times[self.measure_cycles["read0_{0}".format(port)]]
t_final=t_final) 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): def write_delay_measures_write_port(self, port):
""" """
Write the measure statements to quantify the power results for a write port. Write the measure statements to quantify the power results for a write port.
""" """
# add measure statements for power # add measure statements for power
t_initial = self.cycle_times[self.measure_cycles["write0_{0}".format(port)]] for pname in self.power_meas_names:
t_final = self.cycle_times[self.measure_cycles["write0_{0}".format(port)]+1] if "write" not in pname:
self.stim.gen_meas_power(meas_name="WRITE0_POWER{0}".format(port), continue
t_initial=t_initial, t_initial = self.cycle_times[self.measure_cycles["write0_{0}".format(port)]]
t_final=t_final) 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_initial = self.cycle_times[self.measure_cycles["write1_{0}".format(port)]]
t_final = self.cycle_times[self.measure_cycles["write1_{0}".format(port)]+1] 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, self.stim.gen_meas_power(meas_name="{0}{1}".format(pname, port),
t_final=t_final) t_initial=t_initial,
t_final=t_final)
def write_delay_measures(self): def write_delay_measures(self):
""" """
@ -311,8 +361,7 @@ class delay():
starting point. starting point.
""" """
debug.check(port in self.read_ports, "Characterizer requires a read port to determine a period.") 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(tech.spice["feasible_period"])
#feasible_period = float(2.5)#What happens if feasible starting point is wrong? #feasible_period = float(2.5)#What happens if feasible starting point is wrong?
time_out = 9 time_out = 9
@ -334,38 +383,34 @@ class delay():
if not success: if not success:
feasible_period = 2 * feasible_period feasible_period = 2 * feasible_period
break continue
feasible_delay_lh = results["delay_lh{0}".format(port)]
feasible_delay_hl = results["delay_hl{0}".format(port)] #Positions of measurements currently hardcoded. First 2 are delays, next 2 are slews
feasible_slew_lh = results["slew_lh{0}".format(port)] feasible_delays = [results[port][mname] for mname in self.delay_meas_names if "delay" in mname]
feasible_slew_hl = results["slew_hl{0}".format(port)] 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)
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_slews)
slew_str = "slew {0:.4f}ns/{1:.4f}ns".format(feasible_slew_lh, feasible_slew_hl)
debug.info(2, "feasible_period passed for Port {3}: {0}ns {1} {2} ".format(feasible_period, debug.info(2, "feasible_period passed for Port {3}: {0}ns {1} {2} ".format(feasible_period,
delay_str, delay_str,
slew_str, slew_str,
port)) port))
#Add feasible delays of port to dict
#feasible_delays_lh[port] = feasible_delay_lh
#feasible_delays_hl[port] = feasible_delay_hl
if success: 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 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): def find_feasible_period(self):
""" """
Loops through all read ports determining the feasible period and collecting Loops through all read ports determining the feasible period and collecting
delay information from each port. delay information from each port.
""" """
feasible_delays_lh = {} feasible_delays = [{} for i in range(self.total_port_num)]
feasible_delays_hl = {}
self.period = float(tech.spice["feasible_period"]) self.period = float(tech.spice["feasible_period"])
#Get initial feasible period from first port #Get initial feasible delays from first port
(feasible_delays_lh[0], feasible_delays_hl[0]) = self.find_feasible_period_one_port(self.read_ports[0]) feasible_delays[self.read_ports[0]] = self.find_feasible_period_one_port(self.read_ports[0])
previous_period = self.period previous_period = self.period
@ -374,23 +419,27 @@ class delay():
i = 1 i = 1
while i < len(self.read_ports): while i < len(self.read_ports):
port = self.read_ports[i] 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 #Function sets the period. Restart the entire process if period changes to collect accurate delays
if self.period > previous_period: if self.period > previous_period:
i = 0 i = 0
else: else:
i+=1 i+=1
previous_period = self.period 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): def parse_values(self, values_names, port, mult = 1.0):
"""Parse multiple values in the timing output file. Optional multiplier.""" """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 = [] values = []
all_values_floats = True all_values_floats = True
for vname in values_names: for vname in values_names:
#ngspice converts all measure characters to lowercase, not tested on other sims #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 #Check if any of the values fail to parse
if type(value)!=float: if type(value)!=float:
all_values_floats = False all_values_floats = False
@ -409,7 +458,10 @@ class delay():
works on the trimmed netlist by default, so powers do not works on the trimmed netlist by default, so powers do not
include leakage of all cells. 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 # Checking from not data_value to data_value
self.write_delay_stimulus() self.write_delay_stimulus()
@ -418,29 +470,30 @@ class delay():
#Loop through all targeted ports and collect delays and powers. #Loop through all targeted ports and collect delays and powers.
#Too much duplicate code here. Try reducing #Too much duplicate code here. Try reducing
for port in self.targ_read_ports: for port in self.targ_read_ports:
delay_names = ["delay_hl{0}".format(port), "delay_lh{0}".format(port), debug.info(2, "Check delay values for port {}".format(port))
"slew_hl{0}".format(port), "slew_lh{0}".format(port)] delay_names = ["{0}{1}".format(mname,port) for mname in self.delay_meas_names]
delays = self.parse_values(delay_names, 1e9) # scale delays to ns delay_names = [mname for mname in self.delay_meas_names]
if not self.check_valid_delays((delays[delay_names[0]],delays[delay_names[1]],delays[delay_names[2]],delays[delay_names[3]])): delays = self.parse_values(delay_names, port, 1e9) # scale delays to ns
if not self.check_valid_delays(tuple(delays.values())):
return (False,{}) return (False,{})
result.update(delays) result[port].update(delays)
power_names = ["read0_power{0}".format(port), "read1_power{0}".format(port)] power_names = [mname for mname in self.power_meas_names if 'read' in mname]
powers = self.parse_values(power_names, 1e3) # scale power to mw powers = self.parse_values(power_names, port, 1e3) # scale power to mw
#Check that power parsing worked. #Check that power parsing worked.
for name, power in powers.items(): for name, power in powers.items():
if type(power)!=float: if type(power)!=float:
debug.error("Failed to Parse Power Values:\n\t\t{0}".format(powers),1) #Printing the entire dict looks bad. 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: for port in self.targ_write_ports:
power_names = ["write0_power{0}".format(port), "write1_power{0}".format(port)] power_names = [mname for mname in self.power_meas_names if 'write' in mname]
powers = self.parse_values(power_names, 1e3) # scale power to mw powers = self.parse_values(power_names, port, 1e3) # scale power to mw
#Check that power parsing worked. #Check that power parsing worked.
for name, power in powers.items(): for name, power in powers.items():
if type(power)!=float: if type(power)!=float:
debug.error("Failed to Parse Power Values:\n\t\t{0}".format(powers),1) #Printing the entire dict looks bad. 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 # The delay is from the negative edge for our SRAM
return (True,result) return (True,result)
@ -499,11 +552,11 @@ class delay():
return True 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 feasible_period = ub_period = self.period
lb_period = 0.0 lb_period = 0.0
target_period = 0.5 * (ub_period + lb_period) 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. #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 testing purposes, only checks read ports.
for port in self.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. #The min period of one port becomes the new lower bound. Reset the upper_bound.
lb_period = target_period lb_period = target_period
ub_period = feasible_period ub_period = feasible_period
@ -521,10 +574,10 @@ class delay():
self.targ_write_ports = [] self.targ_write_ports = []
return target_period 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 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 #previous_period = ub_period = self.period
@ -546,24 +599,20 @@ class delay():
lb_period, lb_period,
port)) port))
if self.try_period(feasible_delays_lh, feasible_delays_hl): if self.try_period(feasible_delays):
ub_period = target_period ub_period = target_period
else: else:
lb_period = target_period lb_period = target_period
if relative_compare(ub_period, lb_period, error_tolerance=0.05): 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 # ub_period is always feasible.
# and reset the upperbound
return ub_period return ub_period
#target_period = lb_period = ub_period
#ub_period = previous_period
#break
#Update target #Update target
target_period = 0.5 * (ub_period + lb_period) 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 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. works. If it does and the delay is within 5% still, it returns True.
@ -574,27 +623,20 @@ class delay():
return False return False
#Check the values of target readwrite and read ports. Write ports do not produce delays in this current version #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: for port in self.targ_read_ports:
delay_hl = results["delay_hl{0}".format(port)] delay_port_names = [mname for mname in self.delay_meas_names if "delay" in mname]
delay_lh = results["delay_lh{0}".format(port)] for dname in delay_port_names:
slew_hl = results["slew_hl{0}".format(port)] if not relative_compare(results[port][dname],feasible_delays[port][dname],error_tolerance=0.05):
slew_lh = results["slew_lh{0}".format(port)] debug.info(2,"Delay too big {0} vs {1}".format(results[port][dname],feasible_delays[port][dname]))
return False
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
#key=raw_input("press return to continue") #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, #Dynamic way to build string. A bit messy though.
delay_hl, delay_str = ', '.join("{0}={1}ns".format(mname, results[port][mname]) for mname in self.delay_meas_names)
delay_lh, debug.info(2,"Successful period {0}, Port {2}, {1}".format(self.period,
slew_hl, delay_str,
slew_lh, port))
port))
return True return True
def set_probe(self,probe_address, probe_data): 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. 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.set_probe(probe_address, probe_data)
self.create_port_names()
self.create_char_data_dict()
self.load=max(loads) self.load=max(loads)
self.slew=max(slews) self.slew=max(slews)
# This is for debugging a full simulation # This is for debugging a full simulation
@ -652,7 +693,7 @@ class delay():
# sys.exit(1) # sys.exit(1)
#For debugging, skips characterization and returns dummy values. #For debugging, skips characterization and returns dummy values.
# char_data = self.char_data # char_data = self.get_empty_measure_data_dict()
# i = 1.0 # i = 1.0
# for slew in slews: # for slew in slews:
# for load in loads: # for load in loads:
@ -664,34 +705,29 @@ class delay():
# return char_data # return char_data
# 1) Find a feasible period and it's corresponding delays using the trimmed array. # 1) Find a feasible period and it's corresponding delays using the trimmed array.
(feasible_delays_lh, feasible_delays_hl) = self.find_feasible_period() feasible_delays = 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")
# 2) Finds the minimum period without degrading the delays by X% # 2) Finds the minimum period without degrading the delays by X%
self.set_load_slew(max(loads),max(slews)) 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.check(type(min_period)==float,"Couldn't find minimum period.")
debug.info(1, "Min Period Found: {0}ns".format(min_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. # 3) Find the leakage power of the trimmmed and UNtrimmed arrays.
(full_array_leakage, trim_array_leakage)=self.run_power_simulation() (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 leakage_offset = full_array_leakage - trim_array_leakage
# 4) At the minimum period, measure the delay, slew and power for all slew/load pairs. # 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) self.period = min_period
char_port_data = self.simulate_loads_and_slews(slews, loads, leakage_offset)
return self.char_data
return (char_sram_data, char_port_data)
def simulate_loads_and_slews(self, slews, loads, leakage_offset): def simulate_loads_and_slews(self, slews, loads, leakage_offset):
"""Simulate all specified output loads and input slews pairs""" """Simulate all specified output loads and input slews pairs of all ports"""
#Set the target simulation ports to all available ports. This make sims slower but failed sims exit anyways. 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_read_ports = self.read_ports
self.targ_write_ports = self.write_ports self.targ_write_ports = self.write_ports
for slew in slews: for slew in slews:
@ -700,13 +736,17 @@ class delay():
# Find the delay, dynamic power, and leakage power of the trimmed array. # Find the delay, dynamic power, and leakage power of the trimmed array.
(success, delay_results) = self.run_delay_simulation() (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)) 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(): debug.info(1, "Simulation Passed: Port {0} slew={1} load={2}".format("All", self.slew,self.load))
if "power" in k: #The results has a dict for every port but dicts can be empty (e.g. ports were not targeted).
# Subtract partial array leakage and add full array leakage for the power measures for port in range(self.total_port_num):
self.char_data[k].append(v + leakage_offset) for mname,value in delay_results[port].items():
else: if "power" in mname:
self.char_data[k].append(v) # 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): def add_data(self, data, port):
""" Add the array of data values """ """ Add the array of data values """
debug.check(len(data)==self.word_size, "Invalid data word size.") debug.check(len(data)==self.word_size, "Invalid data word size.")
@ -720,7 +760,7 @@ class delay():
else: else:
debug.error("Non-binary data string",1) debug.error("Non-binary data string",1)
index += 1 index += 1
def add_address(self, address, port): def add_address(self, address, port):
""" Add the array of address values """ """ Add the array of address values """
debug.check(len(address)==self.addr_size, "Invalid address size.") 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): def add_noop_all_ports(self, comment, address, data):
""" Add the control values for a noop to all ports. """ """ 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.add_comment("All", comment)
self.t_current,
comment))
self.cycle_times.append(self.t_current) self.cycle_times.append(self.t_current)
self.t_current += self.period self.t_current += self.period
@ -757,10 +795,7 @@ class delay():
def add_read(self, comment, address, data, port): def add_read(self, comment, address, data, port):
""" Add the control values for a read cycle. """ """ Add the control values for a read cycle. """
debug.check(port in self.read_ports, "Cannot add read cycle to a write port.") 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.add_comment(port, comment)
self.t_current,
comment,
port))
self.cycle_times.append(self.t_current) self.cycle_times.append(self.t_current)
self.t_current += self.period self.t_current += self.period
self.add_control_one_port(port, "read") self.add_control_one_port(port, "read")
@ -780,10 +815,7 @@ class delay():
def add_write(self, comment, address, data, port): def add_write(self, comment, address, data, port):
""" Add the control values for a write cycle. """ """ Add the control values for a write cycle. """
debug.check(port in self.write_ports, "Cannot add read cycle to a read port.") 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.add_comment(port, comment)
self.t_current,
comment,
port))
self.cycle_times.append(self.t_current) self.cycle_times.append(self.t_current)
self.t_current += self.period self.t_current += self.period
@ -814,9 +846,19 @@ class delay():
#Append the values depending on the type of port #Append the values depending on the type of port
self.csb_values[port].append(csb_val) 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 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) 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): 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) """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""" 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 = {} self.measure_cycles = {}
# Control signals for ports. These are not the final signals and will likely be changed later. # 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 #web is the enable for write ports. Dicts used for simplicity as ports are not necessarily incremental.
self.web_values = [[] for i in range(self.readwrite_port_num)] self.web_values = {port:[] for port in self.write_ports}
#csb represents a basic "enable" signal that all ports have. #csb acts as an enable for the read ports.
self.csb_values = [[] for i in range(self.total_port_num)] 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. # Address and data values for each address/data bit. A 3d list of size #ports x bits x cycles.
self.data_values=[[[] for i in range(self.addr_size)]]*len(self.write_ports) self.data_values=[[[] for bit in range(self.word_size)] for port in range(len(self.write_ports))]
self.addr_values=[[[] for i in range(self.addr_size)]]*self.total_port_num 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. #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) 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,"Dynamic Power: {0} mW".format(power.dynamic))
debug.info(1,"Leakage Power: {0} mW".format(power.leakage)) debug.info(1,"Leakage Power: {0} mW".format(power.leakage))
data = {"min_period": 0, sram_data = { "min_period": 0,
"delay_lh0": delay_lh, "leakage_power": power.leakage}
"delay_hl0": delay_hl, port_data = [{"delay_lh": delay_lh,
"slew_lh0": slew_lh, "delay_hl": delay_hl,
"slew_hl0": slew_hl, "slew_lh": slew_lh,
"read0_power0": power.dynamic, "slew_hl": slew_hl,
"read1_power0": power.dynamic, "read0_power": power.dynamic,
"write0_power0": power.dynamic, "read1_power": power.dynamic,
"write1_power0": power.dynamic, "write0_power": power.dynamic,
"leakage_power": power.leakage "write1_power": power.dynamic,
} }]
return data return (sram_data,port_data)
def gen_data(self): def gen_data(self):
""" Generates the PWL data inputs for a simulation timing test. """ """ Generates the PWL data inputs for a simulation timing test. """
for write_port in self.write_ports: for write_port in self.write_ports:
for i in range(self.word_size): 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) 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): def gen_addr(self):
@ -996,46 +1038,20 @@ class delay():
""" """
for port in range(self.total_port_num): for port in range(self.total_port_num):
for i in range(self.addr_size): 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) self.stim.gen_pwl(sig_name, self.cycle_times, self.addr_values[port][i], self.period, self.slew, 0.05)
def gen_control(self): def gen_control(self):
""" Generates the control signals """ """ Generates the control signals """
for port in range(self.total_port_num): 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) 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 get_empty_measure_data_dict(self):
def create_port_names(self): """Make a dict of lists for each type of delay and power measurement to append results to"""
"""Generates the port names to be used in characterization and sets default simulation target ports""" measure_names = self.delay_meas_names + self.power_meas_names
self.write_ports = [] #Create list of dicts. List lengths is # of ports. Each dict maps the measurement names to lists.
self.read_ports = [] measure_data = [{mname:[] for mname in measure_names} for i in range(self.total_port_num)]
self.total_port_num = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports return measure_data
#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)]=[]

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.""" """ lib file generation."""
def __init__(self, out_dir, sram, sp_file, use_model=OPTS.analytical_delay): 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.out_dir = out_dir
self.sram = sram self.sram = sram
@ -161,7 +157,7 @@ class lib:
# Leakage is included in dynamic when macro is enabled # Leakage is included in dynamic when macro is enabled
self.lib.write(" leakage_power () {\n") self.lib.write(" leakage_power () {\n")
self.lib.write(" when : \"{0}\";\n".format(control_str)) 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(" }\n")
self.lib.write(" cell_leakage_power : {};\n".format(0)) 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(" related_pin : \"clk\"; \n")
self.lib.write(" timing_type : rising_edge; \n") self.lib.write(" timing_type : rising_edge; \n")
self.lib.write(" cell_rise(CELL_TABLE) {\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(" }\n") # rise delay
self.lib.write(" cell_fall(CELL_TABLE) {\n") 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(" }\n") # fall delay
self.lib.write(" rise_transition(CELL_TABLE) {\n") 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(" }\n") # rise trans
self.lib.write(" fall_transition(CELL_TABLE) {\n") 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") # fall trans
self.lib.write(" }\n") # timing self.lib.write(" }\n") # timing
self.lib.write(" }\n") # pin self.lib.write(" }\n") # pin
@ -428,8 +424,8 @@ class lib:
for port in range(self.total_port_num): for port in range(self.total_port_num):
self.add_clk_control_power(port) self.add_clk_control_power(port)
min_pulse_width = round_time(self.char_results["min_period"])/2.0 min_pulse_width = round_time(self.char_sram_results["min_period"])/2.0
min_period = round_time(self.char_results["min_period"]) min_period = round_time(self.char_sram_results["min_period"])
self.lib.write(" timing(){ \n") self.lib.write(" timing(){ \n")
self.lib.write(" timing_type :\"min_pulse_width\"; \n") self.lib.write(" timing_type :\"min_pulse_width\"; \n")
self.lib.write(" related_pin : clk; \n") self.lib.write(" related_pin : clk; \n")
@ -461,7 +457,7 @@ class lib:
if port in self.write_ports: if port in self.write_ports:
if port in self.read_ports: if port in self.read_ports:
web_name = " & !WEb{0}".format(port) 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(" internal_power(){\n")
self.lib.write(" when : \"!CSb{0} & clk{1}\"; \n".format(port, web_name)) self.lib.write(" when : \"!CSb{0} & clk{1}\"; \n".format(port, web_name))
self.lib.write(" rise_power(scalar){\n") self.lib.write(" rise_power(scalar){\n")
@ -475,7 +471,7 @@ class lib:
if port in self.read_ports: if port in self.read_ports:
if port in self.write_ports: if port in self.write_ports:
web_name = " & WEb{0}".format(port) 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(" internal_power(){\n")
self.lib.write(" when : \"!CSb{0} & !clk{1}\"; \n".format(port, web_name)) self.lib.write(" when : \"!CSb{0} & !clk{1}\"; \n".format(port, web_name))
self.lib.write(" rise_power(scalar){\n") self.lib.write(" rise_power(scalar){\n")
@ -502,13 +498,14 @@ class lib:
if not hasattr(self,"d"): if not hasattr(self,"d"):
self.d = delay(self.sram, self.sp_file, self.corner) self.d = delay(self.sram, self.sp_file, self.corner)
if self.use_model: 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: else:
probe_address = "1" * self.sram.addr_size probe_address = "1" * self.sram.addr_size
probe_data = self.sram.word_size - 1 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): 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 """
# 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.process, self.voltage, self.temperature) = corner
self.device_models = tech.spice["fet_models"][self.process] 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. """ """ 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 ") self.sf.write("Xsram ")
for pin in pin_names:
#Un-tuple the port names. This was done to avoid passing them all as arguments. Could be improved still. self.sf.write("{0} ".format(pin))
#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))
self.sf.write("{0}\n".format(sram_name)) 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): def inst_model(self, pins, model_name):
""" Function to instantiate a generic model with a set of pins """ """ Function to instantiate a generic model with a set of pins """
self.sf.write("X{0} ".format(model_name)) self.sf.write("X{0} ".format(model_name))
@ -153,7 +167,7 @@ class stimuli():
to the initial value. to the initial value.
""" """
# the initial value is not a clock time # 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 # shift signal times earlier for setup time
times = np.array(clk_times) - setup*period times = np.array(clk_times) - setup*period
@ -213,6 +227,10 @@ class stimuli():
power_exp, power_exp,
t_initial, t_initial,
t_final)) 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): def write_control(self, end_time):
""" Write the control cards to run and end the simulation """ """ Write the control cards to run and end the simulation """
@ -255,12 +273,15 @@ class stimuli():
def write_supply(self): def write_supply(self):
""" Writes supply voltage statements """ """ Writes supply voltage statements """
self.sf.write("V{0} {0} 0.0 {1}\n".format(self.vdd_name, self.voltage)) gnd_node_name = "0"
self.sf.write("V{0} {0} 0.0 {1}\n".format(self.gnd_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 # 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} {1} {2}\n".format("test"+self.vdd_name, gnd_node_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.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): def run_sim(self):
""" Run hspice in batch mode and output rawfile to parse. """ """ Run hspice in batch mode and output rawfile to parse. """

View File

@ -1,5 +1,6 @@
import debug import debug
from math import log from math import log
import re
class trim_spice(): 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, "* It should NOT be used for LVS!!")
self.sp_buffer.insert(0, "* WARNING: This is a TRIMMED NETLIST.") 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 # 2. Keep sense amps basd on BL
# FIXME: The bit lines are not indexed the same in sense_amp_array # 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 # 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 # 4. Keep write driver based on DATA
data_name = "data[{}]".format(data_bit) data_regex = r"data\[{}\]".format(data_bit)
self.remove_insts("write_driver_array",[data_name]) self.remove_insts("write_driver_array",[data_regex])
# 5. Keep wordline driver based on WL # 5. Keep wordline driver based on WL
# Need to keep the gater too # 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 # 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. :) # 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 match of the line with a term so you can search for a single
net connection, the instance name, anything.. 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) start_name = ".SUBCKT {}".format(subckt_name)
end_name = ".ENDS {}".format(subckt_name) end_name = ".ENDS {}".format(subckt_name)
@ -120,8 +127,8 @@ class trim_spice():
new_buffer.append(line) new_buffer.append(line)
in_subckt=False in_subckt=False
elif in_subckt: elif in_subckt:
for k in keep_inst_list: for pattern in compiled_patterns:
if k in line: if pattern.search(line) != None:
new_buffer.append(line) new_buffer.append(line)
break break
else: else:

View File

@ -10,10 +10,10 @@ temperatures = [25]
output_path = "temp" output_path = "temp"
output_name = "sram_{0}_{1}_{2}_{3}".format(word_size,num_words,num_banks,tech_name) 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 #Setting for multiport
#bitcell = "pbitcell" # netlist_only = True
# bitcell = "pbitcell"
# These are the configuration parameters # replica_bitcell="replica_pbitcell"
#rw_ports = 2 # num_rw_ports = 1
#r_ports = 2 # num_r_ports = 0
#w_ports = 2 # num_w_ports = 1

View File

@ -2,10 +2,18 @@ word_size = 2
num_words = 16 num_words = 16
num_banks = 1 num_banks = 1
tech_name = "scn3me_subm" tech_name = "scn4m_subm"
process_corners = ["TT"] process_corners = ["TT"]
supply_voltages = [ 5.0 ] supply_voltages = [ 5.0 ]
temperatures = [ 25 ] temperatures = [ 25 ]
output_path = "temp" output_path = "temp"
output_name = "sram_{0}_{1}_{2}_{3}".format(word_size,num_words,num_banks,tech_name) 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("|=========" + name.center(60) + "=========|")
print("|=========" + " ".center(60) + "=========|") print("|=========" + " ".center(60) + "=========|")
print("|=========" + "VLSI Design and Automation Lab".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("|=========" + " ".center(60) + "=========|")
print("|=========" + "VLSI Computer Architecture Research Group".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) + "=========|") print("|=========" + " ".center(60) + "=========|")
user_info = "Usage help: openram-user-group@ucsc.edu" user_info = "Usage help: openram-user-group@ucsc.edu"
print("|=========" + user_info.center(60) + "=========|") 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 config didn't set output name, make a reasonable default.
if (OPTS.output_name == ""): 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, ports = ""
OPTS.num_words, if OPTS.num_rw_ports>0:
OPTS.num_banks, ports += "{}rw_".format(OPTS.num_rw_ports)
OPTS.num_rw_ports, if OPTS.num_w_ports>0:
OPTS.num_w_ports, ports += "{}w_".format(OPTS.num_w_ports)
OPTS.num_r_ports, if OPTS.num_r_ports>0:
OPTS.tech_name) 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)) debug.error("{0} is not an integer in config file.".format(OPTS.word_size))
if type(OPTS.num_words)!=int: if type(OPTS.num_words)!=int:
debug.error("{0} is not an integer in config file.".format(OPTS.sram_size)) 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: if not OPTS.tech_name:
debug.error("Tech name must be specified in config file.") 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) design.design.__init__(self, name)
debug.info(2, "create sram of size {0} with {1} words".format(self.word_size,self.num_words)) 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, # 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 # 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.add_modules()
self.create_modules() self.create_modules()
def create_layout(self): def create_layout(self):
self.place_modules() self.place_modules()
self.setup_routing_constraints() self.setup_routing_constraints()
@ -65,19 +62,9 @@ class bank(design.design):
self.bank_center=self.offset_all_coordinates().scale(-1,-1) self.bank_center=self.offset_all_coordinates().scale(-1,-1)
self.DRC_LVS() self.DRC_LVS()
def add_pins(self): 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""" """ Adding pins for Bank module"""
for port in range(self.total_read): for port in range(self.total_read):
for bit in range(self.word_size): 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") self.add_pin("s_en{0}".format(self.read_index[port]), "INPUT")
for port in range(self.total_write): for port in range(self.total_write):
self.add_pin("w_en{0}".format(port), "INPUT") self.add_pin("w_en{0}".format(port), "INPUT")
for pin in ["clk_buf_bar","clk_buf"]: for port in range(self.total_ports):
self.add_pin(pin,"INPUT") 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("vdd","POWER")
self.add_pin("gnd","GROUND") self.add_pin("gnd","GROUND")
def route_layout(self): def route_layout(self):
""" Create routing amoung the modules """ """ Create routing amoung the modules """
self.route_central_bus() self.route_central_bus()
@ -119,6 +108,7 @@ class bank(design.design):
self.route_bank_select() self.route_bank_select()
self.route_vdd_gnd() self.route_vdd_gnd()
def create_modules(self): def create_modules(self):
""" Add modules. The order should not matter! """ """ Add modules. The order should not matter! """
@ -156,10 +146,10 @@ class bank(design.design):
self.place_row_decoder() self.place_row_decoder()
self.place_wordline_driver() self.place_wordline_driver()
self.place_column_decoder() self.place_column_decoder()
self.place_bank_select() self.place_bank_select()
def compute_sizes(self): def compute_sizes(self):
""" Computes the required sizes to create the bank """ """ Computes the required sizes to create the bank """
@ -181,13 +171,25 @@ class bank(design.design):
# Number of control lines in the bus # Number of control lines in the bus
self.num_control_lines = 4 self.num_control_lines = 4
# The order of the control signals on the control bus: # 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. # These will be outputs of the gaters if this is multibank, if not, normal signals.
if self.num_banks > 1: self.control_signals = []
self.control_signals = ["gated_"+str for str in self.input_control_signals] for port in range(self.total_ports):
else: if self.num_banks > 1:
self.control_signals = self.input_control_signals 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) # The central bus is the column address (one hot) and row address (binary)
if self.col_addr_size>0: if self.col_addr_size>0:
self.num_col_addr_lines = 2**self.col_addr_size 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): for port in range(self.total_ports):
self.column_mux_array.append(self.mod_column_mux_array(columns=self.num_cols, self.column_mux_array.append(self.mod_column_mux_array(columns=self.num_cols,
word_size=self.word_size, word_size=self.word_size,
bitcell_bl=self.read_bl_list[port], bitcell_bl=self.total_bl_list[port],
bitcell_br=self.read_br_list[port])) bitcell_br=self.total_br_list[port]))
self.add_mod(self.column_mux_array[port]) self.add_mod(self.column_mux_array[port])
@ -292,6 +294,7 @@ class bank(design.design):
temp.append("gnd") temp.append("gnd")
self.connect_inst(temp) self.connect_inst(temp)
def place_bitcell_array(self): def place_bitcell_array(self):
""" Placing Bitcell Array """ """ Placing Bitcell Array """
self.bitcell_array_inst.place(vector(0,0)) self.bitcell_array_inst.place(vector(0,0))
@ -308,9 +311,10 @@ class bank(design.design):
for i in range(self.num_cols): for i in range(self.num_cols):
temp.append(self.read_bl_list[port]+"[{0}]".format(i)) temp.append(self.read_bl_list[port]+"[{0}]".format(i))
temp.append(self.read_br_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) self.connect_inst(temp)
def place_precharge_array(self): def place_precharge_array(self):
""" Placing Precharge """ """ Placing Precharge """
@ -320,6 +324,7 @@ class bank(design.design):
# The enclosure is for the well and the spacing is to the bitcell wells # The enclosure is for the well and the spacing is to the bitcell wells
y_offset = self.bitcell_array.height + self.m2_gap y_offset = self.bitcell_array.height + self.m2_gap
self.precharge_array_inst[port].place(vector(0,y_offset)) self.precharge_array_inst[port].place(vector(0,y_offset))
def create_column_mux_array(self): def create_column_mux_array(self):
""" Creating Column Mux when words_per_row > 1 . """ """ Creating Column Mux when words_per_row > 1 . """
@ -343,6 +348,7 @@ class bank(design.design):
temp.append("gnd") temp.append("gnd")
self.connect_inst(temp) self.connect_inst(temp)
def place_column_mux_array(self): def place_column_mux_array(self):
""" Placing Column Mux when words_per_row > 1 . """ """ Placing Column Mux when words_per_row > 1 . """
if self.col_addr_size > 0: if self.col_addr_size > 0:
@ -354,6 +360,7 @@ class bank(design.design):
for port in range(self.total_ports): for port in range(self.total_ports):
y_offset = self.column_mux_height y_offset = self.column_mux_height
self.col_mux_array_inst[port].place(vector(0,y_offset).scale(-1,-1)) self.col_mux_array_inst[port].place(vector(0,y_offset).scale(-1,-1))
def create_sense_amp_array(self): def create_sense_amp_array(self):
""" Creating Sense amp """ """ 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_bl_list[port]+"_out[{0}]".format(bit))
temp.append(self.read_br_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) self.connect_inst(temp)
def place_sense_amp_array(self): def place_sense_amp_array(self):
""" Placing Sense amp """ """ Placing Sense amp """
@ -383,6 +391,7 @@ class bank(design.design):
for port in range(self.total_read): for port in range(self.total_read):
y_offset = self.column_mux_height + self.sense_amp_array.height + self.m2_gap 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)) self.sense_amp_array_inst[port].place(vector(0,y_offset).scale(-1,-1))
def create_write_driver_array(self): def create_write_driver_array(self):
""" Creating Write Driver """ """ Creating Write Driver """
@ -405,6 +414,7 @@ class bank(design.design):
temp.extend([self.prefix+"w_en{0}".format(port), "vdd", "gnd"]) temp.extend([self.prefix+"w_en{0}".format(port), "vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
def place_write_driver_array(self): def place_write_driver_array(self):
""" Placing Write Driver """ """ Placing Write Driver """
@ -413,7 +423,6 @@ class bank(design.design):
y_offset = self.sense_amp_array.height + self.column_mux_height \ y_offset = self.sense_amp_array.height + self.column_mux_height \
+ self.m2_gap + self.write_driver_array.height + self.m2_gap + self.write_driver_array.height
self.write_driver_array_inst[port].place(vector(0,y_offset).scale(-1,-1)) self.write_driver_array_inst[port].place(vector(0,y_offset).scale(-1,-1))
def create_row_decoder(self): def create_row_decoder(self):
@ -432,6 +441,7 @@ class bank(design.design):
temp.extend(["vdd", "gnd"]) temp.extend(["vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
def place_row_decoder(self): def place_row_decoder(self):
""" Place the hierarchical row decoder """ """ Place the hierarchical row decoder """
@ -460,11 +470,12 @@ class bank(design.design):
temp.append("dec_out{0}[{1}]".format(port,row)) temp.append("dec_out{0}[{1}]".format(port,row))
for row in range(self.num_rows): for row in range(self.num_rows):
temp.append(self.total_wl_list[port]+"[{0}]".format(row)) 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("vdd")
temp.append("gnd") temp.append("gnd")
self.connect_inst(temp) self.connect_inst(temp)
def place_wordline_driver(self): def place_wordline_driver(self):
""" Place the Wordline Driver """ """ Place the Wordline Driver """
@ -506,6 +517,7 @@ class bank(design.design):
temp.extend(["vdd", "gnd"]) temp.extend(["vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
def place_column_decoder(self): def place_column_decoder(self):
""" """
Place a 2:4 or 3:8 column address decoder. Place a 2:4 or 3:8 column address decoder.
@ -536,12 +548,13 @@ class bank(design.design):
mod=self.bank_select)) mod=self.bank_select))
temp = [] temp = []
temp.extend(self.input_control_signals) temp.extend(self.input_control_signals[port])
temp.append("bank_sel{}".format(port)) temp.append("bank_sel{}".format(port))
temp.extend(self.control_signals) temp.extend(self.control_signals[port])
temp.extend(["vdd", "gnd"]) temp.extend(["vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
def place_bank_select(self): def place_bank_select(self):
""" Place the bank select logic. """ """ Place the bank select logic. """
@ -552,9 +565,9 @@ class bank(design.design):
for port in range(self.total_ports): for port in range(self.total_ports):
x_off = -(self.row_decoder.width + self.central_bus_width + self.wordline_driver.width) x_off = -(self.row_decoder.width + self.central_bus_width + self.wordline_driver.width)
if self.col_addr_size > 0: 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: 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"]) y_off -= (self.bank_select.height + drc["well_to_well"])
self.bank_select_pos = vector(x_off,y_off) self.bank_select_pos = vector(x_off,y_off)
self.bank_select_inst[port].place(self.bank_select_pos) self.bank_select_inst[port].place(self.bank_select_pos)
@ -565,18 +578,30 @@ class bank(design.design):
for inst in self.insts: for inst in self.insts:
self.copy_power_pins(inst,"vdd") self.copy_power_pins(inst,"vdd")
self.copy_power_pins(inst,"gnd") self.copy_power_pins(inst,"gnd")
def route_bank_select(self): def route_bank_select(self):
""" Route the bank select logic. """ """ Route the bank select logic. """
for port in range(self.total_ports): for port in range(self.total_ports):
for input_name in self.input_control_signals+["bank_sel"]: if self.port_id[port] == "rw":
self.copy_layout_pin(self.bank_select_inst[port], input_name) 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"]
for gated_name in self.control_signals: 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 # Connect the inverter output to the central bus
out_pos = self.bank_select_inst[port].get_pin(gated_name).rc() out_pos = self.bank_select_inst[port].get_pin(gated_bank_sel_signals[signal]).rc()
bus_pos = vector(self.bus_xoffset[gated_name].x, out_pos.y) 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_path("metal3",[out_pos, bus_pos])
self.add_via_center(layers=("metal2", "via2", "metal3"), self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=bus_pos, offset=bus_pos,
@ -594,7 +619,8 @@ class bank(design.design):
After the modules are instantiated, find the dimensions for the After the modules are instantiated, find the dimensions for the
control bus, power ring, etc. control bus, power ring, etc.
""" """
# FIXME: calculate for multiport
#The minimum point is either the bottom of the address flops, #The minimum point is either the bottom of the address flops,
#the column decoder (if there is one). #the column decoder (if there is one).
write_driver_min_y_offset = self.write_driver_array_inst[0].by() - 3*self.m2_pitch 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.height = ur.y - ll.y
self.width = ur.x - ll.x self.width = ur.x - ll.x
def route_central_bus(self): def route_central_bus(self):
""" Create the address, supply, and control signal central bus lines. """ """ Create the address, supply, and control signal central bus lines. """
@ -637,16 +662,16 @@ class bank(design.design):
# and control lines. # and control lines.
# The bank is at (0,0), so this is to the left of the y-axis. # 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 # 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) for port in range(self.total_ports):
control_bus_length = self.max_y_offset - self.min_y_offset control_bus_offset = vector(-self.m2_pitch * self.num_control_lines - self.m2_width, self.min_y_offset)
self.bus_xoffset = self.create_bus(layer="metal2", control_bus_length = self.max_y_offset - self.min_y_offset
pitch=self.m2_pitch, self.bus_xoffset = self.create_bus(layer="metal2",
offset=control_bus_offset, pitch=self.m2_pitch,
names=self.control_signals, offset=control_bus_offset,
length=control_bus_length, names=self.control_signals[port],
vertical=True, length=control_bus_length,
make_pins=(self.num_banks==1)) vertical=True,
make_pins=(self.num_banks==1))
def route_precharge_to_bitcell_array(self): def route_precharge_to_bitcell_array(self):
@ -687,7 +712,8 @@ class bank(design.design):
vector(bitcell_bl.x,yoffset), bitcell_bl]) vector(bitcell_bl.x,yoffset), bitcell_bl])
self.add_path("metal2",[col_mux_br, vector(col_mux_br.x,yoffset), self.add_path("metal2",[col_mux_br, vector(col_mux_br.x,yoffset),
vector(bitcell_br.x,yoffset), bitcell_br]) vector(bitcell_br.x,yoffset), bitcell_br])
def route_sense_amp_to_col_mux_or_bitcell_array(self): 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 """ """ 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]) vector(connect_bl.x,yoffset), connect_bl])
self.add_path("metal2",[sense_amp_br, vector(sense_amp_br.x,yoffset), self.add_path("metal2",[sense_amp_br, vector(sense_amp_br.x,yoffset),
vector(connect_br.x,yoffset), connect_br]) vector(connect_br.x,yoffset), connect_br])
def route_sense_amp_out(self): def route_sense_amp_out(self):
""" Add pins for the sense amp output """ """ Add pins for the sense amp output """
# FIXME: Update for multiport # FIXME: Update for multiport
for bit in range(self.word_size): for port in range(self.total_read):
data_pin = self.sense_amp_array_inst[0].get_pin("data[{}]".format(bit)) for bit in range(self.word_size):
self.add_layout_pin_rect_center(text="dout0[{}]".format(bit), data_pin = self.sense_amp_array_inst[port].get_pin("data[{}]".format(bit))
layer=data_pin.layer, self.add_layout_pin_rect_center(text="dout{0}[{1}]".format(self.read_index[port],bit),
offset=data_pin.center(), layer=data_pin.layer,
height=data_pin.height(), offset=data_pin.center(),
width=data_pin.width()) height=data_pin.height(),
width=data_pin.width())
def route_row_decoder(self): def route_row_decoder(self):
""" Routes the row decoder inputs and supplies """ """ Routes the row decoder inputs and supplies """
# FIXME: Update for multiport # FIXME: Update for multiport
# Create inputs for the row address lines # Create inputs for the row address lines
for row in range(self.row_addr_size): for port in range(self.total_ports):
addr_idx = row + self.col_addr_size for row in range(self.row_addr_size):
decoder_name = "addr[{}]".format(row) addr_idx = row + self.col_addr_size
addr_name = "addr0[{}]".format(addr_idx) decoder_name = "addr[{}]".format(row)
self.copy_layout_pin(self.row_decoder_inst[0], decoder_name, addr_name) 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): def route_write_driver(self):
""" Connecting write driver """ """ Connecting write driver """
for port in range(self.total_ports):
for row in range(self.word_size): for row in range(self.word_size):
data_name = "data[{}]".format(row) data_name = "data[{}]".format(row)
din_name = "din0[{}]".format(row) din_name = "din{0}[{1}]".format(port,row)
self.copy_layout_pin(self.write_driver_array_inst[0], data_name, din_name) self.copy_layout_pin(self.write_driver_array_inst[port], data_name, din_name)
def route_wordline_driver(self): def route_wordline_driver(self):
""" Connecting Wordline driver output to Bitcell WL connection """ """ 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 mid guarantees we exit the input cell to the right.
# The pre/post is to access the pin from "outside" the cell to avoid DRCs driver_wl_pos = self.wordline_driver_inst[port].get_pin("wl[{}]".format(row)).rc()
decoder_out_pos = self.row_decoder_inst[0].get_pin("decode[{}]".format(row)).rc() bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.total_wl_list[port]+"[{}]".format(row)).lc()
driver_in_pos = self.wordline_driver_inst[0].get_pin("in[{}]".format(row)).lc() mid1 = driver_wl_pos.scale(0.5,1)+bitcell_wl_pos.scale(0.5,0)
mid1 = decoder_out_pos.scale(0.5,1)+driver_in_pos.scale(0.5,0) mid2 = driver_wl_pos.scale(0.5,0)+bitcell_wl_pos.scale(0.5,1)
mid2 = decoder_out_pos.scale(0.5,0)+driver_in_pos.scale(0.5,1) self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos])
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])
def route_column_address_lines(self): def route_column_address_lines(self):
@ -773,49 +799,45 @@ class bank(design.design):
if not self.col_addr_size>0: if not self.col_addr_size>0:
return return
for port in range(self.total_ports):
if self.col_addr_size == 1:
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)
# 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. for i in range(self.col_addr_size):
# When above the top select line it will offset "inward" again to prevent conflicts. decoder_name = "in[{}]".format(i)
# This could be done on a single layer, but we follow preferred direction rules for later routing. addr_name = "addr{0}[{1}]".format(port,i)
top_y_offset = self.col_mux_array_inst[0].get_pin("sel[{}]".format(self.num_col_addr_lines-1)).cy() self.copy_layout_pin(self.col_decoder_inst[port], decoder_name, addr_name)
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()
# To get to the edge of the decoder and one track out # This will do a quick "river route" on two layers.
delta_offset = self.col_decoder_inst[0].rx() - decode_out_pos.x + self.m2_pitch # When above the top select line it will offset "inward" again to prevent conflicts.
if decode_out_pos.y > top_y_offset: # This could be done on a single layer, but we follow preferred direction rules for later routing.
mid1_pos = vector(decode_out_pos.x + delta_offset + i*self.m2_pitch,decode_out_pos.y) top_y_offset = self.col_mux_array_inst[port].get_pin("sel[{}]".format(self.num_col_addr_lines-1)).cy()
else: for (decode_name,i) in zip(decode_names,range(self.num_col_addr_lines)):
mid1_pos = vector(decode_out_pos.x + delta_offset + (self.num_col_addr_lines-i)*self.m2_pitch,decode_out_pos.y) mux_name = "sel[{}]".format(i)
mid2_pos = vector(mid1_pos.x,mux_addr_pos.y) mux_addr_pos = self.col_mux_array_inst[port].get_pin(mux_name).lc()
#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]) 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): def add_lvs_correspondence_points(self):
@ -869,30 +891,39 @@ class bank(design.design):
# From control signal to the module pin # From control signal to the module pin
# Connection from the central bus to the main control block crosses # Connection from the central bus to the main control block crosses
# pre-decoder and this connection is in metal3 # pre-decoder and this connection is in metal3
connection = [] write_inst = 0
connection.append((self.prefix+"clk_buf_bar", self.precharge_array_inst[0].get_pin("en").lc())) read_inst = 0
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)
# 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): 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 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) design.design.__init__(self, name)
self.port = port
self.create_netlist() self.create_netlist()
if not OPTS.netlist_only: if not OPTS.netlist_only:
self.create_layout() self.create_layout()
@ -38,10 +40,17 @@ class bank_select(design.design):
def add_pins(self): def add_pins(self):
# Number of control lines in the bus # 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: # The order of the control signals on the control bus:
# FIXME: Update for multiport (these names are not right) # 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 # These will be outputs of the gaters if this is multibank
self.control_signals = ["gated_"+str for str in self.input_control_signals] 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): def add_modules(self):
""" Create modules for later instantiation """ """ 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 # 1x Inverter
self.inv = pinv() self.inv_sel = pinv(height=height)
self.add_mod(self.inv) self.add_mod(self.inv_sel)
# 4x Inverter # 4x Inverter
self.inv4x = pinv(4) self.inv = self.inv4x = pinv(4)
self.add_mod(self.inv4x) self.add_mod(self.inv4x)
self.nor2 = pnor2() self.nor2 = pnor2(height=height)
self.add_mod(self.nor2) self.add_mod(self.nor2)
self.inv4x_nor = pinv(size=4, height=height)
self.add_mod(self.inv4x_nor)
self.nand2 = pnand2() self.nand2 = pnand2()
self.add_mod(self.nand2) self.add_mod(self.nand2)
@ -83,7 +102,7 @@ class bank_select(design.design):
def create_modules(self): def create_modules(self):
self.bank_sel_inv=self.add_inst(name="bank_sel_inv", 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.connect_inst(["bank_sel", "bank_sel_bar", "vdd", "gnd"])
self.logic_inst = [] self.logic_inst = []
@ -107,6 +126,14 @@ class bank_select(design.design):
"vdd", "vdd",
"gnd"]) "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 # the rest are AND (nand2+inv) gates
else: else:
self.logic_inst.append(self.add_inst(name=name_nand, self.logic_inst.append(self.add_inst(name=name_nand,
@ -117,13 +144,13 @@ class bank_select(design.design):
"vdd", "vdd",
"gnd"]) "gnd"])
# They all get inverters on the output # They all get inverters on the output
self.inv_inst.append(self.add_inst(name=name_inv, self.inv_inst.append(self.add_inst(name=name_inv,
mod=self.inv4x)) mod=self.inv4x))
self.connect_inst([gated_name+"_temp_bar", self.connect_inst([gated_name+"_temp_bar",
gated_name, gated_name,
"vdd", "vdd",
"gnd"]) "gnd"])
def place_modules(self): def place_modules(self):
@ -140,7 +167,11 @@ class bank_select(design.design):
input_name = self.input_control_signals[i] 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: if i%2:
y_offset += self.inv.height y_offset += self.inv.height
mirror = "MX" mirror = "MX"

View File

@ -18,12 +18,19 @@ class control_logic(design.design):
Dynamically generated Control logic for the total SRAM circuit. Dynamically generated Control logic for the total SRAM circuit.
""" """
def __init__(self, num_rows): def __init__(self, num_rows, port_type="rw"):
""" Constructor """ """ Constructor """
design.design.__init__(self, "control_logic") name = "control_logic_" + port_type
debug.info(1, "Creating {}".format(self.name)) design.design.__init__(self, name)
debug.info(1, "Creating {}".format(name))
self.num_rows = num_rows 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() self.create_netlist()
if not OPTS.netlist_only: if not OPTS.netlist_only:
@ -41,7 +48,7 @@ class control_logic(design.design):
self.place_modules() self.place_modules()
self.route_all() self.route_all()
self.add_lvs_correspondence_points() #self.add_lvs_correspondence_points()
self.DRC_LVS() self.DRC_LVS()
@ -61,7 +68,7 @@ class control_logic(design.design):
dff = dff_inv() dff = dff_inv()
dff_height = dff.height 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.add_mod(self.ctrl_dff_array)
self.nand2 = pnand2(height=dff_height) self.nand2 = pnand2(height=dff_height)
@ -81,29 +88,50 @@ class control_logic(design.design):
self.inv8 = pinv(size=16, height=dff_height) self.inv8 = pinv(size=16, height=dff_height)
self.add_mod(self.inv8) self.add_mod(self.inv8)
from importlib import reload if (self.port_type == "rw") or (self.port_type == "r"):
c = reload(__import__(OPTS.replica_bitline)) from importlib import reload
replica_bitline = getattr(c, OPTS.replica_bitline) c = reload(__import__(OPTS.replica_bitline))
# FIXME: These should be tuned according to the size! replica_bitline = getattr(c, OPTS.replica_bitline)
delay_stages = 4 # Must be non-inverting # FIXME: These should be tuned according to the size!
delay_fanout = 3 # This can be anything >=2 delay_stages = 4 # Must be non-inverting
bitcell_loads = int(math.ceil(self.num_rows / 5.0)) delay_fanout = 3 # This can be anything >=2
self.replica_bitline = replica_bitline(delay_stages, delay_fanout, bitcell_loads) bitcell_loads = int(math.ceil(self.num_rows / 5.0))
self.add_mod(self.replica_bitline) 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): def setup_signal_busses(self):
""" Setup bus names, determine the size of the busses etc """ """ Setup bus names, determine the size of the busses etc """
# List of input control signals # List of input control signals
self.input_list =["csb","web0"] if self.port_type == "rw":
self.dff_output_list =["cs_bar", "cs", "we_bar", "we"] 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) # 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 # leave space for the bus plus one extra space
self.internal_bus_width = (len(self.internal_bus_list)+1)*self.m2_pitch self.internal_bus_width = (len(self.internal_bus_list)+1)*self.m2_pitch
# Outputs to the bank # 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"] self.supply_list = ["vdd", "gnd"]
@ -118,14 +146,13 @@ class control_logic(design.design):
def create_modules(self): def create_modules(self):
""" Create all the modules """ """ Create all the modules """
self.create_dffs() self.create_dffs()
self.create_clk_row() self.create_clk_row()
self.create_we_row() if (self.port_type == "rw") or (self.port_type == "w"):
# self.create_trien_row() self.create_we_row()
# self.create_trien_bar_row() if (self.port_type == "rw") or (self.port_type == "r"):
self.create_rbl_in_row() self.create_rbl_in_row()
self.create_sen_row() self.create_sen_row()
self.create_rbl() self.create_rbl()
def place_modules(self): def place_modules(self):
@ -134,38 +161,44 @@ class control_logic(design.design):
# and add the vdd/gnd pins # and add the vdd/gnd pins
self.row_end_inst = [] self.row_end_inst = []
# Add the control flops on the left of the bus # Add the control flops on the left of the bus
self.place_dffs() self.place_dffs()
row = 0
# Add the logic on the right of the bus # Add the logic on the right of the bus
self.place_clk_row(row=0) # clk is a double-high cell self.place_clk_row(row=row) # clk is a double-high cell
self.place_we_row(row=2) row += 2
# self.place_trien_row(row=3) if (self.port_type == "rw") or (self.port_type == "w"):
# self.place_trien_bar_row(row=4) self.place_we_row(row=row)
self.place_rbl_in_row(row=3) pre_height = self.w_en_inst.uy()
self.place_sen_row(row=4) control_center_y = self.w_en_inst.by()
self.place_rbl(row=5) 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 # This offset is used for placement of the control logic in the SRAM level.
# the SRAM level. self.control_logic_center = vector(self.ctrl_dff_inst.rx(), control_center_y)
self.control_logic_center = vector(self.ctrl_dff_inst.rx(), self.rbl_inst.by())
# Extra pitch on top and right # 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 # 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): def route_all(self):
""" Routing between modules """ """ Routing between modules """
self.route_dffs() self.route_dffs()
#self.route_trien() if (self.port_type == "rw") or (self.port_type == "w"):
#self.route_trien_bar() self.route_wen()
self.route_rbl_in() if (self.port_type == "rw") or (self.port_type == "r"):
self.route_wen() self.route_rbl_in()
self.route_sen() self.route_sen()
self.route_clk() self.route_clk()
self.route_supply() self.route_supply()
@ -202,7 +235,7 @@ class control_logic(design.design):
def create_rbl_in_row(self): 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) mod=self.nand2)
self.connect_inst(["clk_buf_bar", "cs", "rbl_in_bar", "vdd", "gnd"]) 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 # input: input: pre_s_en_bar, output: s_en
self.s_en_inst=self.add_inst(name="inv_s_en", self.s_en_inst=self.add_inst(name="inv_s_en",
mod=self.inv8) 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): def place_sen_row(self,row):
""" """
@ -262,7 +295,11 @@ class control_logic(design.design):
def route_dffs(self): def route_dffs(self):
""" Route the input inverters """ """ 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) self.connect_vertical_bus(dff_out_map, self.ctrl_dff_inst, self.rail_offsets)
# Connect the clock rail to the other clock rail # Connect the clock rail to the other clock rail
@ -275,7 +312,8 @@ class control_logic(design.design):
rotate=90) rotate=90)
self.copy_layout_pin(self.ctrl_dff_inst, "din[0]", "csb") 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): def create_dffs(self):
@ -302,23 +340,30 @@ class control_logic(design.design):
def create_we_row(self): def create_we_row(self):
# input: WE, CS output: w_en_bar # input: WE, CS output: w_en_bar
self.w_en_bar_inst=self.add_inst(name="nand3_w_en_bar", if self.port_type == "rw":
mod=self.nand3) nand_mod = self.nand3
self.connect_inst(["clk_buf_bar", "cs", "we", "w_en_bar", "vdd", "gnd"]) 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 # input: w_en_bar, output: pre_w_en
self.pre_w_en_inst=self.add_inst(name="inv_pre_w_en", self.pre_w_en_inst = self.add_inst(name="inv_pre_w_en",
mod=self.inv1) mod=self.inv1)
self.connect_inst(["w_en_bar", "pre_w_en", "vdd", "gnd"]) self.connect_inst(["w_en_bar", "pre_w_en", "vdd", "gnd"])
# BUFFER INVERTERS FOR W_EN # BUFFER INVERTERS FOR W_EN
self.pre_w_en_bar_inst=self.add_inst(name="inv_pre_w_en_bar", self.pre_w_en_bar_inst = self.add_inst(name="inv_pre_w_en_bar",
mod=self.inv2) mod=self.inv2)
self.connect_inst(["pre_w_en", "pre_w_en_bar", "vdd", "gnd"]) self.connect_inst(["pre_w_en", "pre_w_en_bar", "vdd", "gnd"])
self.w_en_inst=self.add_inst(name="inv_w_en2", self.w_en_inst = self.add_inst(name="inv_w_en2",
mod=self.inv8) mod=self.inv8)
self.connect_inst(["pre_w_en_bar", "w_en0", "vdd", "gnd"]) self.connect_inst(["pre_w_en_bar", "w_en", "vdd", "gnd"])
def place_we_row(self,row): def place_we_row(self,row):
@ -328,7 +373,10 @@ class control_logic(design.design):
w_en_bar_offset = vector(x_off, y_off) w_en_bar_offset = vector(x_off, y_off)
self.w_en_bar_inst.place(offset=w_en_bar_offset, self.w_en_bar_inst.place(offset=w_en_bar_offset,
mirror=mirror) 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) pre_w_en_offset = vector(x_off, y_off)
self.pre_w_en_inst.place(offset=pre_w_en_offset, self.pre_w_en_inst.place(offset=pre_w_en_offset,
@ -422,7 +470,10 @@ class control_logic(design.design):
def route_wen(self): 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) self.connect_vertical_bus(wen_map, self.w_en_bar_inst, self.rail_offsets)
# Connect the NAND3 output to the inverter # 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_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.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): def route_sen(self):
rbl_out_pos = self.rbl_inst.get_pin("out").bc() 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.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): def route_clk(self):
""" Route the clk and clk_buf_bar signal internally """ """ 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_power_pin("gnd", pin_loc)
self.add_path("metal1", [row_loc, pin_loc]) self.add_path("metal1", [row_loc, pin_loc])
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,"gnd")
self.copy_layout_pin(self.rbl_inst,"vdd") 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,"gnd")
self.copy_layout_pin(self.ctrl_dff_inst,"vdd") 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. Usually, this will be constant, but it could have varied fanout.
""" """
unique_id = 1
def __init__(self, fanout_list, name="delay_chain"): def __init__(self, fanout_list, name="delay_chain"):
"""init function""" """init function"""
name = name+"_{}".format(delay_chain.unique_id)
delay_chain.unique_id += 1
design.design.__init__(self, name) design.design.__init__(self, name)
# Two fanouts are needed so that we can route the vdd/gnd connections # 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 """ """ Add the modules for later usage """
from importlib import reload from importlib import reload
g = reload(__import__(OPTS.delay_chain)) #g = reload(__import__(OPTS.delay_chain))
self.mod_delay_chain = getattr(g, OPTS.delay_chain) #self.mod_delay_chain = getattr(g, OPTS.delay_chain)
g = reload(__import__(OPTS.replica_bitcell)) g = reload(__import__(OPTS.replica_bitcell))
self.mod_replica_bitcell = getattr(g, 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) self.add_mod(self.rbl)
# FIXME: The FO and depth of this should be tuned # 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.add_mod(self.delay_chain)
self.inv = pinv() self.inv = pinv()
@ -110,12 +111,12 @@ class replica_bitline(design.design):
# This is the threshold detect inverter on the output of the RBL # This is the threshold detect inverter on the output of the RBL
self.rbl_inv_inst=self.add_inst(name="rbl_inv", self.rbl_inv_inst=self.add_inst(name="rbl_inv",
mod=self.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", self.tx_inst=self.add_inst(name="rbl_access_tx",
mod=self.access_tx) mod=self.access_tx)
# D, G, S, B # 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 # add the well and poly contact
self.dc_inst=self.add_inst(name="delay_chain", 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", self.rbc_inst=self.add_inst(name="bitcell",
mod=self.replica_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", self.rbl_inst=self.add_inst(name="load",
mod=self.rbl) mod=self.rbl)
total_ports = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports
temp = [] temp = []
temp.append("bl[0]") for port in range(self.total_ports):
temp.append("br[0]") temp.append("bl{}[0]".format(port))
for port in range(total_ports - 1): temp.append("br{}[0]".format(port))
temp.append("gnd")
temp.append("gnd")
for wl in range(self.bitcell_loads): 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("gnd")
temp.append("vdd") temp.append("vdd")
temp.append("gnd") temp.append("gnd")
self.connect_inst(temp) self.connect_inst(temp)
self.wl_list = self.rbl.cell.list_all_wl_names() self.wl_list = self.rbl.cell.list_all_wl_names()
self.bl_list = self.rbl.cell.list_write_bl_names()
def place_modules(self): def place_modules(self):
""" Add all of the module instances in the logical netlist """ """ Add all of the module instances in the logical netlist """
@ -160,9 +168,6 @@ class replica_bitline(design.design):
mirror="MX") mirror="MX")
self.rbl_inst.place(self.rbl_offset) self.rbl_inst.place(self.rbl_offset)
def route(self): def route(self):
@ -178,15 +183,27 @@ class replica_bitline(design.design):
wl = self.wl_list[0]+"[{}]".format(row) wl = self.wl_list[0]+"[{}]".format(row)
pin = self.rbl_inst.get_pin(wl) pin = self.rbl_inst.get_pin(wl)
# Route the connection to the right so that it doesn't interfere # Route the connection to the right so that it doesn't interfere with the cells
# 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_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": if pin.layer != "metal1":
continue continue
self.add_path("metal1", [pin_right, pin_extension]) self.add_path("metal1", [pin_right, pin_extension1, pin_extension2])
self.add_power_pin("gnd", pin_extension) 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): def route_supplies(self):
""" Propagate all vdd/gnd pins up to this level for all modules """ """ 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 # 3. Route the contact of previous route to the bitcell WL
# route bend of previous net to bitcell WL # route bend of previous net to bitcell WL
wl_offset = self.rbc_inst.get_pin("wl").lc() wl_offset = self.rbc_inst.get_pin(self.wl_list[0]).lc()
xmid_point= 0.5*(wl_offset.x+contact_offset.x) wl_mid1 = wl_offset - vector(1.5*drc["minwidth_metal1"], 0)
wl_mid1 = vector(xmid_point,contact_offset.y) wl_mid2 = vector(wl_mid1.x, contact_offset.y)
wl_mid2 = vector(xmid_point,wl_offset.y) #xmid_point= 0.5*(wl_offset.x+contact_offset.x)
self.add_path("metal1", [contact_offset, wl_mid1, wl_mid2, wl_offset]) #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 # DRAIN ROUTE
# Route the drain to the vdd rail # 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) # Route the connection of the source route to the RBL bitline (left)
# Via will go halfway down from the bitcell # 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 # Route down a pitch so we can use M2 routing
bl_down_offset = bl_offset - vector(0, self.m2_pitch) bl_down_offset = bl_offset - vector(0, self.m2_pitch)
self.add_path("metal2",[source_offset, bl_down_offset, bl_offset]) 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 analytical_delay = True
# Purge the temp directory after a successful run (doesn't purge on errors, anyhow) # Purge the temp directory after a successful run (doesn't purge on errors, anyhow)
purge_temp = True purge_temp = True
# Determines whether multi-port portion of unit tests are run or not
multiport_check = True
# These are the configuration parameters # These are the configuration parameters
num_rw_ports = 1 num_rw_ports = 1
@ -66,9 +64,11 @@ class options(optparse.Values):
# These are the main configuration parameters that should be over-ridden # These are the main configuration parameters that should be over-ridden
# in a configuration file. # in a configuration file.
#num_words = 0 #num_words = 0
#num_banks = 1
#word_size = 0 #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 # These are the default modules that can be over-riden
decoder = "hierarchical_decoder" decoder = "hierarchical_decoder"
dff_array = "dff_array" dff_array = "dff_array"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -18,24 +18,24 @@ class precharge_test(openram_test):
import precharge import precharge
import tech import tech
# check precharge in single port
debug.info(2, "Checking precharge for handmade bitcell") debug.info(2, "Checking precharge for handmade bitcell")
tx = precharge.precharge(name="precharge_driver", size=1) tx = precharge.precharge(name="precharge_driver", size=1)
self.local_check(tx) self.local_check(tx)
if OPTS.multiport_check: # check precharge in multi-port
debug.info(2, "Checking precharge for pbitcell") OPTS.bitcell = "pbitcell"
OPTS.bitcell = "pbitcell" OPTS.num_rw_ports = 1
OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1
OPTS.num_r_ports = 1 OPTS.num_w_ports = 1
OPTS.num_w_ports = 1
tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="bl0", bitcell_br="br0") debug.info(2, "Checking precharge for pbitcell (innermost connections)")
self.local_check(tx) 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) debug.info(2, "Checking precharge for pbitcell (outermost connections)")
tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="bl2", bitcell_br="br2")
tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="bl2", bitcell_br="br2") self.local_check(tx)
self.local_check(tx)
globals.end_openram() 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)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
import single_level_column_mux import single_level_column_mux
import tech import tech
# check single level column mux in single port
debug.info(2, "Checking column mux") debug.info(2, "Checking column mux")
tx = single_level_column_mux.single_level_column_mux(tx_size=8) tx = single_level_column_mux.single_level_column_mux(tx_size=8)
self.local_check(tx) self.local_check(tx)
if OPTS.multiport_check: # check single level column mux in multi-port
debug.info(2, "Checking column mux for pbitcell") OPTS.bitcell = "pbitcell"
OPTS.bitcell = "pbitcell" OPTS.num_rw_ports = 1
OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1
OPTS.num_r_ports = 1 OPTS.num_w_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") debug.info(2, "Checking column mux for pbitcell (innermost connections)")
self.local_check(tx) 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) 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")
tx = single_level_column_mux.single_level_column_mux(tx_size=8, bitcell_bl="bl2", bitcell_br="br2") self.local_check(tx)
self.local_check(tx)
globals.end_openram() 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) # a = hierarchical_decoder.hierarchical_decoder(rows=8)
# self.local_check(a) # self.local_check(a)
# check hierarchical decoder for single port
debug.info(1, "Testing 16 row sample for hierarchical_decoder") debug.info(1, "Testing 16 row sample for hierarchical_decoder")
a = hierarchical_decoder.hierarchical_decoder(rows=16) a = hierarchical_decoder.hierarchical_decoder(rows=16)
self.local_check(a) self.local_check(a)
@ -43,6 +44,28 @@ class hierarchical_decoder_test(openram_test):
debug.info(1, "Testing 512 row sample for hierarchical_decoder") debug.info(1, "Testing 512 row sample for hierarchical_decoder")
a = hierarchical_decoder.hierarchical_decoder(rows=512) a = hierarchical_decoder.hierarchical_decoder(rows=512)
self.local_check(a) 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() 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 hierarchical_predecode2x4 as pre
import tech import tech
# checking hierarchical precode 2x4 for single port
debug.info(1, "Testing sample for hierarchy_predecode2x4") debug.info(1, "Testing sample for hierarchy_predecode2x4")
a = pre.hierarchical_predecode2x4() a = pre.hierarchical_predecode2x4()
self.local_check(a) 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() globals.end_openram()
# instantiate a copdsay of the class to actually run the test # 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 hierarchical_predecode3x8 as pre
import tech import tech
# checking hierarchical precode 3x8 for single port
debug.info(1, "Testing sample for hierarchy_predecode3x8") debug.info(1, "Testing sample for hierarchy_predecode3x8")
a = pre.hierarchical_predecode3x8() a = pre.hierarchical_predecode3x8()
self.local_check(a) 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() 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)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
import single_level_column_mux_array 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") 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) a = single_level_column_mux_array.single_level_column_mux_array(columns=16, word_size=8)
self.local_check(a) 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) a = single_level_column_mux_array.single_level_column_mux_array(columns=32, word_size=4)
self.local_check(a) self.local_check(a)
if OPTS.multiport_check: # check single level column mux array in multi-port
debug.info(2, "Checking column mux array for pbitcell") OPTS.bitcell = "pbitcell"
OPTS.bitcell = "pbitcell" OPTS.num_rw_ports = 1
OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1
OPTS.num_r_ports = 1 OPTS.num_w_ports = 1
OPTS.num_w_ports = 1
debug.info(1, "Testing sample for 2-way column_mux_array in multi-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, bitcell_bl="bl0", bitcell_br="br0")
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)
self.local_check(a)
debug.info(1, "Testing sample for 4-way column_mux_array") 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") 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) self.local_check(a)
debug.info(1, "Testing sample for 8-way column_mux_array") 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") 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) self.local_check(a)
debug.info(1, "Testing sample for 8-way column_mux_array") 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="bl1", bitcell_br="br1") 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) 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)
globals.end_openram() globals.end_openram()

View File

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

View File

@ -20,19 +20,20 @@ class wordline_driver_test(openram_test):
import wordline_driver import wordline_driver
import tech import tech
# check wordline driver for single port
debug.info(2, "Checking driver") debug.info(2, "Checking driver")
tx = wordline_driver.wordline_driver(rows=8) tx = wordline_driver.wordline_driver(rows=8)
self.local_check(tx) self.local_check(tx)
if OPTS.multiport_check: # check wordline driver for multi-port
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
OPTS.num_r_ports = 0 OPTS.num_r_ports = 0
debug.info(2, "Checking driver (multi-port case)") debug.info(2, "Checking driver (multi-port case)")
tx = wordline_driver.wordline_driver(rows=8) tx = wordline_driver.wordline_driver(rows=8)
self.local_check(tx) self.local_check(tx)
globals.end_openram() 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)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
import sense_amp_array 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") 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) a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=2)
self.local_check(a) 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) a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=4)
self.local_check(a) self.local_check(a)
if OPTS.multiport_check: # check sense amp array for multi-port
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
OPTS.num_r_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)") 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) a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=2)
self.local_check(a) self.local_check(a)
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=4 (multi-port case)") 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) a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=4)
self.local_check(a) self.local_check(a)
globals.end_openram() 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)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
import write_driver_array import write_driver_array
# check write driver array for single port
debug.info(2, "Testing write_driver_array for columns=8, word_size=8") 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) a = write_driver_array.write_driver_array(columns=8, word_size=8)
self.local_check(a) 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) a = write_driver_array.write_driver_array(columns=16, word_size=8)
self.local_check(a) self.local_check(a)
if OPTS.multiport_check: # check write driver array for multi-port
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
OPTS.num_r_ports = 0 OPTS.num_r_ports = 0
debug.info(2, "Testing write_driver_array for columns=8, word_size=8 (multi-port case)") 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) a = write_driver_array.write_driver_array(columns=8, word_size=8)
self.local_check(a) self.local_check(a)
debug.info(2, "Testing write_driver_array for columns=16, word_size=8 (multi-port case)") 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) a = write_driver_array.write_driver_array(columns=16, word_size=8)
self.local_check(a) self.local_check(a)
globals.end_openram() 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)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
import replica_bitline 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 stages=4
fanout=4 fanout=4
rows=13 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 control_logic
import tech import tech
# check control logic for single port
debug.info(1, "Testing sample for control_logic") debug.info(1, "Testing sample for control_logic")
a = control_logic.control_logic(num_rows=128) a = control_logic.control_logic(num_rows=128)
self.local_check(a) 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() 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)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
import bank_select import bank_select
debug.info(1, "No column mux") debug.info(1, "No column mux, rw control logic")
a = bank_select.bank_select() 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) self.local_check(a)
globals.end_openram() 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") a = bank(c, name="bank1_1rw_0w_0r_single")
self.local_check(a) 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.netlist_only = True
OPTS.num_rw_ports = 1 c.num_words=16
OPTS.num_w_ports = 1 c.words_per_row=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)
OPTS.num_rw_ports = c.num_rw_ports = 2 OPTS.num_rw_ports = c.num_rw_ports = 2
OPTS.num_w_ports = c.num_w_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) self.local_check(a)
""" """
#globals.end_openram() globals.end_openram()
# instantiate a copy of the class to actually run the test # instantiate a copy of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -11,7 +11,7 @@ import globals
from globals import OPTS from globals import OPTS
import debug 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): class sram_1bank_test(openram_test):
def runTest(self): def runTest(self):
@ -19,8 +19,9 @@ class sram_1bank_test(openram_test):
from sram import sram from sram import sram
from sram_config import sram_config from sram_config import sram_config
OPTS.bitcell = "pbitcell" 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_rw_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
OPTS.num_r_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") debug.info(1, "Single bank, no column mux with control logic")
a = sram(c, "sram1") a = sram(c, "sram1")
self.local_check(a, final_verification=True) 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 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") debug.info(1, "Single bank, no column mux with control logic")
a = sram(c, "sram1") a = sram(c, "sram1")
self.local_check(a, final_verification=True) 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.num_words=32
c.words_per_row=2 c.words_per_row=2
debug.info(1, "Single bank two way column mux with control logic") 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") a = sram(c, "sram4")
self.local_check(a, final_verification=True) self.local_check(a, final_verification=True)
""" """
#globals.end_openram() globals.end_openram()
# instantiate a copy of the class to actually run the test # instantiate a copy of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":

View File

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

View File

@ -48,30 +48,32 @@ class timing_sram_test(openram_test):
import tech import tech
loads = [tech.spice["msflop_in_cap"]*4] loads = [tech.spice["msflop_in_cap"]*4]
slews = [tech.spice["rise_time"]*2] 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": if OPTS.tech_name == "freepdk45":
golden_data = {'delay_hl0': [2.584251], golden_data = {'delay_hl': [2.584251],
'delay_lh0': [0.22870469999999998], 'delay_lh': [0.22870469999999998],
'leakage_power': 0.0009567935, 'leakage_power': 0.0009567935,
'min_period': 4.844, 'min_period': 4.844,
'read0_power0': [0.0547588], 'read0_power': [0.0547588],
'read1_power0': [0.051159970000000006], 'read1_power': [0.051159970000000006],
'slew_hl0': [0.08164099999999999], 'slew_hl': [0.08164099999999999],
'slew_lh0': [0.025474979999999998], 'slew_lh': [0.025474979999999998],
'write0_power0': [0.06513271999999999], 'write0_power': [0.06513271999999999],
'write1_power0': [0.058057000000000004]} 'write1_power': [0.058057000000000004]}
elif OPTS.tech_name == "scn4m_subm": elif OPTS.tech_name == "scn4m_subm":
golden_data = {'delay_hl0': [3.644147], golden_data = {'delay_hl': [3.644147],
'delay_lh0': [1.629815], 'delay_lh': [1.629815],
'leakage_power': 0.0009299118999999999, 'leakage_power': 0.0009299118999999999,
'min_period': 4.688, 'min_period': 4.688,
'read0_power0': [16.28732], 'read0_power': [16.28732],
'read1_power0': [15.75155], 'read1_power': [15.75155],
'slew_hl0': [0.6722473], 'slew_hl': [0.6722473],
'slew_lh0': [0.3386347], 'slew_lh': [0.3386347],
'write0_power0': [18.545450000000002], 'write0_power': [18.545450000000002],
'write1_power0': [16.81084]} 'write1_power': [16.81084]}
else: else:
self.assertTrue(False) # other techs fail 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 from globals import OPTS
import debug import debug
@unittest.skip("SKIPPING 22_sram_func_test") #@unittest.skip("SKIPPING 22_sram_func_test")
class sram_func_test(openram_test): class sram_func_test(openram_test):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
OPTS.spice_name="hspice"
OPTS.analytical_delay = False OPTS.analytical_delay = False
# This is a hack to reload the characterizer __init__ with the spice version # This is a hack to reload the characterizer __init__ with the spice version
from importlib import reload from importlib import reload
import characterizer import characterizer
reload(characterizer) reload(characterizer)
from characterizer import delay from characterizer import functional
if not OPTS.spice_exe: if not OPTS.spice_exe:
debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1) debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1)
import sram from sram import sram
from sram_config import sram_config
debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank") c = sram_config(word_size=4,
s = sram.sram(word_size=1, num_words=32,
num_words=16, num_banks=1)
num_banks=1, c.words_per_row=2
name="sram_func_test") debug.info(1, "Functional test for 1bit, 16word SRAM, with 1 bank")
s = sram(c, name="sram1")
tempspice = OPTS.openram_temp + "temp.sp" tempspice = OPTS.openram_temp + "temp.sp"
s.sp_write(tempspice) 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]) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
d = delay(s,tempspice,corner) f = functional(s.s, tempspice, corner)
d.set_probe(probe_address,probe_data) f.num_cycles = 10
(fail, error) = f.run()
# This will exit if it doesn't find a feasible period self.assertTrue(fail,error)
import tech
d.load = tech.spice["msflop_in_cap"]*4
d.slew = tech.spice["rise_time"]*2
feasible_period = d.find_feasible_period()
os.remove(tempspice)
reload(characterizer)
globals.end_openram() globals.end_openram()
# instantiate a copdsay of the class to actually run the test # 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 word_size = 1
num_words = 16 num_words = 16
num_banks = 1
tech_name = "freepdk45" tech_name = "freepdk45"
process_corners = ["TT"] process_corners = ["TT"]

View File

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

View File

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

View File

@ -29,17 +29,19 @@ class openram_test(unittest.TestCase):
tempgds = OPTS.openram_temp + "temp.gds" tempgds = OPTS.openram_temp + "temp.gds"
a.sp_write(tempspice) 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 import verify
result=verify.run_drc(a.name, tempgds) result=verify.run_drc(a.name, tempgds)
if result != 0: if result != 0:
self.fail("DRC failed: {}".format(a.name)) self.fail("DRC failed: {}".format(a.name))
result=verify.run_lvs(a.name, tempgds, tempspice, final_verification) result=verify.run_lvs(a.name, tempgds, tempspice, final_verification)
if result != 0: if result != 0:
self.fail("LVS mismatch: {}".format(a.name)) self.fail("LVS mismatch: {}".format(a.name))
if OPTS.purge_temp: if OPTS.purge_temp:
self.cleanup() 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 word_size = 32
num_words = 1024 num_words = 1024
num_banks = 1
tech_name = "freepdk45" tech_name = "freepdk45"
process_corners = ["TT"] process_corners = ["TT"]

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,5 @@
word_size = 8 word_size = 8
num_words = 512 num_words = 512
num_banks = 4
tech_name = "freepdk45" tech_name = "freepdk45"
process_corners = ["TT"] 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