mirror of https://github.com/VLSIDA/OpenRAM.git
Merge multiport
This commit is contained in:
commit
a2b1d025ab
|
|
@ -18,6 +18,7 @@ class design(hierarchy_design):
|
|||
hierarchy_design.__init__(self,name)
|
||||
|
||||
self.setup_drc_constants()
|
||||
self.setup_multiport_constants()
|
||||
|
||||
self.m1_pitch = max(contact.m1m2.width,contact.m1m2.height) + max(self.m1_space, self.m2_space)
|
||||
self.m2_pitch = max(contact.m2m3.width,contact.m2m3.height) + max(self.m2_space, self.m3_space)
|
||||
|
|
@ -45,7 +46,35 @@ class design(hierarchy_design):
|
|||
self.contact_to_gate = drc["contact_to_gate"]
|
||||
self.well_enclose_active = drc["well_enclosure_active"]
|
||||
self.implant_enclose_active = drc["implant_enclosure_active"]
|
||||
self.implant_space = drc["implant_to_implant"]
|
||||
self.implant_space = drc["implant_to_implant"]
|
||||
|
||||
def setup_multiport_constants(self):
|
||||
""" These are contants and lists that aid multiport design """
|
||||
self.total_write = OPTS.num_rw_ports + OPTS.num_w_ports
|
||||
self.total_read = OPTS.num_rw_ports + OPTS.num_r_ports
|
||||
self.total_ports = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports
|
||||
self.num_rw_ports = OPTS.num_rw_ports
|
||||
|
||||
# Port indices used for data, address, and control signals
|
||||
# Port IDs used to identify port type
|
||||
self.write_index = []
|
||||
self.read_index = []
|
||||
self.port_id = []
|
||||
port_number = 0
|
||||
|
||||
for port in range(OPTS.num_rw_ports):
|
||||
self.write_index.append(port_number)
|
||||
self.read_index.append(port_number)
|
||||
self.port_id.append("rw")
|
||||
port_number += 1
|
||||
for port in range(OPTS.num_w_ports):
|
||||
self.write_index.append(port_number)
|
||||
self.port_id.append("w")
|
||||
port_number += 1
|
||||
for port in range(OPTS.num_r_ports):
|
||||
self.read_index.append(port_number)
|
||||
self.port_id.append("r")
|
||||
port_number += 1
|
||||
|
||||
def analytical_power(self, proc, vdd, temp, load):
|
||||
""" Get total power of a module """
|
||||
|
|
|
|||
|
|
@ -123,7 +123,8 @@ class layout(lef.lef):
|
|||
"""Adds an instance of a mod to this module"""
|
||||
self.insts.append(geometry.instance(name, mod, offset, mirror, rotate))
|
||||
debug.info(3, "adding instance {}".format(self.insts[-1]))
|
||||
debug.info(4, "instance list: " + ",".join(x.name for x in self.insts))
|
||||
# This is commented out for runtime reasons
|
||||
#debug.info(4, "instance list: " + ",".join(x.name for x in self.insts))
|
||||
return self.insts[-1]
|
||||
|
||||
def get_inst(self, name):
|
||||
|
|
|
|||
|
|
@ -12,14 +12,19 @@ class pbitcell(design.design):
|
|||
with a variable number of read/write, write, and read ports
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, replica_bitcell=False):
|
||||
|
||||
self.num_rw_ports = OPTS.num_rw_ports
|
||||
self.num_w_ports = OPTS.num_w_ports
|
||||
self.num_r_ports = OPTS.num_r_ports
|
||||
self.total_ports = self.num_rw_ports + self.num_w_ports + self.num_r_ports
|
||||
|
||||
name = "pbitcell_{0}RW_{1}W_{2}R".format(self.num_rw_ports, self.num_w_ports, self.num_r_ports)
|
||||
self.replica_bitcell = replica_bitcell
|
||||
|
||||
if self.replica_bitcell:
|
||||
name = "replica_pbitcell_{0}RW_{1}W_{2}R".format(self.num_rw_ports, self.num_w_ports, self.num_r_ports)
|
||||
else:
|
||||
name = "pbitcell_{0}RW_{1}W_{2}R".format(self.num_rw_ports, self.num_w_ports, self.num_r_ports)
|
||||
# This is not a pgate because pgates depend on the bitcell height!
|
||||
design.design.__init__(self, name)
|
||||
debug.info(2, "create a multi-port bitcell with {0} rw ports, {1} w ports and {2} r ports".format(self.num_rw_ports,
|
||||
|
|
@ -30,7 +35,7 @@ class pbitcell(design.design):
|
|||
# We must always create the bitcell layout because
|
||||
# some transistor sizes in the other netlists depend on it
|
||||
self.create_layout()
|
||||
|
||||
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
|
|
@ -70,7 +75,13 @@ class pbitcell(design.design):
|
|||
self.route_read_access()
|
||||
self.extend_well()
|
||||
|
||||
self.offset_all_coordinates()
|
||||
if self.replica_bitcell:
|
||||
self.route_rbc_short()
|
||||
|
||||
# in netlist_only mode, calling offset_all_coordinates will not be possible
|
||||
# this function is not needed to calculate the dimensions of pbitcell in netlist_only mode though
|
||||
if not OPTS.netlist_only:
|
||||
self.offset_all_coordinates()
|
||||
self.DRC_LVS()
|
||||
|
||||
def add_pins(self):
|
||||
|
|
@ -121,6 +132,11 @@ class pbitcell(design.design):
|
|||
self.add_pin("vdd")
|
||||
self.add_pin("gnd")
|
||||
|
||||
if self.replica_bitcell:
|
||||
self.Q_bar = "vdd"
|
||||
else:
|
||||
self.Q_bar = "Q_bar"
|
||||
|
||||
|
||||
def add_modules(self):
|
||||
"""
|
||||
|
|
@ -229,6 +245,10 @@ class pbitcell(design.design):
|
|||
|
||||
# calculation for row line tiling
|
||||
self.rail_tile_height = drc["active_to_body_active"] + contact.well.width
|
||||
if self.inverter_pmos_contact_extension > 0:
|
||||
self.vdd_tile_height = self.inverter_pmos_contact_extension + drc["minwidth_metal1"] + contact.well.width
|
||||
else:
|
||||
self.vdd_tile_height = self.rail_tile_height
|
||||
self.rowline_tile_height = drc["minwidth_metal1"] + contact.m1m2.width
|
||||
|
||||
# calculations related to inverter connections
|
||||
|
|
@ -292,7 +312,7 @@ class pbitcell(design.design):
|
|||
|
||||
# topmost position = height of the inverter + height of vdd
|
||||
self.topmost_ypos = self.inverter_nmos.active_height + self.inverter_gap + self.inverter_pmos.active_height \
|
||||
+ self.rail_tile_height
|
||||
+ self.vdd_tile_height
|
||||
|
||||
# calculations for the cell dimensions
|
||||
array_vdd_overlap = 0.5*contact.well.width
|
||||
|
|
@ -309,20 +329,20 @@ class pbitcell(design.design):
|
|||
# create active for nmos
|
||||
self.inverter_nmos_left = self.add_inst(name="inverter_nmos_left",
|
||||
mod=self.inverter_nmos)
|
||||
self.connect_inst(["Q_bar", "Q", "gnd", "gnd"])
|
||||
self.connect_inst([self.Q_bar, "Q", "gnd", "gnd"])
|
||||
|
||||
self.inverter_nmos_right = self.add_inst(name="inverter_nmos_right",
|
||||
mod=self.inverter_nmos)
|
||||
self.connect_inst(["gnd", "Q_bar", "Q", "gnd"])
|
||||
self.connect_inst(["gnd", self.Q_bar, "Q", "gnd"])
|
||||
|
||||
# create active for pmos
|
||||
self.inverter_pmos_left = self.add_inst(name="inverter_pmos_left",
|
||||
mod=self.inverter_pmos)
|
||||
self.connect_inst(["Q_bar", "Q", "vdd", "vdd"])
|
||||
self.connect_inst([self.Q_bar, "Q", "vdd", "vdd"])
|
||||
|
||||
self.inverter_pmos_right = self.add_inst(name="inverter_pmos_right",
|
||||
mod=self.inverter_pmos)
|
||||
self.connect_inst(["vdd", "Q_bar", "Q", "vdd"])
|
||||
self.connect_inst(["vdd", self.Q_bar, "Q", "vdd"])
|
||||
|
||||
|
||||
def place_storage(self):
|
||||
|
|
@ -343,6 +363,7 @@ class pbitcell(design.design):
|
|||
self.inverter_pmos_left.place([left_inverter_xpos, inverter_pmos_ypos])
|
||||
self.inverter_pmos_right.place([right_inverter_xpos, inverter_pmos_ypos])
|
||||
|
||||
|
||||
def route_storage(self):
|
||||
"""
|
||||
Routes inputs and outputs of inverters to cross couple them
|
||||
|
|
@ -391,13 +412,13 @@ class pbitcell(design.design):
|
|||
height=contact.well.second_layer_width)
|
||||
|
||||
vdd_ypos = self.inverter_nmos.active_height + self.inverter_gap + self.inverter_pmos.active_height \
|
||||
+ drc["active_to_body_active"] + 0.5*(drc["minwidth_tx"] - drc["minwidth_metal1"])
|
||||
+ self.vdd_tile_height - contact.well.second_layer_width
|
||||
self.vdd_position = vector(self.leftmost_xpos, vdd_ypos)
|
||||
self.vdd = self.add_layout_pin(text="vdd",
|
||||
layer="metal1",
|
||||
offset=self.vdd_position,
|
||||
width=self.width,
|
||||
height=drc["minwidth_metal1"])
|
||||
height=contact.well.second_layer_width)
|
||||
|
||||
# Connect inverters to rails
|
||||
# connect inverter nmos to gnd
|
||||
|
|
@ -438,7 +459,7 @@ class pbitcell(design.design):
|
|||
|
||||
self.readwrite_nmos_right[k] = self.add_inst(name="readwrite_nmos_right{}".format(k),
|
||||
mod=self.readwrite_nmos)
|
||||
self.connect_inst(["Q_bar", self.rw_wl_names[k], self.rw_br_names[k], "gnd"])
|
||||
self.connect_inst([self.Q_bar, self.rw_wl_names[k], self.rw_br_names[k], "gnd"])
|
||||
|
||||
|
||||
def place_readwrite_ports(self):
|
||||
|
|
@ -642,7 +663,7 @@ class pbitcell(design.design):
|
|||
|
||||
self.write_nmos_right[k] = self.add_inst(name="write_nmos_right{}".format(k),
|
||||
mod=self.write_nmos)
|
||||
self.connect_inst(["Q_bar", self.w_wl_names[k], self.w_br_names[k], "gnd"])
|
||||
self.connect_inst([self.Q_bar, self.w_wl_names[k], self.w_br_names[k], "gnd"])
|
||||
|
||||
|
||||
def place_write_ports(self):
|
||||
|
|
@ -845,7 +866,7 @@ class pbitcell(design.design):
|
|||
# add read-access transistors
|
||||
self.read_access_nmos_left[k] = self.add_inst(name="read_access_nmos_left{}".format(k),
|
||||
mod=self.read_nmos)
|
||||
self.connect_inst(["RA_to_R_left{}".format(k), " Q_bar", "gnd", "gnd"])
|
||||
self.connect_inst(["RA_to_R_left{}".format(k), self.Q_bar, "gnd", "gnd"])
|
||||
|
||||
self.read_access_nmos_right[k] = self.add_inst(name="read_access_nmos_right{}".format(k),
|
||||
mod=self.read_nmos)
|
||||
|
|
@ -1153,7 +1174,7 @@ class pbitcell(design.design):
|
|||
well_type="p")
|
||||
|
||||
# connect nimplants to vdd
|
||||
offset = vector(0, self.vdd_position.y + 0.5*drc["minwidth_metal1"])
|
||||
offset = vector(0, self.vdd_position.y + 0.5*contact.well.second_layer_width)
|
||||
self.add_contact_center(layers=("active", "contact", "metal1"),
|
||||
offset=offset,
|
||||
rotate=90,
|
||||
|
|
@ -1215,3 +1236,10 @@ class pbitcell(design.design):
|
|||
""" Creates a list of br pin names asscociated with write ports"""
|
||||
br_pins = self.rw_br_names + self.w_br_names
|
||||
return br_pins
|
||||
|
||||
def route_rbc_short(self):
|
||||
""" route the short from Q_bar to gnd necessary for the replica bitcell """
|
||||
Q_bar_pos = self.inverter_pmos_left.get_pin("D").uc()
|
||||
vdd_pos = vector(Q_bar_pos.x, self.vdd_position.y)
|
||||
|
||||
self.add_path("metal1", [Q_bar_pos, vdd_pos])
|
||||
|
|
@ -5,6 +5,8 @@ from globals import OPTS,find_exe,get_tool
|
|||
from .lib import *
|
||||
from .delay import *
|
||||
from .setup_hold import *
|
||||
from .functional import *
|
||||
from .simulation import *
|
||||
|
||||
|
||||
debug.info(1,"Initializing characterizer...")
|
||||
|
|
|
|||
|
|
@ -34,12 +34,61 @@ class delay():
|
|||
self.num_rows = self.sram.num_rows
|
||||
self.num_banks = self.sram.num_banks
|
||||
self.sp_file = spfile
|
||||
|
||||
self.total_ports = self.sram.total_ports
|
||||
self.total_write = self.sram.total_write
|
||||
self.total_read = self.sram.total_read
|
||||
self.read_index = self.sram.read_index
|
||||
self.write_index = self.sram.write_index
|
||||
self.port_id = self.sram.port_id
|
||||
|
||||
# These are the member variables for a simulation
|
||||
self.period = 0
|
||||
self.set_load_slew(0,0)
|
||||
self.set_corner(corner)
|
||||
|
||||
self.create_port_names()
|
||||
self.create_signal_names()
|
||||
|
||||
#Create global measure names. Should maybe be an input at some point.
|
||||
self.create_measurement_names()
|
||||
|
||||
def create_measurement_names(self):
|
||||
"""Create measurement names. The names themselves currently define the type of measurement"""
|
||||
#Altering the names will crash the characterizer. TODO: object orientated approach to the measurements.
|
||||
self.delay_meas_names = ["delay_lh", "delay_hl", "slew_lh", "slew_hl"]
|
||||
self.power_meas_names = ["read0_power", "read1_power", "write0_power", "write1_power"]
|
||||
|
||||
def create_signal_names(self):
|
||||
self.addr_name = "A"
|
||||
self.din_name = "DIN"
|
||||
self.dout_name = "DOUT"
|
||||
|
||||
#This is TODO once multiport control has been finalized.
|
||||
#self.control_name = "CSB"
|
||||
|
||||
def create_port_names(self):
|
||||
"""Generates the port names to be used in characterization and sets default simulation target ports"""
|
||||
self.write_ports = []
|
||||
self.read_ports = []
|
||||
self.total_port_num = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports
|
||||
|
||||
#save a member variable to avoid accessing global. readwrite ports have different control signals.
|
||||
self.readwrite_port_num = OPTS.num_rw_ports
|
||||
|
||||
#Generate the port names. readwrite ports are required to be added first for this to work.
|
||||
for readwrite_port_num in range(OPTS.num_rw_ports):
|
||||
self.read_ports.append(readwrite_port_num)
|
||||
self.write_ports.append(readwrite_port_num)
|
||||
#This placement is intentional. It makes indexing input data easier. See self.data_values
|
||||
for write_port_num in range(OPTS.num_rw_ports, OPTS.num_rw_ports+OPTS.num_w_ports):
|
||||
self.write_ports.append(write_port_num)
|
||||
for read_port_num in range(OPTS.num_rw_ports+OPTS.num_w_ports, OPTS.num_rw_ports+OPTS.num_w_ports+OPTS.num_r_ports):
|
||||
self.read_ports.append(read_port_num)
|
||||
|
||||
#Set the default target ports for simulation. Default is all the ports.
|
||||
self.targ_read_ports = self.read_ports
|
||||
self.targ_write_ports = self.write_ports
|
||||
|
||||
def set_corner(self,corner):
|
||||
""" Set the corner values """
|
||||
self.corner = corner
|
||||
|
|
@ -78,15 +127,16 @@ class delay():
|
|||
|
||||
# instantiate the sram
|
||||
self.sf.write("\n* Instantiation of the SRAM\n")
|
||||
self.stim.inst_sram(abits=self.addr_size,
|
||||
dbits=self.word_size,
|
||||
port_info=(self.total_port_num,self.readwrite_port_num,self.read_ports,self.write_ports),
|
||||
self.stim.inst_sram(sram=self.sram,
|
||||
port_signal_names=(self.addr_name,self.din_name,self.dout_name),
|
||||
port_info=(self.total_port_num,self.write_ports,self.read_ports),
|
||||
abits=self.addr_size,
|
||||
dbits=self.word_size,
|
||||
sram_name=self.name)
|
||||
|
||||
self.sf.write("\n* SRAM output loads\n")
|
||||
for port in self.read_ports:
|
||||
for i in range(self.word_size):
|
||||
self.sf.write("CD{0}{1} DOUT{0}[{1}] 0 {2}f\n".format(port,i,self.load))
|
||||
self.sf.write("CD{0}{1} {2}{0}_{1} 0 {3}f\n".format(port,i,self.dout_name,self.load))
|
||||
|
||||
|
||||
def write_delay_stimulus(self):
|
||||
|
|
@ -121,14 +171,15 @@ class delay():
|
|||
self.sf.write("\n* Generation of control signals\n")
|
||||
self.gen_control()
|
||||
|
||||
self.sf.write("\n* Generation of global clock signal\n")
|
||||
self.stim.gen_pulse(sig_name="CLK",
|
||||
v1=0,
|
||||
v2=self.vdd_voltage,
|
||||
offset=self.period,
|
||||
period=self.period,
|
||||
t_rise=self.slew,
|
||||
t_fall=self.slew)
|
||||
self.sf.write("\n* Generation of Port clock signal\n")
|
||||
for port in range(self.total_port_num):
|
||||
self.stim.gen_pulse(sig_name="CLK{0}".format(port),
|
||||
v1=0,
|
||||
v2=self.vdd_voltage,
|
||||
offset=self.period,
|
||||
period=self.period,
|
||||
t_rise=self.slew,
|
||||
t_fall=self.slew)
|
||||
|
||||
self.write_delay_measures()
|
||||
|
||||
|
|
@ -165,22 +216,23 @@ class delay():
|
|||
self.sf.write("\n* Generation of data and address signals\n")
|
||||
for write_port in self.write_ports:
|
||||
for i in range(self.word_size):
|
||||
self.stim.gen_constant(sig_name="DIN{0}[{1}] ".format(write_port, i),
|
||||
self.stim.gen_constant(sig_name="{0}{1}_{2} ".format(self.din_name,write_port, i),
|
||||
v_val=0)
|
||||
for port in range(self.total_port_num):
|
||||
for i in range(self.addr_size):
|
||||
self.stim.gen_constant(sig_name="A{0}[{1}]".format(port, i),
|
||||
self.stim.gen_constant(sig_name="{0}{1}_{2}".format(self.addr_name,port, i),
|
||||
v_val=0)
|
||||
|
||||
# generate control signals
|
||||
self.sf.write("\n* Generation of control signals\n")
|
||||
for port in range(self.total_port_num):
|
||||
self.stim.gen_constant(sig_name="CSB{0}".format(port), v_val=self.vdd_voltage)
|
||||
if port in self.read_ports and port in self.write_ports:
|
||||
if port in self.write_ports and port in self.read_ports:
|
||||
self.stim.gen_constant(sig_name="WEB{0}".format(port), v_val=self.vdd_voltage)
|
||||
|
||||
self.sf.write("\n* Generation of global clock signal\n")
|
||||
self.stim.gen_constant(sig_name="CLK", v_val=0)
|
||||
for port in range(self.total_port_num):
|
||||
self.stim.gen_constant(sig_name="CLK{0}".format(port), v_val=0)
|
||||
|
||||
self.write_power_measures()
|
||||
|
||||
|
|
@ -189,87 +241,85 @@ class delay():
|
|||
|
||||
self.sf.close()
|
||||
|
||||
def get_delay_meas_values(self, delay_name, port):
|
||||
"""Get the values needed to generate a Spice measurement statement based on the name of the measurement."""
|
||||
debug.check('lh' in delay_name or 'hl' in delay_name, "Measure command {0} does not contain direction (lh/hl)")
|
||||
trig_clk_name = "clk{0}".format(port)
|
||||
meas_name="{0}{1}".format(delay_name, port)
|
||||
targ_name = "{0}".format("{0}{1}_{2}".format(self.dout_name,port,self.probe_data))
|
||||
half_vdd = 0.5 * self.vdd_voltage
|
||||
trig_slew_low = 0.1 * self.vdd_voltage
|
||||
targ_slew_high = 0.9 * self.vdd_voltage
|
||||
if 'delay' in delay_name:
|
||||
trig_dir="RISE"
|
||||
trig_val = half_vdd
|
||||
targ_val = half_vdd
|
||||
trig_name = trig_clk_name
|
||||
if 'lh' in delay_name:
|
||||
targ_dir="RISE"
|
||||
trig_td = targ_td = self.cycle_times[self.measure_cycles["read1_{0}".format(port)]]
|
||||
else:
|
||||
targ_dir="FALL"
|
||||
trig_td = targ_td = self.cycle_times[self.measure_cycles["read0_{0}".format(port)]]
|
||||
|
||||
elif 'slew' in delay_name:
|
||||
trig_name = targ_name
|
||||
if 'lh' in delay_name:
|
||||
trig_val = trig_slew_low
|
||||
targ_val = targ_slew_high
|
||||
targ_dir = trig_dir = "RISE"
|
||||
trig_td = targ_td = self.cycle_times[self.measure_cycles["read1_{0}".format(port)]]
|
||||
else:
|
||||
trig_val = targ_slew_high
|
||||
targ_val = trig_slew_low
|
||||
targ_dir = trig_dir = "FALL"
|
||||
trig_td = targ_td = self.cycle_times[self.measure_cycles["read0_{0}".format(port)]]
|
||||
else:
|
||||
debug.error(1, "Measure command {0} not recognized".format(delay_name))
|
||||
return (meas_name,trig_name,targ_name,trig_val,targ_val,trig_dir,targ_dir,trig_td,targ_td)
|
||||
|
||||
def write_delay_measures_read_port(self, port):
|
||||
"""
|
||||
Write the measure statements to quantify the delay and power results for a read port.
|
||||
"""
|
||||
|
||||
# Trigger on the clk of the appropriate cycle
|
||||
trig_name = "clk"
|
||||
#Target name should be an input to the function or a member variable. That way, the ports can be singled out for testing
|
||||
targ_name = "{0}".format("DOUT{0}[{1}]".format(port,self.probe_data))
|
||||
trig_val = targ_val = 0.5 * self.vdd_voltage
|
||||
|
||||
# Delay the target to measure after the negative edge
|
||||
self.stim.gen_meas_delay(meas_name="DELAY_HL{0}".format(port),
|
||||
trig_name=trig_name,
|
||||
targ_name=targ_name,
|
||||
trig_val=trig_val,
|
||||
targ_val=targ_val,
|
||||
trig_dir="RISE",
|
||||
targ_dir="FALL",
|
||||
trig_td=self.cycle_times[self.measure_cycles["read0_{0}".format(port)]],
|
||||
targ_td=self.cycle_times[self.measure_cycles["read0_{0}".format(port)]])
|
||||
|
||||
self.stim.gen_meas_delay(meas_name="DELAY_LH{0}".format(port),
|
||||
trig_name=trig_name,
|
||||
targ_name=targ_name,
|
||||
trig_val=trig_val,
|
||||
targ_val=targ_val,
|
||||
trig_dir="RISE",
|
||||
targ_dir="RISE",
|
||||
trig_td=self.cycle_times[self.measure_cycles["read1_{0}".format(port)]],
|
||||
targ_td=self.cycle_times[self.measure_cycles["read1_{0}".format(port)]])
|
||||
|
||||
self.stim.gen_meas_delay(meas_name="SLEW_HL{0}".format(port),
|
||||
trig_name=targ_name,
|
||||
targ_name=targ_name,
|
||||
trig_val=0.9*self.vdd_voltage,
|
||||
targ_val=0.1*self.vdd_voltage,
|
||||
trig_dir="FALL",
|
||||
targ_dir="FALL",
|
||||
trig_td=self.cycle_times[self.measure_cycles["read0_{0}".format(port)]],
|
||||
targ_td=self.cycle_times[self.measure_cycles["read0_{0}".format(port)]])
|
||||
|
||||
self.stim.gen_meas_delay(meas_name="SLEW_LH{0}".format(port),
|
||||
trig_name=targ_name,
|
||||
targ_name=targ_name,
|
||||
trig_val=0.1*self.vdd_voltage,
|
||||
targ_val=0.9*self.vdd_voltage,
|
||||
trig_dir="RISE",
|
||||
targ_dir="RISE",
|
||||
trig_td=self.cycle_times[self.measure_cycles["read1_{0}".format(port)]],
|
||||
targ_td=self.cycle_times[self.measure_cycles["read1_{0}".format(port)]])
|
||||
|
||||
# add measure statements for delays/slews
|
||||
for dname in self.delay_meas_names:
|
||||
meas_values = self.get_delay_meas_values(dname, port)
|
||||
self.stim.gen_meas_delay(*meas_values)
|
||||
|
||||
# add measure statements for power
|
||||
t_initial = self.cycle_times[self.measure_cycles["read0_{0}".format(port)]]
|
||||
t_final = self.cycle_times[self.measure_cycles["read0_{0}".format(port)]+1]
|
||||
self.stim.gen_meas_power(meas_name="READ0_POWER{0}".format(port),
|
||||
t_initial=t_initial,
|
||||
t_final=t_final)
|
||||
|
||||
t_initial = self.cycle_times[self.measure_cycles["read1_{0}".format(port)]]
|
||||
t_final = self.cycle_times[self.measure_cycles["read1_{0}".format(port)]+1]
|
||||
self.stim.gen_meas_power(meas_name="READ1_POWER{0}".format(port),
|
||||
t_initial=t_initial,
|
||||
t_final=t_final)
|
||||
|
||||
for pname in self.power_meas_names:
|
||||
if "read" not in pname:
|
||||
continue
|
||||
#Different naming schemes are used for the measure cycle dict and measurement names.
|
||||
#TODO: make them the same so they can be indexed the same.
|
||||
if '1' in pname:
|
||||
t_initial = self.cycle_times[self.measure_cycles["read1_{0}".format(port)]]
|
||||
t_final = self.cycle_times[self.measure_cycles["read1_{0}".format(port)]+1]
|
||||
elif '0' in pname:
|
||||
t_initial = self.cycle_times[self.measure_cycles["read0_{0}".format(port)]]
|
||||
t_final = self.cycle_times[self.measure_cycles["read0_{0}".format(port)]+1]
|
||||
self.stim.gen_meas_power(meas_name="{0}{1}".format(pname, port),
|
||||
t_initial=t_initial,
|
||||
t_final=t_final)
|
||||
|
||||
def write_delay_measures_write_port(self, port):
|
||||
"""
|
||||
Write the measure statements to quantify the power results for a write port.
|
||||
"""
|
||||
# add measure statements for power
|
||||
t_initial = self.cycle_times[self.measure_cycles["write0_{0}".format(port)]]
|
||||
t_final = self.cycle_times[self.measure_cycles["write0_{0}".format(port)]+1]
|
||||
self.stim.gen_meas_power(meas_name="WRITE0_POWER{0}".format(port),
|
||||
t_initial=t_initial,
|
||||
t_final=t_final)
|
||||
|
||||
t_initial = self.cycle_times[self.measure_cycles["write1_{0}".format(port)]]
|
||||
t_final = self.cycle_times[self.measure_cycles["write1_{0}".format(port)]+1]
|
||||
self.stim.gen_meas_power(meas_name="WRITE1_POWER{0}".format(port),
|
||||
t_initial=t_initial,
|
||||
t_final=t_final)
|
||||
for pname in self.power_meas_names:
|
||||
if "write" not in pname:
|
||||
continue
|
||||
t_initial = self.cycle_times[self.measure_cycles["write0_{0}".format(port)]]
|
||||
t_final = self.cycle_times[self.measure_cycles["write0_{0}".format(port)]+1]
|
||||
if '1' in pname:
|
||||
t_initial = self.cycle_times[self.measure_cycles["write1_{0}".format(port)]]
|
||||
t_final = self.cycle_times[self.measure_cycles["write1_{0}".format(port)]+1]
|
||||
|
||||
self.stim.gen_meas_power(meas_name="{0}{1}".format(pname, port),
|
||||
t_initial=t_initial,
|
||||
t_final=t_final)
|
||||
|
||||
def write_delay_measures(self):
|
||||
"""
|
||||
|
|
@ -311,8 +361,7 @@ class delay():
|
|||
starting point.
|
||||
"""
|
||||
debug.check(port in self.read_ports, "Characterizer requires a read port to determine a period.")
|
||||
#Adding this as a sanity check for editing this function later. This function assumes period has been set previously
|
||||
debug.check(self.period > 0, "Initial starting period not defined")
|
||||
|
||||
feasible_period = float(tech.spice["feasible_period"])
|
||||
#feasible_period = float(2.5)#What happens if feasible starting point is wrong?
|
||||
time_out = 9
|
||||
|
|
@ -334,38 +383,34 @@ class delay():
|
|||
|
||||
if not success:
|
||||
feasible_period = 2 * feasible_period
|
||||
break
|
||||
feasible_delay_lh = results["delay_lh{0}".format(port)]
|
||||
feasible_delay_hl = results["delay_hl{0}".format(port)]
|
||||
feasible_slew_lh = results["slew_lh{0}".format(port)]
|
||||
feasible_slew_hl = results["slew_hl{0}".format(port)]
|
||||
|
||||
delay_str = "feasible_delay {0:.4f}ns/{1:.4f}ns".format(feasible_delay_lh, feasible_delay_hl)
|
||||
slew_str = "slew {0:.4f}ns/{1:.4f}ns".format(feasible_slew_lh, feasible_slew_hl)
|
||||
continue
|
||||
|
||||
#Positions of measurements currently hardcoded. First 2 are delays, next 2 are slews
|
||||
feasible_delays = [results[port][mname] for mname in self.delay_meas_names if "delay" in mname]
|
||||
feasible_slews = [results[port][mname] for mname in self.delay_meas_names if "slew" in mname]
|
||||
delay_str = "feasible_delay {0:.4f}ns/{1:.4f}ns".format(*feasible_delays)
|
||||
slew_str = "slew {0:.4f}ns/{1:.4f}ns".format(*feasible_slews)
|
||||
debug.info(2, "feasible_period passed for Port {3}: {0}ns {1} {2} ".format(feasible_period,
|
||||
delay_str,
|
||||
slew_str,
|
||||
port))
|
||||
#Add feasible delays of port to dict
|
||||
#feasible_delays_lh[port] = feasible_delay_lh
|
||||
#feasible_delays_hl[port] = feasible_delay_hl
|
||||
|
||||
if success:
|
||||
debug.info(1, "Found feasible_period: {0}ns".format(feasible_period))
|
||||
debug.info(2, "Found feasible_period for port {0}: {1}ns".format(port, feasible_period))
|
||||
self.period = feasible_period
|
||||
return (feasible_delay_lh, feasible_delay_hl)
|
||||
#Only return results related to input port.
|
||||
return results[port]
|
||||
|
||||
def find_feasible_period(self):
|
||||
"""
|
||||
Loops through all read ports determining the feasible period and collecting
|
||||
delay information from each port.
|
||||
"""
|
||||
feasible_delays_lh = {}
|
||||
feasible_delays_hl = {}
|
||||
feasible_delays = [{} for i in range(self.total_port_num)]
|
||||
self.period = float(tech.spice["feasible_period"])
|
||||
|
||||
#Get initial feasible period from first port
|
||||
(feasible_delays_lh[0], feasible_delays_hl[0]) = self.find_feasible_period_one_port(self.read_ports[0])
|
||||
#Get initial feasible delays from first port
|
||||
feasible_delays[self.read_ports[0]] = self.find_feasible_period_one_port(self.read_ports[0])
|
||||
previous_period = self.period
|
||||
|
||||
|
||||
|
|
@ -374,23 +419,27 @@ class delay():
|
|||
i = 1
|
||||
while i < len(self.read_ports):
|
||||
port = self.read_ports[i]
|
||||
(feasible_delays_lh[port], feasible_delays_hl[port]) = self.find_feasible_period_one_port(port)
|
||||
#Only extract port values from the specified port, not the entire results.
|
||||
feasible_delays[port].update(self.find_feasible_period_one_port(port))
|
||||
#Function sets the period. Restart the entire process if period changes to collect accurate delays
|
||||
if self.period > previous_period:
|
||||
i = 0
|
||||
else:
|
||||
i+=1
|
||||
previous_period = self.period
|
||||
return (feasible_delays_lh, feasible_delays_hl)
|
||||
debug.info(1, "Found feasible_period: {0}ns".format(self.period))
|
||||
return feasible_delays
|
||||
|
||||
|
||||
def parse_values(self, values_names, mult = 1.0):
|
||||
"""Parse multiple values in the timing output file. Optional multiplier."""
|
||||
def parse_values(self, values_names, port, mult = 1.0):
|
||||
"""Parse multiple values in the timing output file. Optional multiplier.
|
||||
Return a dict of the input names and values. Port used for parsing file.
|
||||
"""
|
||||
values = []
|
||||
all_values_floats = True
|
||||
for vname in values_names:
|
||||
#ngspice converts all measure characters to lowercase, not tested on other sims
|
||||
value = parse_spice_list("timing", vname.lower())
|
||||
value = parse_spice_list("timing", "{0}{1}".format(vname.lower(), port))
|
||||
#Check if any of the values fail to parse
|
||||
if type(value)!=float:
|
||||
all_values_floats = False
|
||||
|
|
@ -409,7 +458,10 @@ class delay():
|
|||
works on the trimmed netlist by default, so powers do not
|
||||
include leakage of all cells.
|
||||
"""
|
||||
result = {}
|
||||
#Sanity Check
|
||||
debug.check(self.period > 0, "Target simulation period non-positive")
|
||||
|
||||
result = [{} for i in range(self.total_port_num)]
|
||||
# Checking from not data_value to data_value
|
||||
self.write_delay_stimulus()
|
||||
|
||||
|
|
@ -418,29 +470,30 @@ class delay():
|
|||
#Loop through all targeted ports and collect delays and powers.
|
||||
#Too much duplicate code here. Try reducing
|
||||
for port in self.targ_read_ports:
|
||||
delay_names = ["delay_hl{0}".format(port), "delay_lh{0}".format(port),
|
||||
"slew_hl{0}".format(port), "slew_lh{0}".format(port)]
|
||||
delays = self.parse_values(delay_names, 1e9) # scale delays to ns
|
||||
if not self.check_valid_delays((delays[delay_names[0]],delays[delay_names[1]],delays[delay_names[2]],delays[delay_names[3]])):
|
||||
debug.info(2, "Check delay values for port {}".format(port))
|
||||
delay_names = ["{0}{1}".format(mname,port) for mname in self.delay_meas_names]
|
||||
delay_names = [mname for mname in self.delay_meas_names]
|
||||
delays = self.parse_values(delay_names, port, 1e9) # scale delays to ns
|
||||
if not self.check_valid_delays(tuple(delays.values())):
|
||||
return (False,{})
|
||||
result.update(delays)
|
||||
result[port].update(delays)
|
||||
|
||||
power_names = ["read0_power{0}".format(port), "read1_power{0}".format(port)]
|
||||
powers = self.parse_values(power_names, 1e3) # scale power to mw
|
||||
power_names = [mname for mname in self.power_meas_names if 'read' in mname]
|
||||
powers = self.parse_values(power_names, port, 1e3) # scale power to mw
|
||||
#Check that power parsing worked.
|
||||
for name, power in powers.items():
|
||||
if type(power)!=float:
|
||||
debug.error("Failed to Parse Power Values:\n\t\t{0}".format(powers),1) #Printing the entire dict looks bad.
|
||||
result.update(powers)
|
||||
result[port].update(powers)
|
||||
|
||||
for port in self.targ_write_ports:
|
||||
power_names = ["write0_power{0}".format(port), "write1_power{0}".format(port)]
|
||||
powers = self.parse_values(power_names, 1e3) # scale power to mw
|
||||
power_names = [mname for mname in self.power_meas_names if 'write' in mname]
|
||||
powers = self.parse_values(power_names, port, 1e3) # scale power to mw
|
||||
#Check that power parsing worked.
|
||||
for name, power in powers.items():
|
||||
if type(power)!=float:
|
||||
debug.error("Failed to Parse Power Values:\n\t\t{0}".format(powers),1) #Printing the entire dict looks bad.
|
||||
result.update(powers)
|
||||
result[port].update(powers)
|
||||
|
||||
# The delay is from the negative edge for our SRAM
|
||||
return (True,result)
|
||||
|
|
@ -499,11 +552,11 @@ class delay():
|
|||
|
||||
return True
|
||||
|
||||
def find_min_period(self, feasible_delays_lh, feasible_delays_hl):
|
||||
def find_min_period(self, feasible_delays):
|
||||
"""
|
||||
Determine the minimum period for all ports.
|
||||
Determine a single minimum period for all ports.
|
||||
"""
|
||||
|
||||
|
||||
feasible_period = ub_period = self.period
|
||||
lb_period = 0.0
|
||||
target_period = 0.5 * (ub_period + lb_period)
|
||||
|
|
@ -511,7 +564,7 @@ class delay():
|
|||
#Find the minimum period for all ports. Start at one port and perform binary search then use that delay as a starting position.
|
||||
#For testing purposes, only checks read ports.
|
||||
for port in self.read_ports:
|
||||
target_period = self.find_min_period_one_port(feasible_delays_lh, feasible_delays_hl, port, lb_period, ub_period, target_period)
|
||||
target_period = self.find_min_period_one_port(feasible_delays, port, lb_period, ub_period, target_period)
|
||||
#The min period of one port becomes the new lower bound. Reset the upper_bound.
|
||||
lb_period = target_period
|
||||
ub_period = feasible_period
|
||||
|
|
@ -521,10 +574,10 @@ class delay():
|
|||
self.targ_write_ports = []
|
||||
return target_period
|
||||
|
||||
def find_min_period_one_port(self, feasible_delays_lh, feasible_delays_hl, port, lb_period, ub_period, target_period):
|
||||
def find_min_period_one_port(self, feasible_delays, port, lb_period, ub_period, target_period):
|
||||
"""
|
||||
Searches for the smallest period with output delays being within 5% of
|
||||
long period. For the current logic to characterize multiport, bound are required as an input.
|
||||
long period. For the current logic to characterize multiport, bounds are required as an input.
|
||||
"""
|
||||
|
||||
#previous_period = ub_period = self.period
|
||||
|
|
@ -546,24 +599,20 @@ class delay():
|
|||
lb_period,
|
||||
port))
|
||||
|
||||
if self.try_period(feasible_delays_lh, feasible_delays_hl):
|
||||
if self.try_period(feasible_delays):
|
||||
ub_period = target_period
|
||||
else:
|
||||
lb_period = target_period
|
||||
|
||||
if relative_compare(ub_period, lb_period, error_tolerance=0.05):
|
||||
# ub_period is always feasible. When done with a port, set the target period of the next port as the lower bound
|
||||
# and reset the upperbound
|
||||
# ub_period is always feasible.
|
||||
return ub_period
|
||||
#target_period = lb_period = ub_period
|
||||
#ub_period = previous_period
|
||||
#break
|
||||
|
||||
|
||||
#Update target
|
||||
target_period = 0.5 * (ub_period + lb_period)
|
||||
|
||||
|
||||
def try_period(self, feasible_delays_lh, feasible_delays_hl):
|
||||
def try_period(self, feasible_delays):
|
||||
"""
|
||||
This tries to simulate a period and checks if the result
|
||||
works. If it does and the delay is within 5% still, it returns True.
|
||||
|
|
@ -574,27 +623,20 @@ class delay():
|
|||
return False
|
||||
|
||||
#Check the values of target readwrite and read ports. Write ports do not produce delays in this current version
|
||||
for port in self.targ_read_ports:
|
||||
delay_hl = results["delay_hl{0}".format(port)]
|
||||
delay_lh = results["delay_lh{0}".format(port)]
|
||||
slew_hl = results["slew_hl{0}".format(port)]
|
||||
slew_lh = results["slew_lh{0}".format(port)]
|
||||
|
||||
if not relative_compare(delay_lh,feasible_delays_lh[port],error_tolerance=0.05):
|
||||
debug.info(2,"Delay too big {0} vs {1}".format(delay_lh,feasible_delays_lh[port]))
|
||||
return False
|
||||
elif not relative_compare(delay_hl,feasible_delays_hl[port],error_tolerance=0.05):
|
||||
debug.info(2,"Delay too big {0} vs {1}".format(delay_hl,feasible_delays_hl[port]))
|
||||
return False
|
||||
for port in self.targ_read_ports:
|
||||
delay_port_names = [mname for mname in self.delay_meas_names if "delay" in mname]
|
||||
for dname in delay_port_names:
|
||||
if not relative_compare(results[port][dname],feasible_delays[port][dname],error_tolerance=0.05):
|
||||
debug.info(2,"Delay too big {0} vs {1}".format(results[port][dname],feasible_delays[port][dname]))
|
||||
return False
|
||||
|
||||
#key=raw_input("press return to continue")
|
||||
|
||||
debug.info(2,"Successful period {0}, Port {5}, delay_hl={1}ns, delay_lh={2}ns slew_hl={3}ns slew_lh={4}ns".format(self.period,
|
||||
delay_hl,
|
||||
delay_lh,
|
||||
slew_hl,
|
||||
slew_lh,
|
||||
port))
|
||||
|
||||
#Dynamic way to build string. A bit messy though.
|
||||
delay_str = ', '.join("{0}={1}ns".format(mname, results[port][mname]) for mname in self.delay_meas_names)
|
||||
debug.info(2,"Successful period {0}, Port {2}, {1}".format(self.period,
|
||||
delay_str,
|
||||
port))
|
||||
return True
|
||||
|
||||
def set_probe(self,probe_address, probe_data):
|
||||
|
|
@ -633,12 +675,11 @@ class delay():
|
|||
"""
|
||||
Main function to characterize an SRAM for a table. Computes both delay and power characterization.
|
||||
"""
|
||||
#Dict to hold all characterization values
|
||||
char_sram_data = {}
|
||||
|
||||
self.set_probe(probe_address, probe_data)
|
||||
|
||||
self.create_port_names()
|
||||
|
||||
self.create_char_data_dict()
|
||||
|
||||
self.load=max(loads)
|
||||
self.slew=max(slews)
|
||||
# This is for debugging a full simulation
|
||||
|
|
@ -652,7 +693,7 @@ class delay():
|
|||
# sys.exit(1)
|
||||
|
||||
#For debugging, skips characterization and returns dummy values.
|
||||
# char_data = self.char_data
|
||||
# char_data = self.get_empty_measure_data_dict()
|
||||
# i = 1.0
|
||||
# for slew in slews:
|
||||
# for load in loads:
|
||||
|
|
@ -664,34 +705,29 @@ class delay():
|
|||
# return char_data
|
||||
|
||||
# 1) Find a feasible period and it's corresponding delays using the trimmed array.
|
||||
(feasible_delays_lh, feasible_delays_hl) = self.find_feasible_period()
|
||||
#Check all the delays
|
||||
for k,v in feasible_delays_lh.items():
|
||||
debug.check(v>0,"Negative delay may not be possible")
|
||||
for k,v in feasible_delays_hl.items():
|
||||
debug.check(v>0,"Negative delay may not be possible")
|
||||
|
||||
feasible_delays = self.find_feasible_period()
|
||||
|
||||
# 2) Finds the minimum period without degrading the delays by X%
|
||||
self.set_load_slew(max(loads),max(slews))
|
||||
min_period = self.find_min_period(feasible_delays_lh, feasible_delays_hl)
|
||||
min_period = self.find_min_period(feasible_delays)
|
||||
debug.check(type(min_period)==float,"Couldn't find minimum period.")
|
||||
debug.info(1, "Min Period Found: {0}ns".format(min_period))
|
||||
self.char_data["min_period"] = round_time(min_period)
|
||||
char_sram_data["min_period"] = round_time(min_period)
|
||||
|
||||
# 3) Find the leakage power of the trimmmed and UNtrimmed arrays.
|
||||
(full_array_leakage, trim_array_leakage)=self.run_power_simulation()
|
||||
self.char_data["leakage_power"]=full_array_leakage
|
||||
char_sram_data["leakage_power"]=full_array_leakage
|
||||
leakage_offset = full_array_leakage - trim_array_leakage
|
||||
|
||||
# 4) At the minimum period, measure the delay, slew and power for all slew/load pairs.
|
||||
self.simulate_loads_and_slews(slews, loads, leakage_offset)
|
||||
|
||||
return self.char_data
|
||||
self.period = min_period
|
||||
char_port_data = self.simulate_loads_and_slews(slews, loads, leakage_offset)
|
||||
|
||||
return (char_sram_data, char_port_data)
|
||||
|
||||
def simulate_loads_and_slews(self, slews, loads, leakage_offset):
|
||||
"""Simulate all specified output loads and input slews pairs"""
|
||||
#Set the target simulation ports to all available ports. This make sims slower but failed sims exit anyways.
|
||||
"""Simulate all specified output loads and input slews pairs of all ports"""
|
||||
measure_data = self.get_empty_measure_data_dict()
|
||||
#Set the target simulation ports to all available ports. This make sims slower but failed sims exit anyways.
|
||||
self.targ_read_ports = self.read_ports
|
||||
self.targ_write_ports = self.write_ports
|
||||
for slew in slews:
|
||||
|
|
@ -700,13 +736,17 @@ class delay():
|
|||
# Find the delay, dynamic power, and leakage power of the trimmed array.
|
||||
(success, delay_results) = self.run_delay_simulation()
|
||||
debug.check(success,"Couldn't run a simulation. slew={0} load={1}\n".format(self.slew,self.load))
|
||||
for k,v in delay_results.items():
|
||||
if "power" in k:
|
||||
# Subtract partial array leakage and add full array leakage for the power measures
|
||||
self.char_data[k].append(v + leakage_offset)
|
||||
else:
|
||||
self.char_data[k].append(v)
|
||||
|
||||
debug.info(1, "Simulation Passed: Port {0} slew={1} load={2}".format("All", self.slew,self.load))
|
||||
#The results has a dict for every port but dicts can be empty (e.g. ports were not targeted).
|
||||
for port in range(self.total_port_num):
|
||||
for mname,value in delay_results[port].items():
|
||||
if "power" in mname:
|
||||
# Subtract partial array leakage and add full array leakage for the power measures
|
||||
measure_data[port][mname].append(value + leakage_offset)
|
||||
else:
|
||||
measure_data[port][mname].append(value)
|
||||
return measure_data
|
||||
|
||||
def add_data(self, data, port):
|
||||
""" Add the array of data values """
|
||||
debug.check(len(data)==self.word_size, "Invalid data word size.")
|
||||
|
|
@ -720,7 +760,7 @@ class delay():
|
|||
else:
|
||||
debug.error("Non-binary data string",1)
|
||||
index += 1
|
||||
|
||||
|
||||
def add_address(self, address, port):
|
||||
""" Add the array of address values """
|
||||
debug.check(len(address)==self.addr_size, "Invalid address size.")
|
||||
|
|
@ -744,9 +784,7 @@ class delay():
|
|||
|
||||
def add_noop_all_ports(self, comment, address, data):
|
||||
""" Add the control values for a noop to all ports. """
|
||||
self.cycle_comments.append("Cycle {0:2d}\tPort All\t{1:5.2f}ns:\t{2}".format(len(self.cycle_times),
|
||||
self.t_current,
|
||||
comment))
|
||||
self.add_comment("All", comment)
|
||||
self.cycle_times.append(self.t_current)
|
||||
self.t_current += self.period
|
||||
|
||||
|
|
@ -757,10 +795,7 @@ class delay():
|
|||
def add_read(self, comment, address, data, port):
|
||||
""" Add the control values for a read cycle. """
|
||||
debug.check(port in self.read_ports, "Cannot add read cycle to a write port.")
|
||||
self.cycle_comments.append("Cycle {0:2d}\tPort {3}\t{1:5.2f}ns:\t{2}".format(len(self.cycle_comments),
|
||||
self.t_current,
|
||||
comment,
|
||||
port))
|
||||
self.add_comment(port, comment)
|
||||
self.cycle_times.append(self.t_current)
|
||||
self.t_current += self.period
|
||||
self.add_control_one_port(port, "read")
|
||||
|
|
@ -780,10 +815,7 @@ class delay():
|
|||
def add_write(self, comment, address, data, port):
|
||||
""" Add the control values for a write cycle. """
|
||||
debug.check(port in self.write_ports, "Cannot add read cycle to a read port.")
|
||||
self.cycle_comments.append("Cycle {0:2d}\tPort {3}\t{1:5.2f}ns:\t{2}".format(len(self.cycle_comments),
|
||||
self.t_current,
|
||||
comment,
|
||||
port))
|
||||
self.add_comment(port, comment)
|
||||
self.cycle_times.append(self.t_current)
|
||||
self.t_current += self.period
|
||||
|
||||
|
|
@ -814,9 +846,19 @@ class delay():
|
|||
#Append the values depending on the type of port
|
||||
self.csb_values[port].append(csb_val)
|
||||
#If port is in both lists, add rw control signal. Condition indicates its a RW port.
|
||||
if port < len(self.web_values):
|
||||
if port in self.write_ports and port in self.read_ports:
|
||||
self.web_values[port].append(web_val)
|
||||
|
||||
def add_comment(self, port, comment):
|
||||
"""Add comment to list to be printed in stimulus file"""
|
||||
#Clean up time before appending. Make spacing dynamic as well.
|
||||
time = "{0:.2f} ns:".format(self.t_current)
|
||||
time_spacing = len(time)+6
|
||||
self.cycle_comments.append("Cycle {0:<6d} Port {1:<6} {2:<{3}}: {4}".format(len(self.cycle_times),
|
||||
port,
|
||||
time,
|
||||
time_spacing,
|
||||
comment))
|
||||
def gen_test_cycles_one_port(self, read_port, write_port):
|
||||
"""Intended but not implemented: Returns a list of key time-points [ns] of the waveform (each rising edge)
|
||||
of the cycles to do a timing evaluation of a single port. Current: Values overwritten for multiple calls"""
|
||||
|
|
@ -906,14 +948,14 @@ class delay():
|
|||
self.measure_cycles = {}
|
||||
|
||||
# Control signals for ports. These are not the final signals and will likely be changed later.
|
||||
#write enable bar for readwrite ports to control read or write
|
||||
self.web_values = [[] for i in range(self.readwrite_port_num)]
|
||||
#csb represents a basic "enable" signal that all ports have.
|
||||
self.csb_values = [[] for i in range(self.total_port_num)]
|
||||
#web is the enable for write ports. Dicts used for simplicity as ports are not necessarily incremental.
|
||||
self.web_values = {port:[] for port in self.write_ports}
|
||||
#csb acts as an enable for the read ports.
|
||||
self.csb_values = {port:[] for port in range(self.total_port_num)}
|
||||
|
||||
# Address and data values for each address/data bit. A dict of 3d lists of size #ports x bits x cycles.
|
||||
self.data_values=[[[] for i in range(self.addr_size)]]*len(self.write_ports)
|
||||
self.addr_values=[[[] for i in range(self.addr_size)]]*self.total_port_num
|
||||
# Address and data values for each address/data bit. A 3d list of size #ports x bits x cycles.
|
||||
self.data_values=[[[] for bit in range(self.word_size)] for port in range(len(self.write_ports))]
|
||||
self.addr_values=[[[] for bit in range(self.addr_size)] for port in range(self.total_port_num)]
|
||||
|
||||
#Get any available read/write port in case only a single write or read ports is being characterized.
|
||||
cur_read_port = self.get_available_port(get_read_port=True)
|
||||
|
|
@ -969,24 +1011,24 @@ class delay():
|
|||
debug.info(1,"Dynamic Power: {0} mW".format(power.dynamic))
|
||||
debug.info(1,"Leakage Power: {0} mW".format(power.leakage))
|
||||
|
||||
data = {"min_period": 0,
|
||||
"delay_lh0": delay_lh,
|
||||
"delay_hl0": delay_hl,
|
||||
"slew_lh0": slew_lh,
|
||||
"slew_hl0": slew_hl,
|
||||
"read0_power0": power.dynamic,
|
||||
"read1_power0": power.dynamic,
|
||||
"write0_power0": power.dynamic,
|
||||
"write1_power0": power.dynamic,
|
||||
"leakage_power": power.leakage
|
||||
}
|
||||
return data
|
||||
sram_data = { "min_period": 0,
|
||||
"leakage_power": power.leakage}
|
||||
port_data = [{"delay_lh": delay_lh,
|
||||
"delay_hl": delay_hl,
|
||||
"slew_lh": slew_lh,
|
||||
"slew_hl": slew_hl,
|
||||
"read0_power": power.dynamic,
|
||||
"read1_power": power.dynamic,
|
||||
"write0_power": power.dynamic,
|
||||
"write1_power": power.dynamic,
|
||||
}]
|
||||
return (sram_data,port_data)
|
||||
|
||||
def gen_data(self):
|
||||
""" Generates the PWL data inputs for a simulation timing test. """
|
||||
for write_port in self.write_ports:
|
||||
for i in range(self.word_size):
|
||||
sig_name="DIN{0}[{1}] ".format(write_port, i)
|
||||
sig_name="{0}{1}_{2} ".format(self.din_name,write_port, i)
|
||||
self.stim.gen_pwl(sig_name, self.cycle_times, self.data_values[write_port][i], self.period, self.slew, 0.05)
|
||||
|
||||
def gen_addr(self):
|
||||
|
|
@ -996,46 +1038,20 @@ class delay():
|
|||
"""
|
||||
for port in range(self.total_port_num):
|
||||
for i in range(self.addr_size):
|
||||
sig_name = "A{0}[{1}]".format(port,i)
|
||||
sig_name = "{0}{1}_{2}".format(self.addr_name,port,i)
|
||||
self.stim.gen_pwl(sig_name, self.cycle_times, self.addr_values[port][i], self.period, self.slew, 0.05)
|
||||
|
||||
def gen_control(self):
|
||||
""" Generates the control signals """
|
||||
for port in range(self.total_port_num):
|
||||
self.stim.gen_pwl("CSB{0}".format(port), self.cycle_times, self.csb_values[port], self.period, self.slew, 0.05)
|
||||
if port in self.read_ports and port in self.write_ports:
|
||||
self.stim.gen_pwl("WEB{0}".format(port), self.cycle_times, self.web_values[port], self.period, self.slew, 0.05)
|
||||
|
||||
for readwrite_port in range(self.readwrite_port_num):
|
||||
self.stim.gen_pwl("WEB{0}".format(readwrite_port), self.cycle_times, self.web_values[readwrite_port], self.period, self.slew, 0.05)
|
||||
|
||||
|
||||
def create_port_names(self):
|
||||
"""Generates the port names to be used in characterization and sets default simulation target ports"""
|
||||
self.write_ports = []
|
||||
self.read_ports = []
|
||||
self.total_port_num = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports
|
||||
|
||||
#save a member variable to avoid accessing global. readwrite ports have different control signals.
|
||||
self.readwrite_port_num = OPTS.num_rw_ports
|
||||
|
||||
#Generate the port names. readwrite ports are required to be added first for this to work.
|
||||
for readwrite_port_num in range(OPTS.num_rw_ports):
|
||||
self.read_ports.append(readwrite_port_num)
|
||||
self.write_ports.append(readwrite_port_num)
|
||||
#This placement is intentional. It makes indexing input data easier. See self.data_values
|
||||
for write_port_num in range(OPTS.num_rw_ports, OPTS.num_rw_ports+OPTS.num_w_ports):
|
||||
self.write_ports.append(write_port_num)
|
||||
for read_port_num in range(OPTS.num_rw_ports+OPTS.num_w_ports, OPTS.num_rw_ports+OPTS.num_w_ports+OPTS.num_r_ports):
|
||||
self.read_ports.append(read_port_num)
|
||||
|
||||
#Set the default target ports for simulation. Default is all the ports.
|
||||
self.targ_read_ports = self.read_ports
|
||||
self.targ_write_ports = self.write_ports
|
||||
|
||||
def create_char_data_dict(self):
|
||||
"""Make a dict of lists for each type of measurement to append results to"""
|
||||
#Making this a member variable may not be the best option, but helps reduce code clutter
|
||||
self.char_data = {}
|
||||
for port in range(self.total_port_num):
|
||||
for m in ["delay_lh", "delay_hl", "slew_lh", "slew_hl", "read0_power",
|
||||
"read1_power", "write0_power", "write1_power"]:
|
||||
self.char_data ["{0}{1}".format(m,port)]=[]
|
||||
def get_empty_measure_data_dict(self):
|
||||
"""Make a dict of lists for each type of delay and power measurement to append results to"""
|
||||
measure_names = self.delay_meas_names + self.power_meas_names
|
||||
#Create list of dicts. List lengths is # of ports. Each dict maps the measurement names to lists.
|
||||
measure_data = [{mname:[] for mname in measure_names} for i in range(self.total_port_num)]
|
||||
return measure_data
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
||||
|
|
@ -12,10 +12,6 @@ class lib:
|
|||
""" lib file generation."""
|
||||
|
||||
def __init__(self, out_dir, sram, sp_file, use_model=OPTS.analytical_delay):
|
||||
#Temporary Workaround to here to set num of ports. Crashes if set in config file.
|
||||
#OPTS.num_rw_ports = 2
|
||||
#OPTS.num_r_ports = 1
|
||||
#OPTS.num_w_ports = 1
|
||||
|
||||
self.out_dir = out_dir
|
||||
self.sram = sram
|
||||
|
|
@ -161,7 +157,7 @@ class lib:
|
|||
# Leakage is included in dynamic when macro is enabled
|
||||
self.lib.write(" leakage_power () {\n")
|
||||
self.lib.write(" when : \"{0}\";\n".format(control_str))
|
||||
self.lib.write(" value : {};\n".format(self.char_results["leakage_power"]))
|
||||
self.lib.write(" value : {};\n".format(self.char_sram_results["leakage_power"]))
|
||||
self.lib.write(" }\n")
|
||||
self.lib.write(" cell_leakage_power : {};\n".format(0))
|
||||
|
||||
|
|
@ -347,16 +343,16 @@ class lib:
|
|||
self.lib.write(" related_pin : \"clk\"; \n")
|
||||
self.lib.write(" timing_type : rising_edge; \n")
|
||||
self.lib.write(" cell_rise(CELL_TABLE) {\n")
|
||||
self.write_values(self.char_results["delay_lh{0}".format(read_port)],len(self.loads)," ")
|
||||
self.write_values(self.char_port_results[read_port]["delay_lh"],len(self.loads)," ")
|
||||
self.lib.write(" }\n") # rise delay
|
||||
self.lib.write(" cell_fall(CELL_TABLE) {\n")
|
||||
self.write_values(self.char_results["delay_hl{0}".format(read_port)],len(self.loads)," ")
|
||||
self.write_values(self.char_port_results[read_port]["delay_hl"],len(self.loads)," ")
|
||||
self.lib.write(" }\n") # fall delay
|
||||
self.lib.write(" rise_transition(CELL_TABLE) {\n")
|
||||
self.write_values(self.char_results["slew_lh{0}".format(read_port)],len(self.loads)," ")
|
||||
self.write_values(self.char_port_results[read_port]["slew_lh"],len(self.loads)," ")
|
||||
self.lib.write(" }\n") # rise trans
|
||||
self.lib.write(" fall_transition(CELL_TABLE) {\n")
|
||||
self.write_values(self.char_results["slew_hl{0}".format(read_port)],len(self.loads)," ")
|
||||
self.write_values(self.char_port_results[read_port]["slew_hl"],len(self.loads)," ")
|
||||
self.lib.write(" }\n") # fall trans
|
||||
self.lib.write(" }\n") # timing
|
||||
self.lib.write(" }\n") # pin
|
||||
|
|
@ -428,8 +424,8 @@ class lib:
|
|||
for port in range(self.total_port_num):
|
||||
self.add_clk_control_power(port)
|
||||
|
||||
min_pulse_width = round_time(self.char_results["min_period"])/2.0
|
||||
min_period = round_time(self.char_results["min_period"])
|
||||
min_pulse_width = round_time(self.char_sram_results["min_period"])/2.0
|
||||
min_period = round_time(self.char_sram_results["min_period"])
|
||||
self.lib.write(" timing(){ \n")
|
||||
self.lib.write(" timing_type :\"min_pulse_width\"; \n")
|
||||
self.lib.write(" related_pin : clk; \n")
|
||||
|
|
@ -461,7 +457,7 @@ class lib:
|
|||
if port in self.write_ports:
|
||||
if port in self.read_ports:
|
||||
web_name = " & !WEb{0}".format(port)
|
||||
avg_write_power = np.mean(self.char_results["write1_power{0}".format(port)] + self.char_results["write0_power{0}".format(port)])
|
||||
avg_write_power = np.mean(self.char_port_results[port]["write1_power"] + self.char_port_results[port]["write0_power"])
|
||||
self.lib.write(" internal_power(){\n")
|
||||
self.lib.write(" when : \"!CSb{0} & clk{1}\"; \n".format(port, web_name))
|
||||
self.lib.write(" rise_power(scalar){\n")
|
||||
|
|
@ -475,7 +471,7 @@ class lib:
|
|||
if port in self.read_ports:
|
||||
if port in self.write_ports:
|
||||
web_name = " & WEb{0}".format(port)
|
||||
avg_read_power = np.mean(self.char_results["read1_power{0}".format(port)] + self.char_results["read0_power{0}".format(port)])
|
||||
avg_read_power = np.mean(self.char_port_results[port]["read1_power"] + self.char_port_results[port]["read0_power"])
|
||||
self.lib.write(" internal_power(){\n")
|
||||
self.lib.write(" when : \"!CSb{0} & !clk{1}\"; \n".format(port, web_name))
|
||||
self.lib.write(" rise_power(scalar){\n")
|
||||
|
|
@ -502,13 +498,14 @@ class lib:
|
|||
if not hasattr(self,"d"):
|
||||
self.d = delay(self.sram, self.sp_file, self.corner)
|
||||
if self.use_model:
|
||||
self.char_results = self.d.analytical_delay(self.sram,self.slews,self.loads)
|
||||
char_results = self.d.analytical_delay(self.sram,self.slews,self.loads)
|
||||
self.char_sram_results, self.char_port_results = char_results
|
||||
else:
|
||||
probe_address = "1" * self.sram.addr_size
|
||||
probe_data = self.sram.word_size - 1
|
||||
self.char_results = self.d.analyze(probe_address, probe_data, self.slews, self.loads)
|
||||
|
||||
|
||||
char_results = self.d.analyze(probe_address, probe_data, self.slews, self.loads)
|
||||
self.char_sram_results, self.char_port_results = char_results
|
||||
|
||||
def compute_setup_hold(self):
|
||||
""" Do the analysis if we haven't characterized a FF yet """
|
||||
# Do the analysis if we haven't characterized a FF yet
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
@ -28,39 +28,53 @@ class stimuli():
|
|||
|
||||
(self.process, self.voltage, self.temperature) = corner
|
||||
self.device_models = tech.spice["fet_models"][self.process]
|
||||
|
||||
|
||||
def inst_sram(self, abits, dbits, port_info, sram_name):
|
||||
def inst_sram(self, sram, port_signal_names, port_info, abits, dbits, sram_name):
|
||||
""" Function to instatiate an SRAM subckt. """
|
||||
pin_names = self.gen_pin_names(port_signal_names, port_info, abits, dbits)
|
||||
#Only checking length. This should check functionality as well (TODO) and/or import that information from the SRAM
|
||||
debug.check(len(sram.pins) == len(pin_names), "Number of pins generated for characterization do match pins of SRAM\nsram.pins = {0}\npin_names = {1}".format(sram.pins,pin_names))
|
||||
|
||||
self.sf.write("Xsram ")
|
||||
|
||||
#Un-tuple the port names. This was done to avoid passing them all as arguments. Could be improved still.
|
||||
#This should be generated from the pin list of the sram... change when multiport pins done.
|
||||
(total_port_num,readwrite_num,read_ports,write_ports) = port_info
|
||||
|
||||
for write_input in write_ports:
|
||||
for i in range(dbits):
|
||||
self.sf.write("DIN{0}[{1}] ".format(write_input, i))
|
||||
|
||||
for port in range(total_port_num):
|
||||
for i in range(abits):
|
||||
self.sf.write("A{0}[{1}] ".format(port,i))
|
||||
|
||||
#These control signals assume 6t sram i.e. a single readwrite port. If multiple readwrite ports are used then add more
|
||||
#control signals. Not sure if this is correct, consider a temporary change until control signals for multiport are finalized.
|
||||
for port in range(total_port_num):
|
||||
self.sf.write("CSB{0} ".format(port))
|
||||
for readwrite_port in range(readwrite_num):
|
||||
self.sf.write("WEB{0} ".format(readwrite_port))
|
||||
|
||||
self.sf.write("{0} ".format(tech.spice["clk"]))
|
||||
for read_output in read_ports:
|
||||
for i in range(dbits):
|
||||
self.sf.write("DOUT{0}[{1}] ".format(read_output, i))
|
||||
self.sf.write("{0} {1} ".format(self.vdd_name, self.gnd_name))
|
||||
for pin in pin_names:
|
||||
self.sf.write("{0} ".format(pin))
|
||||
self.sf.write("{0}\n".format(sram_name))
|
||||
|
||||
def gen_pin_names(self, port_signal_names, port_info, abits, dbits):
|
||||
"""Creates the pins names of the SRAM based on the no. of ports."""
|
||||
#This may seem redundant as the pin names are already defined in the sram. However, it is difficult to extract the
|
||||
#functionality from the names, so they are recreated. As the order is static, changing the order of the pin names
|
||||
#will cause issues here.
|
||||
pin_names = []
|
||||
(addr_name, din_name, dout_name) = port_signal_names
|
||||
(total_ports, write_index, read_index) = port_info
|
||||
|
||||
for write_input in write_index:
|
||||
for i in range(dbits):
|
||||
pin_names.append("{0}{1}_{2}".format(din_name,write_input, i))
|
||||
|
||||
for port in range(total_ports):
|
||||
for i in range(abits):
|
||||
pin_names.append("{0}{1}_{2}".format(addr_name,port,i))
|
||||
|
||||
#Control signals not finalized.
|
||||
for port in range(total_ports):
|
||||
pin_names.append("CSB{0}".format(port))
|
||||
for port in range(total_ports):
|
||||
if (port in read_index) and (port in write_index):
|
||||
pin_names.append("WEB{0}".format(port))
|
||||
|
||||
for port in range(total_ports):
|
||||
pin_names.append("{0}{1}".format(tech.spice["clk"], port))
|
||||
|
||||
for read_output in read_index:
|
||||
for i in range(dbits):
|
||||
pin_names.append("{0}{1}_{2}".format(dout_name,read_output, i))
|
||||
|
||||
pin_names.append("{0}".format(self.vdd_name))
|
||||
pin_names.append("{0}".format(self.gnd_name))
|
||||
return pin_names
|
||||
|
||||
def inst_model(self, pins, model_name):
|
||||
""" Function to instantiate a generic model with a set of pins """
|
||||
self.sf.write("X{0} ".format(model_name))
|
||||
|
|
@ -153,7 +167,7 @@ class stimuli():
|
|||
to the initial value.
|
||||
"""
|
||||
# the initial value is not a clock time
|
||||
debug.check(len(clk_times)==len(data_values),"Clock and data value lengths don't match.")
|
||||
debug.check(len(clk_times)==len(data_values),"Clock and data value lengths don't match. {0} clock values, {1} data values for {2}".format(len(clk_times), len(data_values), sig_name))
|
||||
|
||||
# shift signal times earlier for setup time
|
||||
times = np.array(clk_times) - setup*period
|
||||
|
|
@ -213,6 +227,10 @@ class stimuli():
|
|||
power_exp,
|
||||
t_initial,
|
||||
t_final))
|
||||
|
||||
def gen_meas_value(self, meas_name, dout, t_intital, t_final):
|
||||
measure_string=".meas tran {0} AVG v({1}) FROM={2}n TO={3}n\n\n".format(meas_name, dout, t_intital, t_final)
|
||||
self.sf.write(measure_string)
|
||||
|
||||
def write_control(self, end_time):
|
||||
""" Write the control cards to run and end the simulation """
|
||||
|
|
@ -255,12 +273,15 @@ class stimuli():
|
|||
|
||||
def write_supply(self):
|
||||
""" Writes supply voltage statements """
|
||||
self.sf.write("V{0} {0} 0.0 {1}\n".format(self.vdd_name, self.voltage))
|
||||
self.sf.write("V{0} {0} 0.0 {1}\n".format(self.gnd_name, 0))
|
||||
gnd_node_name = "0"
|
||||
self.sf.write("V{0} {0} {1} {2}\n".format(self.vdd_name, gnd_node_name, self.voltage))
|
||||
# This is for the test power supply
|
||||
self.sf.write("V{0} {0} 0.0 {1}\n".format("test"+self.vdd_name, self.voltage))
|
||||
self.sf.write("V{0} {0} 0.0 {1}\n".format("test"+self.gnd_name, 0))
|
||||
self.sf.write("V{0} {0} {1} {2}\n".format("test"+self.vdd_name, gnd_node_name, self.voltage))
|
||||
self.sf.write("V{0} {0} {1} {2}\n".format("test"+self.gnd_name, gnd_node_name, 0.0))
|
||||
|
||||
#Adding a commented out supply for simulators where gnd and 0 are not global grounds.
|
||||
self.sf.write("\n*Nodes gnd and 0 are the same global ground node in ngspice/hspice/xa. Otherwise, this source may be needed.\n")
|
||||
self.sf.write("*V{0} {0} {1} {2}\n".format(self.gnd_name, gnd_node_name, 0.0))
|
||||
|
||||
def run_sim(self):
|
||||
""" Run hspice in batch mode and output rawfile to parse. """
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import debug
|
||||
from math import log
|
||||
import re
|
||||
|
||||
class trim_spice():
|
||||
"""
|
||||
|
|
@ -73,25 +74,28 @@ class trim_spice():
|
|||
self.sp_buffer.insert(0, "* It should NOT be used for LVS!!")
|
||||
self.sp_buffer.insert(0, "* WARNING: This is a TRIMMED NETLIST.")
|
||||
|
||||
self.remove_insts("bitcell_array",[wl_name,bl_name])
|
||||
|
||||
wl_regex = r"wl\d*\[{}\]".format(wl_address)
|
||||
bl_regex = r"bl\d*\[{}\]".format(int(self.words_per_row*data_bit + col_address))
|
||||
self.remove_insts("bitcell_array",[wl_regex,bl_regex])
|
||||
|
||||
# 2. Keep sense amps basd on BL
|
||||
# FIXME: The bit lines are not indexed the same in sense_amp_array
|
||||
#self.remove_insts("sense_amp_array",[bl_name])
|
||||
#self.remove_insts("sense_amp_array",[bl_regex])
|
||||
|
||||
# 3. Keep column muxes basd on BL
|
||||
self.remove_insts("column_mux_array",[bl_name])
|
||||
self.remove_insts("column_mux_array",[bl_regex])
|
||||
|
||||
# 4. Keep write driver based on DATA
|
||||
data_name = "data[{}]".format(data_bit)
|
||||
self.remove_insts("write_driver_array",[data_name])
|
||||
data_regex = r"data\[{}\]".format(data_bit)
|
||||
self.remove_insts("write_driver_array",[data_regex])
|
||||
|
||||
# 5. Keep wordline driver based on WL
|
||||
# Need to keep the gater too
|
||||
#self.remove_insts("wordline_driver",wl_name)
|
||||
#self.remove_insts("wordline_driver",wl_regex)
|
||||
|
||||
# 6. Keep precharges based on BL
|
||||
self.remove_insts("precharge_array",[bl_name])
|
||||
self.remove_insts("precharge_array",[bl_regex])
|
||||
|
||||
# Everything else isn't worth removing. :)
|
||||
|
||||
|
|
@ -107,6 +111,9 @@ class trim_spice():
|
|||
match of the line with a term so you can search for a single
|
||||
net connection, the instance name, anything..
|
||||
"""
|
||||
#Expects keep_inst_list are regex patterns. Compile them here.
|
||||
compiled_patterns = [re.compile(pattern) for pattern in keep_inst_list]
|
||||
|
||||
start_name = ".SUBCKT {}".format(subckt_name)
|
||||
end_name = ".ENDS {}".format(subckt_name)
|
||||
|
||||
|
|
@ -120,8 +127,8 @@ class trim_spice():
|
|||
new_buffer.append(line)
|
||||
in_subckt=False
|
||||
elif in_subckt:
|
||||
for k in keep_inst_list:
|
||||
if k in line:
|
||||
for pattern in compiled_patterns:
|
||||
if pattern.search(line) != None:
|
||||
new_buffer.append(line)
|
||||
break
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -10,10 +10,10 @@ temperatures = [25]
|
|||
output_path = "temp"
|
||||
output_name = "sram_{0}_{1}_{2}_{3}".format(word_size,num_words,num_banks,tech_name)
|
||||
|
||||
#Below are some additions to test additional ports on sram
|
||||
#bitcell = "pbitcell"
|
||||
|
||||
# These are the configuration parameters
|
||||
#rw_ports = 2
|
||||
#r_ports = 2
|
||||
#w_ports = 2
|
||||
#Setting for multiport
|
||||
# netlist_only = True
|
||||
# bitcell = "pbitcell"
|
||||
# replica_bitcell="replica_pbitcell"
|
||||
# num_rw_ports = 1
|
||||
# num_r_ports = 0
|
||||
# num_w_ports = 1
|
||||
|
|
|
|||
|
|
@ -2,10 +2,18 @@ word_size = 2
|
|||
num_words = 16
|
||||
num_banks = 1
|
||||
|
||||
tech_name = "scn3me_subm"
|
||||
tech_name = "scn4m_subm"
|
||||
process_corners = ["TT"]
|
||||
supply_voltages = [ 5.0 ]
|
||||
temperatures = [ 25 ]
|
||||
|
||||
output_path = "temp"
|
||||
output_name = "sram_{0}_{1}_{2}_{3}".format(word_size,num_words,num_banks,tech_name)
|
||||
|
||||
#Setting for multiport
|
||||
# netlist_only = True
|
||||
# bitcell = "pbitcell"
|
||||
# replica_bitcell="replica_pbitcell"
|
||||
# num_rw_ports = 1
|
||||
# num_r_ports = 1
|
||||
# num_w_ports = 0
|
||||
|
|
@ -74,10 +74,12 @@ def print_banner():
|
|||
print("|=========" + name.center(60) + "=========|")
|
||||
print("|=========" + " ".center(60) + "=========|")
|
||||
print("|=========" + "VLSI Design and Automation Lab".center(60) + "=========|")
|
||||
print("|=========" + "University of California Santa Cruz CE Department".center(60) + "=========|")
|
||||
print("|=========" + "Computer Science and Engineering Department".center(60) + "=========|")
|
||||
print("|=========" + "University of California Santa Cruz".center(60) + "=========|")
|
||||
print("|=========" + " ".center(60) + "=========|")
|
||||
print("|=========" + "VLSI Computer Architecture Research Group".center(60) + "=========|")
|
||||
print("|=========" + "Oklahoma State University ECE Department".center(60) + "=========|")
|
||||
print("|=========" + "Electrical and Computer Engineering Department".center(60) + "=========|")
|
||||
print("|=========" + "Oklahoma State University".center(60) + "=========|")
|
||||
print("|=========" + " ".center(60) + "=========|")
|
||||
user_info = "Usage help: openram-user-group@ucsc.edu"
|
||||
print("|=========" + user_info.center(60) + "=========|")
|
||||
|
|
@ -223,13 +225,17 @@ def read_config(config_file, is_unit_test=True):
|
|||
|
||||
# If config didn't set output name, make a reasonable default.
|
||||
if (OPTS.output_name == ""):
|
||||
OPTS.output_name = "sram_{0}b_{1}w_{2}bank_{3}rw_{4}w_{5}r_{6}".format(OPTS.word_size,
|
||||
OPTS.num_words,
|
||||
OPTS.num_banks,
|
||||
OPTS.num_rw_ports,
|
||||
OPTS.num_w_ports,
|
||||
OPTS.num_r_ports,
|
||||
OPTS.tech_name)
|
||||
ports = ""
|
||||
if OPTS.num_rw_ports>0:
|
||||
ports += "{}rw_".format(OPTS.num_rw_ports)
|
||||
if OPTS.num_w_ports>0:
|
||||
ports += "{}w_".format(OPTS.num_w_ports)
|
||||
if OPTS.num_r_ports>0:
|
||||
ports += "{}r_".format(OPTS.num_r_ports)
|
||||
OPTS.output_name = "sram_{0}b_{1}_{2}{3}".format(OPTS.word_size,
|
||||
OPTS.num_words,
|
||||
ports,
|
||||
OPTS.tech_name)
|
||||
|
||||
|
||||
|
||||
|
|
@ -387,8 +393,6 @@ def report_status():
|
|||
debug.error("{0} is not an integer in config file.".format(OPTS.word_size))
|
||||
if type(OPTS.num_words)!=int:
|
||||
debug.error("{0} is not an integer in config file.".format(OPTS.sram_size))
|
||||
if type(OPTS.num_banks)!=int:
|
||||
debug.error("{0} is not an integer in config file.".format(OPTS.num_banks))
|
||||
|
||||
if not OPTS.tech_name:
|
||||
debug.error("Tech name must be specified in config file.")
|
||||
|
|
|
|||
|
|
@ -29,10 +29,6 @@ class bank(design.design):
|
|||
design.design.__init__(self, name)
|
||||
debug.info(2, "create sram of size {0} with {1} words".format(self.word_size,self.num_words))
|
||||
|
||||
|
||||
self.total_write = OPTS.num_rw_ports + OPTS.num_w_ports
|
||||
self.total_read = OPTS.num_rw_ports + OPTS.num_r_ports
|
||||
self.total_ports = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports
|
||||
|
||||
# The local control signals are gated when we have bank select logic,
|
||||
# so this prefix will be added to all of the input signals to create
|
||||
|
|
@ -53,6 +49,7 @@ class bank(design.design):
|
|||
self.add_modules()
|
||||
self.create_modules()
|
||||
|
||||
|
||||
def create_layout(self):
|
||||
self.place_modules()
|
||||
self.setup_routing_constraints()
|
||||
|
|
@ -65,19 +62,9 @@ class bank(design.design):
|
|||
self.bank_center=self.offset_all_coordinates().scale(-1,-1)
|
||||
|
||||
self.DRC_LVS()
|
||||
|
||||
|
||||
|
||||
def add_pins(self):
|
||||
self.read_index = []
|
||||
port_number = 0
|
||||
for port in range(OPTS.num_rw_ports):
|
||||
self.read_index.append("{}".format(port_number))
|
||||
port_number += 1
|
||||
for port in range(OPTS.num_w_ports):
|
||||
port_number += 1
|
||||
for port in range(OPTS.num_r_ports):
|
||||
self.read_index.append("{}".format(port_number))
|
||||
port_number += 1
|
||||
|
||||
""" Adding pins for Bank module"""
|
||||
for port in range(self.total_read):
|
||||
for bit in range(self.word_size):
|
||||
|
|
@ -98,11 +85,13 @@ class bank(design.design):
|
|||
self.add_pin("s_en{0}".format(self.read_index[port]), "INPUT")
|
||||
for port in range(self.total_write):
|
||||
self.add_pin("w_en{0}".format(port), "INPUT")
|
||||
for pin in ["clk_buf_bar","clk_buf"]:
|
||||
self.add_pin(pin,"INPUT")
|
||||
for port in range(self.total_ports):
|
||||
self.add_pin("clk_buf_bar{0}".format(port),"INPUT")
|
||||
self.add_pin("clk_buf{0}".format(port),"INPUT")
|
||||
self.add_pin("vdd","POWER")
|
||||
self.add_pin("gnd","GROUND")
|
||||
|
||||
|
||||
def route_layout(self):
|
||||
""" Create routing amoung the modules """
|
||||
self.route_central_bus()
|
||||
|
|
@ -119,6 +108,7 @@ class bank(design.design):
|
|||
self.route_bank_select()
|
||||
|
||||
self.route_vdd_gnd()
|
||||
|
||||
|
||||
def create_modules(self):
|
||||
""" Add modules. The order should not matter! """
|
||||
|
|
@ -156,10 +146,10 @@ class bank(design.design):
|
|||
self.place_row_decoder()
|
||||
self.place_wordline_driver()
|
||||
self.place_column_decoder()
|
||||
|
||||
|
||||
self.place_bank_select()
|
||||
|
||||
|
||||
|
||||
def compute_sizes(self):
|
||||
""" Computes the required sizes to create the bank """
|
||||
|
||||
|
|
@ -181,13 +171,25 @@ class bank(design.design):
|
|||
# Number of control lines in the bus
|
||||
self.num_control_lines = 4
|
||||
# The order of the control signals on the control bus:
|
||||
self.input_control_signals = ["clk_buf", "clk_buf_bar", "w_en0", "s_en0"]
|
||||
self.input_control_signals = []
|
||||
port_num = 0
|
||||
for port in range(OPTS.num_rw_ports):
|
||||
self.input_control_signals.append(["clk_buf{}".format(port_num), "clk_buf_bar{}".format(port_num), "w_en{}".format(port_num), "s_en{}".format(port_num)])
|
||||
port_num += 1
|
||||
for port in range(OPTS.num_w_ports):
|
||||
self.input_control_signals.append(["clk_buf{}".format(port_num), "clk_buf_bar{}".format(port_num), "w_en{}".format(port_num)])
|
||||
port_num += 1
|
||||
for port in range(OPTS.num_r_ports):
|
||||
self.input_control_signals.append(["clk_buf{}".format(port_num), "clk_buf_bar{}".format(port_num), "s_en{}".format(port_num)])
|
||||
port_num += 1
|
||||
|
||||
# These will be outputs of the gaters if this is multibank, if not, normal signals.
|
||||
if self.num_banks > 1:
|
||||
self.control_signals = ["gated_"+str for str in self.input_control_signals]
|
||||
else:
|
||||
self.control_signals = self.input_control_signals
|
||||
self.control_signals = []
|
||||
for port in range(self.total_ports):
|
||||
if self.num_banks > 1:
|
||||
self.control_signals.append(["gated_"+str for str in self.input_control_signals[port]])
|
||||
else:
|
||||
self.control_signals.append(self.input_control_signals[port])
|
||||
# The central bus is the column address (one hot) and row address (binary)
|
||||
if self.col_addr_size>0:
|
||||
self.num_col_addr_lines = 2**self.col_addr_size
|
||||
|
|
@ -247,8 +249,8 @@ class bank(design.design):
|
|||
for port in range(self.total_ports):
|
||||
self.column_mux_array.append(self.mod_column_mux_array(columns=self.num_cols,
|
||||
word_size=self.word_size,
|
||||
bitcell_bl=self.read_bl_list[port],
|
||||
bitcell_br=self.read_br_list[port]))
|
||||
bitcell_bl=self.total_bl_list[port],
|
||||
bitcell_br=self.total_br_list[port]))
|
||||
self.add_mod(self.column_mux_array[port])
|
||||
|
||||
|
||||
|
|
@ -292,6 +294,7 @@ class bank(design.design):
|
|||
temp.append("gnd")
|
||||
self.connect_inst(temp)
|
||||
|
||||
|
||||
def place_bitcell_array(self):
|
||||
""" Placing Bitcell Array """
|
||||
self.bitcell_array_inst.place(vector(0,0))
|
||||
|
|
@ -308,9 +311,10 @@ class bank(design.design):
|
|||
for i in range(self.num_cols):
|
||||
temp.append(self.read_bl_list[port]+"[{0}]".format(i))
|
||||
temp.append(self.read_br_list[port]+"[{0}]".format(i))
|
||||
temp.extend([self.prefix+"clk_buf_bar", "vdd"])
|
||||
temp.extend([self.prefix+"clk_buf_bar{0}".format(self.read_index[port]), "vdd"])
|
||||
self.connect_inst(temp)
|
||||
|
||||
|
||||
def place_precharge_array(self):
|
||||
""" Placing Precharge """
|
||||
|
||||
|
|
@ -320,6 +324,7 @@ class bank(design.design):
|
|||
# The enclosure is for the well and the spacing is to the bitcell wells
|
||||
y_offset = self.bitcell_array.height + self.m2_gap
|
||||
self.precharge_array_inst[port].place(vector(0,y_offset))
|
||||
|
||||
|
||||
def create_column_mux_array(self):
|
||||
""" Creating Column Mux when words_per_row > 1 . """
|
||||
|
|
@ -343,6 +348,7 @@ class bank(design.design):
|
|||
temp.append("gnd")
|
||||
self.connect_inst(temp)
|
||||
|
||||
|
||||
def place_column_mux_array(self):
|
||||
""" Placing Column Mux when words_per_row > 1 . """
|
||||
if self.col_addr_size > 0:
|
||||
|
|
@ -354,6 +360,7 @@ class bank(design.design):
|
|||
for port in range(self.total_ports):
|
||||
y_offset = self.column_mux_height
|
||||
self.col_mux_array_inst[port].place(vector(0,y_offset).scale(-1,-1))
|
||||
|
||||
|
||||
def create_sense_amp_array(self):
|
||||
""" Creating Sense amp """
|
||||
|
|
@ -373,9 +380,10 @@ class bank(design.design):
|
|||
temp.append(self.read_bl_list[port]+"_out[{0}]".format(bit))
|
||||
temp.append(self.read_br_list[port]+"_out[{0}]".format(bit))
|
||||
|
||||
temp.extend([self.prefix+"s_en{0}".format(port), "vdd", "gnd"])
|
||||
temp.extend([self.prefix+"s_en{}".format(self.read_index[port]), "vdd", "gnd"])
|
||||
self.connect_inst(temp)
|
||||
|
||||
|
||||
def place_sense_amp_array(self):
|
||||
""" Placing Sense amp """
|
||||
|
||||
|
|
@ -383,6 +391,7 @@ class bank(design.design):
|
|||
for port in range(self.total_read):
|
||||
y_offset = self.column_mux_height + self.sense_amp_array.height + self.m2_gap
|
||||
self.sense_amp_array_inst[port].place(vector(0,y_offset).scale(-1,-1))
|
||||
|
||||
|
||||
def create_write_driver_array(self):
|
||||
""" Creating Write Driver """
|
||||
|
|
@ -405,6 +414,7 @@ class bank(design.design):
|
|||
temp.extend([self.prefix+"w_en{0}".format(port), "vdd", "gnd"])
|
||||
self.connect_inst(temp)
|
||||
|
||||
|
||||
def place_write_driver_array(self):
|
||||
""" Placing Write Driver """
|
||||
|
||||
|
|
@ -413,7 +423,6 @@ class bank(design.design):
|
|||
y_offset = self.sense_amp_array.height + self.column_mux_height \
|
||||
+ self.m2_gap + self.write_driver_array.height
|
||||
self.write_driver_array_inst[port].place(vector(0,y_offset).scale(-1,-1))
|
||||
|
||||
|
||||
|
||||
def create_row_decoder(self):
|
||||
|
|
@ -432,6 +441,7 @@ class bank(design.design):
|
|||
temp.extend(["vdd", "gnd"])
|
||||
self.connect_inst(temp)
|
||||
|
||||
|
||||
def place_row_decoder(self):
|
||||
""" Place the hierarchical row decoder """
|
||||
|
||||
|
|
@ -460,11 +470,12 @@ class bank(design.design):
|
|||
temp.append("dec_out{0}[{1}]".format(port,row))
|
||||
for row in range(self.num_rows):
|
||||
temp.append(self.total_wl_list[port]+"[{0}]".format(row))
|
||||
temp.append(self.prefix+"clk_buf")
|
||||
temp.append(self.prefix+"clk_buf{0}".format(port))
|
||||
temp.append("vdd")
|
||||
temp.append("gnd")
|
||||
self.connect_inst(temp)
|
||||
|
||||
|
||||
def place_wordline_driver(self):
|
||||
""" Place the Wordline Driver """
|
||||
|
||||
|
|
@ -506,6 +517,7 @@ class bank(design.design):
|
|||
temp.extend(["vdd", "gnd"])
|
||||
self.connect_inst(temp)
|
||||
|
||||
|
||||
def place_column_decoder(self):
|
||||
"""
|
||||
Place a 2:4 or 3:8 column address decoder.
|
||||
|
|
@ -536,12 +548,13 @@ class bank(design.design):
|
|||
mod=self.bank_select))
|
||||
|
||||
temp = []
|
||||
temp.extend(self.input_control_signals)
|
||||
temp.extend(self.input_control_signals[port])
|
||||
temp.append("bank_sel{}".format(port))
|
||||
temp.extend(self.control_signals)
|
||||
temp.extend(self.control_signals[port])
|
||||
temp.extend(["vdd", "gnd"])
|
||||
self.connect_inst(temp)
|
||||
|
||||
|
||||
def place_bank_select(self):
|
||||
""" Place the bank select logic. """
|
||||
|
||||
|
|
@ -552,9 +565,9 @@ class bank(design.design):
|
|||
for port in range(self.total_ports):
|
||||
x_off = -(self.row_decoder.width + self.central_bus_width + self.wordline_driver.width)
|
||||
if self.col_addr_size > 0:
|
||||
y_off = min(self.col_decoder_inst[0].by(), self.col_mux_array_inst[0].by())
|
||||
y_off = min(self.col_decoder_inst[port].by(), self.col_mux_array_inst[port].by())
|
||||
else:
|
||||
y_off = self.row_decoder_inst[0].by()
|
||||
y_off = self.row_decoder_inst[port].by()
|
||||
y_off -= (self.bank_select.height + drc["well_to_well"])
|
||||
self.bank_select_pos = vector(x_off,y_off)
|
||||
self.bank_select_inst[port].place(self.bank_select_pos)
|
||||
|
|
@ -565,18 +578,30 @@ class bank(design.design):
|
|||
for inst in self.insts:
|
||||
self.copy_power_pins(inst,"vdd")
|
||||
self.copy_power_pins(inst,"gnd")
|
||||
|
||||
|
||||
def route_bank_select(self):
|
||||
""" Route the bank select logic. """
|
||||
|
||||
for port in range(self.total_ports):
|
||||
for input_name in self.input_control_signals+["bank_sel"]:
|
||||
self.copy_layout_pin(self.bank_select_inst[port], input_name)
|
||||
|
||||
for gated_name in self.control_signals:
|
||||
if self.port_id[port] == "rw":
|
||||
bank_sel_signals = ["clk_buf", "clk_buf_bar", "w_en", "s_en", "bank_sel"]
|
||||
gated_bank_sel_signals = ["gated_clk_buf", "gated_clk_buf_bar", "gated_w_en", "gated_s_en"]
|
||||
elif self.port_id[port] == "w":
|
||||
bank_sel_signals = ["clk_buf", "clk_buf_bar", "w_en", "bank_sel"]
|
||||
gated_bank_sel_signals = ["gated_clk_buf", "gated_clk_buf_bar", "gated_w_en"]
|
||||
else:
|
||||
bank_sel_signals = ["clk_buf", "clk_buf_bar", "s_en", "bank_sel"]
|
||||
gated_bank_sel_signals = ["gated_clk_buf", "gated_clk_buf_bar", "gated_s_en"]
|
||||
|
||||
copy_control_signals = self.input_control_signals[port]+["bank_sel{}".format(port)]
|
||||
for signal in range(len(copy_control_signals)):
|
||||
self.copy_layout_pin(self.bank_select_inst[port], bank_sel_signals[signal], copy_control_signals[signal])
|
||||
|
||||
for signal in range(len(gated_bank_sel_signals)):
|
||||
# Connect the inverter output to the central bus
|
||||
out_pos = self.bank_select_inst[port].get_pin(gated_name).rc()
|
||||
bus_pos = vector(self.bus_xoffset[gated_name].x, out_pos.y)
|
||||
out_pos = self.bank_select_inst[port].get_pin(gated_bank_sel_signals[signal]).rc()
|
||||
name = self.control_signals[port][signal]
|
||||
bus_pos = vector(self.bus_xoffset[name].x, out_pos.y)
|
||||
self.add_path("metal3",[out_pos, bus_pos])
|
||||
self.add_via_center(layers=("metal2", "via2", "metal3"),
|
||||
offset=bus_pos,
|
||||
|
|
@ -594,7 +619,8 @@ class bank(design.design):
|
|||
After the modules are instantiated, find the dimensions for the
|
||||
control bus, power ring, etc.
|
||||
"""
|
||||
|
||||
# FIXME: calculate for multiport
|
||||
|
||||
#The minimum point is either the bottom of the address flops,
|
||||
#the column decoder (if there is one).
|
||||
write_driver_min_y_offset = self.write_driver_array_inst[0].by() - 3*self.m2_pitch
|
||||
|
|
@ -628,7 +654,6 @@ class bank(design.design):
|
|||
self.height = ur.y - ll.y
|
||||
self.width = ur.x - ll.x
|
||||
|
||||
|
||||
|
||||
def route_central_bus(self):
|
||||
""" Create the address, supply, and control signal central bus lines. """
|
||||
|
|
@ -637,16 +662,16 @@ class bank(design.design):
|
|||
# and control lines.
|
||||
# The bank is at (0,0), so this is to the left of the y-axis.
|
||||
# 2 pitches on the right for vias/jogs to access the inputs
|
||||
control_bus_offset = vector(-self.m2_pitch * self.num_control_lines - self.m2_width, self.min_y_offset)
|
||||
control_bus_length = self.max_y_offset - self.min_y_offset
|
||||
self.bus_xoffset = self.create_bus(layer="metal2",
|
||||
pitch=self.m2_pitch,
|
||||
offset=control_bus_offset,
|
||||
names=self.control_signals,
|
||||
length=control_bus_length,
|
||||
vertical=True,
|
||||
make_pins=(self.num_banks==1))
|
||||
|
||||
for port in range(self.total_ports):
|
||||
control_bus_offset = vector(-self.m2_pitch * self.num_control_lines - self.m2_width, self.min_y_offset)
|
||||
control_bus_length = self.max_y_offset - self.min_y_offset
|
||||
self.bus_xoffset = self.create_bus(layer="metal2",
|
||||
pitch=self.m2_pitch,
|
||||
offset=control_bus_offset,
|
||||
names=self.control_signals[port],
|
||||
length=control_bus_length,
|
||||
vertical=True,
|
||||
make_pins=(self.num_banks==1))
|
||||
|
||||
|
||||
def route_precharge_to_bitcell_array(self):
|
||||
|
|
@ -687,7 +712,8 @@ class bank(design.design):
|
|||
vector(bitcell_bl.x,yoffset), bitcell_bl])
|
||||
self.add_path("metal2",[col_mux_br, vector(col_mux_br.x,yoffset),
|
||||
vector(bitcell_br.x,yoffset), bitcell_br])
|
||||
|
||||
|
||||
|
||||
def route_sense_amp_to_col_mux_or_bitcell_array(self):
|
||||
""" Routing of BL and BR between sense_amp and column mux or bitcell array """
|
||||
|
||||
|
|
@ -711,61 +737,61 @@ class bank(design.design):
|
|||
vector(connect_bl.x,yoffset), connect_bl])
|
||||
self.add_path("metal2",[sense_amp_br, vector(sense_amp_br.x,yoffset),
|
||||
vector(connect_br.x,yoffset), connect_br])
|
||||
|
||||
|
||||
|
||||
|
||||
def route_sense_amp_out(self):
|
||||
""" Add pins for the sense amp output """
|
||||
|
||||
# FIXME: Update for multiport
|
||||
for bit in range(self.word_size):
|
||||
data_pin = self.sense_amp_array_inst[0].get_pin("data[{}]".format(bit))
|
||||
self.add_layout_pin_rect_center(text="dout0[{}]".format(bit),
|
||||
layer=data_pin.layer,
|
||||
offset=data_pin.center(),
|
||||
height=data_pin.height(),
|
||||
width=data_pin.width())
|
||||
|
||||
for port in range(self.total_read):
|
||||
for bit in range(self.word_size):
|
||||
data_pin = self.sense_amp_array_inst[port].get_pin("data[{}]".format(bit))
|
||||
self.add_layout_pin_rect_center(text="dout{0}[{1}]".format(self.read_index[port],bit),
|
||||
layer=data_pin.layer,
|
||||
offset=data_pin.center(),
|
||||
height=data_pin.height(),
|
||||
width=data_pin.width())
|
||||
|
||||
|
||||
def route_row_decoder(self):
|
||||
""" Routes the row decoder inputs and supplies """
|
||||
|
||||
# FIXME: Update for multiport
|
||||
# Create inputs for the row address lines
|
||||
for row in range(self.row_addr_size):
|
||||
addr_idx = row + self.col_addr_size
|
||||
decoder_name = "addr[{}]".format(row)
|
||||
addr_name = "addr0[{}]".format(addr_idx)
|
||||
self.copy_layout_pin(self.row_decoder_inst[0], decoder_name, addr_name)
|
||||
for port in range(self.total_ports):
|
||||
for row in range(self.row_addr_size):
|
||||
addr_idx = row + self.col_addr_size
|
||||
decoder_name = "addr[{}]".format(row)
|
||||
addr_name = "addr{0}[{1}]".format(port,addr_idx)
|
||||
self.copy_layout_pin(self.row_decoder_inst[port], decoder_name, addr_name)
|
||||
|
||||
|
||||
def route_write_driver(self):
|
||||
""" Connecting write driver """
|
||||
|
||||
for row in range(self.word_size):
|
||||
data_name = "data[{}]".format(row)
|
||||
din_name = "din0[{}]".format(row)
|
||||
self.copy_layout_pin(self.write_driver_array_inst[0], data_name, din_name)
|
||||
|
||||
for port in range(self.total_ports):
|
||||
for row in range(self.word_size):
|
||||
data_name = "data[{}]".format(row)
|
||||
din_name = "din{0}[{1}]".format(port,row)
|
||||
self.copy_layout_pin(self.write_driver_array_inst[port], data_name, din_name)
|
||||
|
||||
|
||||
def route_wordline_driver(self):
|
||||
""" Connecting Wordline driver output to Bitcell WL connection """
|
||||
for port in range(self.total_ports):
|
||||
for row in range(self.num_rows):
|
||||
# The pre/post is to access the pin from "outside" the cell to avoid DRCs
|
||||
decoder_out_pos = self.row_decoder_inst[port].get_pin("decode[{}]".format(row)).rc()
|
||||
driver_in_pos = self.wordline_driver_inst[port].get_pin("in[{}]".format(row)).lc()
|
||||
mid1 = decoder_out_pos.scale(0.5,1)+driver_in_pos.scale(0.5,0)
|
||||
mid2 = decoder_out_pos.scale(0.5,0)+driver_in_pos.scale(0.5,1)
|
||||
self.add_path("metal1", [decoder_out_pos, mid1, mid2, driver_in_pos])
|
||||
|
||||
for row in range(self.num_rows):
|
||||
# The pre/post is to access the pin from "outside" the cell to avoid DRCs
|
||||
decoder_out_pos = self.row_decoder_inst[0].get_pin("decode[{}]".format(row)).rc()
|
||||
driver_in_pos = self.wordline_driver_inst[0].get_pin("in[{}]".format(row)).lc()
|
||||
mid1 = decoder_out_pos.scale(0.5,1)+driver_in_pos.scale(0.5,0)
|
||||
mid2 = decoder_out_pos.scale(0.5,0)+driver_in_pos.scale(0.5,1)
|
||||
self.add_path("metal1", [decoder_out_pos, mid1, mid2, driver_in_pos])
|
||||
|
||||
# The mid guarantees we exit the input cell to the right.
|
||||
driver_wl_pos = self.wordline_driver_inst[0].get_pin("wl[{}]".format(row)).rc()
|
||||
bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.total_wl_list[0]+"[{}]".format(row)).lc()
|
||||
mid1 = driver_wl_pos.scale(0.5,1)+bitcell_wl_pos.scale(0.5,0)
|
||||
mid2 = driver_wl_pos.scale(0.5,0)+bitcell_wl_pos.scale(0.5,1)
|
||||
self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos])
|
||||
|
||||
# The mid guarantees we exit the input cell to the right.
|
||||
driver_wl_pos = self.wordline_driver_inst[port].get_pin("wl[{}]".format(row)).rc()
|
||||
bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.total_wl_list[port]+"[{}]".format(row)).lc()
|
||||
mid1 = driver_wl_pos.scale(0.5,1)+bitcell_wl_pos.scale(0.5,0)
|
||||
mid2 = driver_wl_pos.scale(0.5,0)+bitcell_wl_pos.scale(0.5,1)
|
||||
self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos])
|
||||
|
||||
|
||||
def route_column_address_lines(self):
|
||||
|
|
@ -773,49 +799,45 @@ class bank(design.design):
|
|||
if not self.col_addr_size>0:
|
||||
return
|
||||
|
||||
|
||||
|
||||
if self.col_addr_size == 1:
|
||||
|
||||
# Connect to sel[0] and sel[1]
|
||||
decode_names = ["Zb", "Z"]
|
||||
|
||||
# The Address LSB
|
||||
self.copy_layout_pin(self.col_decoder_inst[0], "A", "addr0[0]")
|
||||
|
||||
elif self.col_addr_size > 1:
|
||||
decode_names = []
|
||||
for i in range(self.num_col_addr_lines):
|
||||
decode_names.append("out[{}]".format(i))
|
||||
|
||||
for i in range(self.col_addr_size):
|
||||
decoder_name = "in[{}]".format(i)
|
||||
addr_name = "addr0[{}]".format(i)
|
||||
self.copy_layout_pin(self.col_decoder_inst[0], decoder_name, addr_name)
|
||||
for port in range(self.total_ports):
|
||||
if self.col_addr_size == 1:
|
||||
|
||||
# Connect to sel[0] and sel[1]
|
||||
decode_names = ["Zb", "Z"]
|
||||
|
||||
# The Address LSB
|
||||
self.copy_layout_pin(self.col_decoder_inst[port], "A", "addr{}[0]".format(port))
|
||||
|
||||
elif self.col_addr_size > 1:
|
||||
decode_names = []
|
||||
for i in range(self.num_col_addr_lines):
|
||||
decode_names.append("out[{}]".format(i))
|
||||
|
||||
# This will do a quick "river route" on two layers.
|
||||
# When above the top select line it will offset "inward" again to prevent conflicts.
|
||||
# This could be done on a single layer, but we follow preferred direction rules for later routing.
|
||||
top_y_offset = self.col_mux_array_inst[0].get_pin("sel[{}]".format(self.num_col_addr_lines-1)).cy()
|
||||
for (decode_name,i) in zip(decode_names,range(self.num_col_addr_lines)):
|
||||
mux_name = "sel[{}]".format(i)
|
||||
mux_addr_pos = self.col_mux_array_inst[0].get_pin(mux_name).lc()
|
||||
|
||||
decode_out_pos = self.col_decoder_inst[0].get_pin(decode_name).center()
|
||||
for i in range(self.col_addr_size):
|
||||
decoder_name = "in[{}]".format(i)
|
||||
addr_name = "addr{0}[{1}]".format(port,i)
|
||||
self.copy_layout_pin(self.col_decoder_inst[port], decoder_name, addr_name)
|
||||
|
||||
|
||||
# To get to the edge of the decoder and one track out
|
||||
delta_offset = self.col_decoder_inst[0].rx() - decode_out_pos.x + self.m2_pitch
|
||||
if decode_out_pos.y > top_y_offset:
|
||||
mid1_pos = vector(decode_out_pos.x + delta_offset + i*self.m2_pitch,decode_out_pos.y)
|
||||
else:
|
||||
mid1_pos = vector(decode_out_pos.x + delta_offset + (self.num_col_addr_lines-i)*self.m2_pitch,decode_out_pos.y)
|
||||
mid2_pos = vector(mid1_pos.x,mux_addr_pos.y)
|
||||
#self.add_wire(("metal1","via1","metal2"),[decode_out_pos, mid1_pos, mid2_pos, mux_addr_pos])
|
||||
self.add_path("metal1",[decode_out_pos, mid1_pos, mid2_pos, mux_addr_pos])
|
||||
|
||||
# This will do a quick "river route" on two layers.
|
||||
# When above the top select line it will offset "inward" again to prevent conflicts.
|
||||
# This could be done on a single layer, but we follow preferred direction rules for later routing.
|
||||
top_y_offset = self.col_mux_array_inst[port].get_pin("sel[{}]".format(self.num_col_addr_lines-1)).cy()
|
||||
for (decode_name,i) in zip(decode_names,range(self.num_col_addr_lines)):
|
||||
mux_name = "sel[{}]".format(i)
|
||||
mux_addr_pos = self.col_mux_array_inst[port].get_pin(mux_name).lc()
|
||||
|
||||
decode_out_pos = self.col_decoder_inst[port].get_pin(decode_name).center()
|
||||
|
||||
|
||||
# To get to the edge of the decoder and one track out
|
||||
delta_offset = self.col_decoder_inst[port].rx() - decode_out_pos.x + self.m2_pitch
|
||||
if decode_out_pos.y > top_y_offset:
|
||||
mid1_pos = vector(decode_out_pos.x + delta_offset + i*self.m2_pitch,decode_out_pos.y)
|
||||
else:
|
||||
mid1_pos = vector(decode_out_pos.x + delta_offset + (self.num_col_addr_lines-i)*self.m2_pitch,decode_out_pos.y)
|
||||
mid2_pos = vector(mid1_pos.x,mux_addr_pos.y)
|
||||
#self.add_wire(("metal1","via1","metal2"),[decode_out_pos, mid1_pos, mid2_pos, mux_addr_pos])
|
||||
self.add_path("metal1",[decode_out_pos, mid1_pos, mid2_pos, mux_addr_pos])
|
||||
|
||||
|
||||
def add_lvs_correspondence_points(self):
|
||||
|
|
@ -869,30 +891,39 @@ class bank(design.design):
|
|||
# From control signal to the module pin
|
||||
# Connection from the central bus to the main control block crosses
|
||||
# pre-decoder and this connection is in metal3
|
||||
connection = []
|
||||
connection.append((self.prefix+"clk_buf_bar", self.precharge_array_inst[0].get_pin("en").lc()))
|
||||
connection.append((self.prefix+"w_en0", self.write_driver_array_inst[0].get_pin("en").lc()))
|
||||
connection.append((self.prefix+"s_en0", self.sense_amp_array_inst[0].get_pin("en").lc()))
|
||||
|
||||
for (control_signal, pin_pos) in connection:
|
||||
control_pos = vector(self.bus_xoffset[control_signal].x ,pin_pos.y)
|
||||
self.add_path("metal1", [control_pos, pin_pos])
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=control_pos,
|
||||
rotate=90)
|
||||
|
||||
# clk to wordline_driver
|
||||
control_signal = self.prefix+"clk_buf"
|
||||
pin_pos = self.wordline_driver_inst[0].get_pin("en").uc()
|
||||
mid_pos = pin_pos + vector(0,self.m1_pitch)
|
||||
control_x_offset = self.bus_xoffset[control_signal].x
|
||||
control_pos = vector(control_x_offset + self.m1_width, mid_pos.y)
|
||||
self.add_wire(("metal1","via1","metal2"),[pin_pos, mid_pos, control_pos])
|
||||
control_via_pos = vector(control_x_offset, mid_pos.y)
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=control_via_pos,
|
||||
rotate=90)
|
||||
write_inst = 0
|
||||
read_inst = 0
|
||||
|
||||
# Control lines for RW ports
|
||||
for port in range(self.total_ports):
|
||||
connection = []
|
||||
if (self.port_id[port] == "rw") or (self.port_id[port] == "r"):
|
||||
connection.append((self.prefix+"clk_buf_bar{}".format(port), self.precharge_array_inst[read_inst].get_pin("en").lc()))
|
||||
if (self.port_id[port] == "rw") or (self.port_id[port] == "w"):
|
||||
connection.append((self.prefix+"w_en{}".format(port), self.write_driver_array_inst[write_inst].get_pin("en").lc()))
|
||||
write_inst += 1
|
||||
if (self.port_id[port] == "rw") or (self.port_id[port] == "r"):
|
||||
connection.append((self.prefix+"s_en{}".format(port), self.sense_amp_array_inst[read_inst].get_pin("en").lc()))
|
||||
read_inst += 1
|
||||
|
||||
for (control_signal, pin_pos) in connection:
|
||||
control_pos = vector(self.bus_xoffset[control_signal].x ,pin_pos.y)
|
||||
self.add_path("metal1", [control_pos, pin_pos])
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=control_pos,
|
||||
rotate=90)
|
||||
|
||||
# clk to wordline_driver
|
||||
control_signal = self.prefix+"clk_buf{}".format(port)
|
||||
pin_pos = self.wordline_driver_inst[port].get_pin("en").uc()
|
||||
mid_pos = pin_pos + vector(0,self.m1_pitch)
|
||||
control_x_offset = self.bus_xoffset[control_signal].x
|
||||
control_pos = vector(control_x_offset + self.m1_width, mid_pos.y)
|
||||
self.add_wire(("metal1","via1","metal2"),[pin_pos, mid_pos, control_pos])
|
||||
control_via_pos = vector(control_x_offset, mid_pos.y)
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=control_via_pos,
|
||||
rotate=90)
|
||||
|
||||
|
||||
def analytical_delay(self, slew, load):
|
||||
|
|
|
|||
|
|
@ -15,9 +15,11 @@ class bank_select(design.design):
|
|||
banks are created in upper level SRAM module
|
||||
"""
|
||||
|
||||
def __init__(self, name="bank_select"):
|
||||
def __init__(self, name="bank_select", port="rw"):
|
||||
design.design.__init__(self, name)
|
||||
|
||||
self.port = port
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
|
@ -38,10 +40,17 @@ class bank_select(design.design):
|
|||
def add_pins(self):
|
||||
|
||||
# Number of control lines in the bus
|
||||
self.num_control_lines = 4
|
||||
if self.port == "rw":
|
||||
self.num_control_lines = 4
|
||||
else:
|
||||
self.num_control_lines = 3
|
||||
# The order of the control signals on the control bus:
|
||||
# FIXME: Update for multiport (these names are not right)
|
||||
self.input_control_signals = ["clk_buf", "clk_buf_bar", "w_en0", "s_en0"]
|
||||
self.input_control_signals = ["clk_buf", "clk_buf_bar"]
|
||||
if (self.port == "rw") or (self.port == "w"):
|
||||
self.input_control_signals.append("w_en")
|
||||
if (self.port == "rw") or (self.port == "r"):
|
||||
self.input_control_signals.append("s_en")
|
||||
# These will be outputs of the gaters if this is multibank
|
||||
self.control_signals = ["gated_"+str for str in self.input_control_signals]
|
||||
|
||||
|
|
@ -53,16 +62,26 @@ class bank_select(design.design):
|
|||
|
||||
def add_modules(self):
|
||||
""" Create modules for later instantiation """
|
||||
from importlib import reload
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
||||
self.bitcell = self.mod_bitcell()
|
||||
|
||||
height = self.bitcell.height + drc["poly_to_active"]
|
||||
|
||||
# 1x Inverter
|
||||
self.inv = pinv()
|
||||
self.add_mod(self.inv)
|
||||
self.inv_sel = pinv(height=height)
|
||||
self.add_mod(self.inv_sel)
|
||||
|
||||
# 4x Inverter
|
||||
self.inv4x = pinv(4)
|
||||
self.inv = self.inv4x = pinv(4)
|
||||
self.add_mod(self.inv4x)
|
||||
|
||||
self.nor2 = pnor2()
|
||||
self.nor2 = pnor2(height=height)
|
||||
self.add_mod(self.nor2)
|
||||
|
||||
self.inv4x_nor = pinv(size=4, height=height)
|
||||
self.add_mod(self.inv4x_nor)
|
||||
|
||||
self.nand2 = pnand2()
|
||||
self.add_mod(self.nand2)
|
||||
|
|
@ -83,7 +102,7 @@ class bank_select(design.design):
|
|||
def create_modules(self):
|
||||
|
||||
self.bank_sel_inv=self.add_inst(name="bank_sel_inv",
|
||||
mod=self.inv)
|
||||
mod=self.inv_sel)
|
||||
self.connect_inst(["bank_sel", "bank_sel_bar", "vdd", "gnd"])
|
||||
|
||||
self.logic_inst = []
|
||||
|
|
@ -107,6 +126,14 @@ class bank_select(design.design):
|
|||
"vdd",
|
||||
"gnd"])
|
||||
|
||||
# They all get inverters on the output
|
||||
self.inv_inst.append(self.add_inst(name=name_inv,
|
||||
mod=self.inv4x_nor))
|
||||
self.connect_inst([gated_name+"_temp_bar",
|
||||
gated_name,
|
||||
"vdd",
|
||||
"gnd"])
|
||||
|
||||
# the rest are AND (nand2+inv) gates
|
||||
else:
|
||||
self.logic_inst.append(self.add_inst(name=name_nand,
|
||||
|
|
@ -117,13 +144,13 @@ class bank_select(design.design):
|
|||
"vdd",
|
||||
"gnd"])
|
||||
|
||||
# They all get inverters on the output
|
||||
self.inv_inst.append(self.add_inst(name=name_inv,
|
||||
mod=self.inv4x))
|
||||
self.connect_inst([gated_name+"_temp_bar",
|
||||
gated_name,
|
||||
"vdd",
|
||||
"gnd"])
|
||||
# They all get inverters on the output
|
||||
self.inv_inst.append(self.add_inst(name=name_inv,
|
||||
mod=self.inv4x))
|
||||
self.connect_inst([gated_name+"_temp_bar",
|
||||
gated_name,
|
||||
"vdd",
|
||||
"gnd"])
|
||||
|
||||
def place_modules(self):
|
||||
|
||||
|
|
@ -140,7 +167,11 @@ class bank_select(design.design):
|
|||
|
||||
input_name = self.input_control_signals[i]
|
||||
|
||||
y_offset = self.inv.height * i
|
||||
if i == 0:
|
||||
y_offset = 0
|
||||
else:
|
||||
y_offset = self.inv4x_nor.height + self.inv.height * (i-1)
|
||||
|
||||
if i%2:
|
||||
y_offset += self.inv.height
|
||||
mirror = "MX"
|
||||
|
|
|
|||
|
|
@ -18,12 +18,19 @@ class control_logic(design.design):
|
|||
Dynamically generated Control logic for the total SRAM circuit.
|
||||
"""
|
||||
|
||||
def __init__(self, num_rows):
|
||||
def __init__(self, num_rows, port_type="rw"):
|
||||
""" Constructor """
|
||||
design.design.__init__(self, "control_logic")
|
||||
debug.info(1, "Creating {}".format(self.name))
|
||||
|
||||
name = "control_logic_" + port_type
|
||||
design.design.__init__(self, name)
|
||||
debug.info(1, "Creating {}".format(name))
|
||||
|
||||
self.num_rows = num_rows
|
||||
self.port_type = port_type
|
||||
|
||||
if self.port_type == "rw":
|
||||
self.num_control_signals = 2
|
||||
else:
|
||||
self.num_control_signals = 1
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
|
|
@ -41,7 +48,7 @@ class control_logic(design.design):
|
|||
self.place_modules()
|
||||
self.route_all()
|
||||
|
||||
self.add_lvs_correspondence_points()
|
||||
#self.add_lvs_correspondence_points()
|
||||
|
||||
self.DRC_LVS()
|
||||
|
||||
|
|
@ -61,7 +68,7 @@ class control_logic(design.design):
|
|||
dff = dff_inv()
|
||||
dff_height = dff.height
|
||||
|
||||
self.ctrl_dff_array = dff_inv_array(rows=2,columns=1)
|
||||
self.ctrl_dff_array = dff_inv_array(rows=self.num_control_signals,columns=1)
|
||||
self.add_mod(self.ctrl_dff_array)
|
||||
|
||||
self.nand2 = pnand2(height=dff_height)
|
||||
|
|
@ -81,29 +88,50 @@ class control_logic(design.design):
|
|||
self.inv8 = pinv(size=16, height=dff_height)
|
||||
self.add_mod(self.inv8)
|
||||
|
||||
from importlib import reload
|
||||
c = reload(__import__(OPTS.replica_bitline))
|
||||
replica_bitline = getattr(c, OPTS.replica_bitline)
|
||||
# FIXME: These should be tuned according to the size!
|
||||
delay_stages = 4 # Must be non-inverting
|
||||
delay_fanout = 3 # This can be anything >=2
|
||||
bitcell_loads = int(math.ceil(self.num_rows / 5.0))
|
||||
self.replica_bitline = replica_bitline(delay_stages, delay_fanout, bitcell_loads)
|
||||
self.add_mod(self.replica_bitline)
|
||||
if (self.port_type == "rw") or (self.port_type == "r"):
|
||||
from importlib import reload
|
||||
c = reload(__import__(OPTS.replica_bitline))
|
||||
replica_bitline = getattr(c, OPTS.replica_bitline)
|
||||
# FIXME: These should be tuned according to the size!
|
||||
delay_stages = 4 # Must be non-inverting
|
||||
delay_fanout = 3 # This can be anything >=2
|
||||
bitcell_loads = int(math.ceil(self.num_rows / 5.0))
|
||||
self.replica_bitline = replica_bitline(delay_stages, delay_fanout, bitcell_loads, name="replica_bitline_"+self.port_type)
|
||||
self.add_mod(self.replica_bitline)
|
||||
|
||||
|
||||
def setup_signal_busses(self):
|
||||
""" Setup bus names, determine the size of the busses etc """
|
||||
|
||||
# List of input control signals
|
||||
self.input_list =["csb","web0"]
|
||||
self.dff_output_list =["cs_bar", "cs", "we_bar", "we"]
|
||||
if self.port_type == "rw":
|
||||
self.input_list = ["csb", "web"]
|
||||
else:
|
||||
self.input_list = ["csb"]
|
||||
|
||||
if self.port_type == "rw":
|
||||
self.dff_output_list = ["cs_bar", "cs", "we_bar", "we"]
|
||||
else:
|
||||
self.dff_output_list = ["cs_bar", "cs"]
|
||||
|
||||
# list of output control signals (for making a vertical bus)
|
||||
self.internal_bus_list = ["clk_buf", "clk_buf_bar", "we", "cs"]
|
||||
if self.port_type == "rw":
|
||||
self.internal_bus_list = ["clk_buf", "clk_buf_bar", "we", "cs"]
|
||||
else:
|
||||
self.internal_bus_list = ["clk_buf", "clk_buf_bar", "cs"]
|
||||
# leave space for the bus plus one extra space
|
||||
self.internal_bus_width = (len(self.internal_bus_list)+1)*self.m2_pitch
|
||||
|
||||
# Outputs to the bank
|
||||
self.output_list = ["s_en0", "w_en0", "clk_buf_bar", "clk_buf"]
|
||||
if self.port_type == "r":
|
||||
self.output_list = ["s_en"]
|
||||
elif self.port_type == "w":
|
||||
self.output_list = ["w_en"]
|
||||
else:
|
||||
self.output_list = ["s_en", "w_en"]
|
||||
self.output_list.append("clk_buf_bar")
|
||||
self.output_list.append("clk_buf")
|
||||
|
||||
self.supply_list = ["vdd", "gnd"]
|
||||
|
||||
|
||||
|
|
@ -118,14 +146,13 @@ class control_logic(design.design):
|
|||
def create_modules(self):
|
||||
""" Create all the modules """
|
||||
self.create_dffs()
|
||||
self.create_clk_row()
|
||||
self.create_we_row()
|
||||
# self.create_trien_row()
|
||||
# self.create_trien_bar_row()
|
||||
self.create_rbl_in_row()
|
||||
self.create_sen_row()
|
||||
self.create_rbl()
|
||||
|
||||
self.create_clk_row()
|
||||
if (self.port_type == "rw") or (self.port_type == "w"):
|
||||
self.create_we_row()
|
||||
if (self.port_type == "rw") or (self.port_type == "r"):
|
||||
self.create_rbl_in_row()
|
||||
self.create_sen_row()
|
||||
self.create_rbl()
|
||||
|
||||
|
||||
def place_modules(self):
|
||||
|
|
@ -134,38 +161,44 @@ class control_logic(design.design):
|
|||
# and add the vdd/gnd pins
|
||||
self.row_end_inst = []
|
||||
|
||||
|
||||
# Add the control flops on the left of the bus
|
||||
self.place_dffs()
|
||||
|
||||
row = 0
|
||||
# Add the logic on the right of the bus
|
||||
self.place_clk_row(row=0) # clk is a double-high cell
|
||||
self.place_we_row(row=2)
|
||||
# self.place_trien_row(row=3)
|
||||
# self.place_trien_bar_row(row=4)
|
||||
self.place_rbl_in_row(row=3)
|
||||
self.place_sen_row(row=4)
|
||||
self.place_rbl(row=5)
|
||||
|
||||
self.place_clk_row(row=row) # clk is a double-high cell
|
||||
row += 2
|
||||
if (self.port_type == "rw") or (self.port_type == "w"):
|
||||
self.place_we_row(row=row)
|
||||
pre_height = self.w_en_inst.uy()
|
||||
control_center_y = self.w_en_inst.by()
|
||||
row += 1
|
||||
if (self.port_type == "rw") or (self.port_type == "r"):
|
||||
self.place_rbl_in_row(row=row)
|
||||
self.place_sen_row(row=row+1)
|
||||
self.place_rbl(row=row+2)
|
||||
pre_height = self.rbl_inst.uy()
|
||||
control_center_y = self.rbl_inst.by()
|
||||
|
||||
# This offset is used for placement of the control logic in
|
||||
# the SRAM level.
|
||||
self.control_logic_center = vector(self.ctrl_dff_inst.rx(), self.rbl_inst.by())
|
||||
# This offset is used for placement of the control logic in the SRAM level.
|
||||
self.control_logic_center = vector(self.ctrl_dff_inst.rx(), control_center_y)
|
||||
|
||||
# Extra pitch on top and right
|
||||
self.height = self.rbl_inst.uy() + self.m3_pitch
|
||||
self.height = pre_height + self.m3_pitch
|
||||
# Max of modules or logic rows
|
||||
self.width = max(self.rbl_inst.rx(), max([inst.rx() for inst in self.row_end_inst])) + self.m2_pitch
|
||||
|
||||
if (self.port_type == "rw") or (self.port_type == "r"):
|
||||
self.width = max(self.rbl_inst.rx(), max([inst.rx() for inst in self.row_end_inst])) + self.m2_pitch
|
||||
else:
|
||||
self.width = max([inst.rx() for inst in self.row_end_inst]) + self.m2_pitch
|
||||
|
||||
def route_all(self):
|
||||
""" Routing between modules """
|
||||
self.route_dffs()
|
||||
#self.route_trien()
|
||||
#self.route_trien_bar()
|
||||
self.route_rbl_in()
|
||||
self.route_wen()
|
||||
self.route_sen()
|
||||
if (self.port_type == "rw") or (self.port_type == "w"):
|
||||
self.route_wen()
|
||||
if (self.port_type == "rw") or (self.port_type == "r"):
|
||||
self.route_rbl_in()
|
||||
self.route_sen()
|
||||
self.route_clk()
|
||||
self.route_supply()
|
||||
|
||||
|
|
@ -202,7 +235,7 @@ class control_logic(design.design):
|
|||
|
||||
|
||||
def create_rbl_in_row(self):
|
||||
self.rbl_in_bar_inst=self.add_inst(name="nand3_rbl_in_bar",
|
||||
self.rbl_in_bar_inst=self.add_inst(name="nand2_rbl_in_bar",
|
||||
mod=self.nand2)
|
||||
self.connect_inst(["clk_buf_bar", "cs", "rbl_in_bar", "vdd", "gnd"])
|
||||
|
||||
|
|
@ -238,7 +271,7 @@ class control_logic(design.design):
|
|||
# input: input: pre_s_en_bar, output: s_en
|
||||
self.s_en_inst=self.add_inst(name="inv_s_en",
|
||||
mod=self.inv8)
|
||||
self.connect_inst(["pre_s_en_bar", "s_en0", "vdd", "gnd"])
|
||||
self.connect_inst(["pre_s_en_bar", "s_en", "vdd", "gnd"])
|
||||
|
||||
def place_sen_row(self,row):
|
||||
"""
|
||||
|
|
@ -262,7 +295,11 @@ class control_logic(design.design):
|
|||
def route_dffs(self):
|
||||
""" Route the input inverters """
|
||||
|
||||
dff_out_map = zip(["dout_bar[{}]".format(i) for i in range(3)], ["cs", "we"])
|
||||
if self.port_type == "r":
|
||||
control_inputs = ["cs"]
|
||||
else:
|
||||
control_inputs = ["cs", "we"]
|
||||
dff_out_map = zip(["dout_bar[{}]".format(i) for i in range(2*self.num_control_signals - 1)], control_inputs)
|
||||
self.connect_vertical_bus(dff_out_map, self.ctrl_dff_inst, self.rail_offsets)
|
||||
|
||||
# Connect the clock rail to the other clock rail
|
||||
|
|
@ -275,7 +312,8 @@ class control_logic(design.design):
|
|||
rotate=90)
|
||||
|
||||
self.copy_layout_pin(self.ctrl_dff_inst, "din[0]", "csb")
|
||||
self.copy_layout_pin(self.ctrl_dff_inst, "din[1]", "web0")
|
||||
if (self.port_type == "rw"):
|
||||
self.copy_layout_pin(self.ctrl_dff_inst, "din[1]", "web")
|
||||
|
||||
|
||||
def create_dffs(self):
|
||||
|
|
@ -302,23 +340,30 @@ class control_logic(design.design):
|
|||
|
||||
def create_we_row(self):
|
||||
# input: WE, CS output: w_en_bar
|
||||
self.w_en_bar_inst=self.add_inst(name="nand3_w_en_bar",
|
||||
mod=self.nand3)
|
||||
self.connect_inst(["clk_buf_bar", "cs", "we", "w_en_bar", "vdd", "gnd"])
|
||||
if self.port_type == "rw":
|
||||
nand_mod = self.nand3
|
||||
temp = ["clk_buf_bar", "cs", "we", "w_en_bar", "vdd", "gnd"]
|
||||
else:
|
||||
nand_mod = self.nand2
|
||||
temp = ["clk_buf_bar", "cs", "w_en_bar", "vdd", "gnd"]
|
||||
|
||||
self.w_en_bar_inst = self.add_inst(name="nand3_w_en_bar",
|
||||
mod=nand_mod)
|
||||
self.connect_inst(temp)
|
||||
|
||||
# input: w_en_bar, output: pre_w_en
|
||||
self.pre_w_en_inst=self.add_inst(name="inv_pre_w_en",
|
||||
mod=self.inv1)
|
||||
self.connect_inst(["w_en_bar", "pre_w_en", "vdd", "gnd"])
|
||||
self.pre_w_en_inst = self.add_inst(name="inv_pre_w_en",
|
||||
mod=self.inv1)
|
||||
self.connect_inst(["w_en_bar", "pre_w_en", "vdd", "gnd"])
|
||||
|
||||
# BUFFER INVERTERS FOR W_EN
|
||||
self.pre_w_en_bar_inst=self.add_inst(name="inv_pre_w_en_bar",
|
||||
mod=self.inv2)
|
||||
self.connect_inst(["pre_w_en", "pre_w_en_bar", "vdd", "gnd"])
|
||||
self.pre_w_en_bar_inst = self.add_inst(name="inv_pre_w_en_bar",
|
||||
mod=self.inv2)
|
||||
self.connect_inst(["pre_w_en", "pre_w_en_bar", "vdd", "gnd"])
|
||||
|
||||
self.w_en_inst=self.add_inst(name="inv_w_en2",
|
||||
mod=self.inv8)
|
||||
self.connect_inst(["pre_w_en_bar", "w_en0", "vdd", "gnd"])
|
||||
self.w_en_inst = self.add_inst(name="inv_w_en2",
|
||||
mod=self.inv8)
|
||||
self.connect_inst(["pre_w_en_bar", "w_en", "vdd", "gnd"])
|
||||
|
||||
|
||||
def place_we_row(self,row):
|
||||
|
|
@ -328,7 +373,10 @@ class control_logic(design.design):
|
|||
w_en_bar_offset = vector(x_off, y_off)
|
||||
self.w_en_bar_inst.place(offset=w_en_bar_offset,
|
||||
mirror=mirror)
|
||||
x_off += self.nand3.width
|
||||
if self.port_type == "rw":
|
||||
x_off += self.nand3.width
|
||||
else:
|
||||
x_off += self.nand2.width
|
||||
|
||||
pre_w_en_offset = vector(x_off, y_off)
|
||||
self.pre_w_en_inst.place(offset=pre_w_en_offset,
|
||||
|
|
@ -422,7 +470,10 @@ class control_logic(design.design):
|
|||
|
||||
|
||||
def route_wen(self):
|
||||
wen_map = zip(["A", "B", "C"], ["clk_buf_bar", "cs", "we"])
|
||||
if self.port_type == "rw":
|
||||
wen_map = zip(["A", "B", "C"], ["clk_buf_bar", "cs", "we"])
|
||||
else:
|
||||
wen_map = zip(["A", "B"], ["clk_buf_bar", "cs"])
|
||||
self.connect_vertical_bus(wen_map, self.w_en_bar_inst, self.rail_offsets)
|
||||
|
||||
# Connect the NAND3 output to the inverter
|
||||
|
|
@ -435,7 +486,7 @@ class control_logic(design.design):
|
|||
self.add_path("metal1",[self.pre_w_en_inst.get_pin("Z").center(), self.pre_w_en_bar_inst.get_pin("A").center()])
|
||||
self.add_path("metal1",[self.pre_w_en_bar_inst.get_pin("Z").center(), self.w_en_inst.get_pin("A").center()])
|
||||
|
||||
self.connect_output(self.w_en_inst, "Z", "w_en0")
|
||||
self.connect_output(self.w_en_inst, "Z", "w_en")
|
||||
|
||||
def route_sen(self):
|
||||
rbl_out_pos = self.rbl_inst.get_pin("out").bc()
|
||||
|
|
@ -446,7 +497,7 @@ class control_logic(design.design):
|
|||
|
||||
self.add_path("metal1",[self.pre_s_en_bar_inst.get_pin("Z").center(), self.s_en_inst.get_pin("A").center()])
|
||||
|
||||
self.connect_output(self.s_en_inst, "Z", "s_en0")
|
||||
self.connect_output(self.s_en_inst, "Z", "s_en")
|
||||
|
||||
def route_clk(self):
|
||||
""" Route the clk and clk_buf_bar signal internally """
|
||||
|
|
@ -498,9 +549,9 @@ class control_logic(design.design):
|
|||
self.add_power_pin("gnd", pin_loc)
|
||||
self.add_path("metal1", [row_loc, pin_loc])
|
||||
|
||||
|
||||
self.copy_layout_pin(self.rbl_inst,"gnd")
|
||||
self.copy_layout_pin(self.rbl_inst,"vdd")
|
||||
if (self.port_type == "rw") or (self.port_type == "r"):
|
||||
self.copy_layout_pin(self.rbl_inst,"gnd")
|
||||
self.copy_layout_pin(self.rbl_inst,"vdd")
|
||||
|
||||
self.copy_layout_pin(self.ctrl_dff_inst,"gnd")
|
||||
self.copy_layout_pin(self.ctrl_dff_inst,"vdd")
|
||||
|
|
|
|||
|
|
@ -13,8 +13,12 @@ class delay_chain(design.design):
|
|||
Usually, this will be constant, but it could have varied fanout.
|
||||
"""
|
||||
|
||||
unique_id = 1
|
||||
|
||||
def __init__(self, fanout_list, name="delay_chain"):
|
||||
"""init function"""
|
||||
name = name+"_{}".format(delay_chain.unique_id)
|
||||
delay_chain.unique_id += 1
|
||||
design.design.__init__(self, name)
|
||||
|
||||
# Two fanouts are needed so that we can route the vdd/gnd connections
|
||||
|
|
|
|||
|
|
@ -81,8 +81,8 @@ class replica_bitline(design.design):
|
|||
""" Add the modules for later usage """
|
||||
|
||||
from importlib import reload
|
||||
g = reload(__import__(OPTS.delay_chain))
|
||||
self.mod_delay_chain = getattr(g, OPTS.delay_chain)
|
||||
#g = reload(__import__(OPTS.delay_chain))
|
||||
#self.mod_delay_chain = getattr(g, OPTS.delay_chain)
|
||||
|
||||
g = reload(__import__(OPTS.replica_bitcell))
|
||||
self.mod_replica_bitcell = getattr(g, OPTS.replica_bitcell)
|
||||
|
|
@ -95,7 +95,8 @@ class replica_bitline(design.design):
|
|||
self.add_mod(self.rbl)
|
||||
|
||||
# FIXME: The FO and depth of this should be tuned
|
||||
self.delay_chain = self.mod_delay_chain([self.delay_fanout]*self.delay_stages)
|
||||
from delay_chain import delay_chain
|
||||
self.delay_chain = delay_chain([self.delay_fanout]*self.delay_stages)
|
||||
self.add_mod(self.delay_chain)
|
||||
|
||||
self.inv = pinv()
|
||||
|
|
@ -110,12 +111,12 @@ class replica_bitline(design.design):
|
|||
# This is the threshold detect inverter on the output of the RBL
|
||||
self.rbl_inv_inst=self.add_inst(name="rbl_inv",
|
||||
mod=self.inv)
|
||||
self.connect_inst(["bl[0]", "out", "vdd", "gnd"])
|
||||
self.connect_inst(["bl0[0]", "out", "vdd", "gnd"])
|
||||
|
||||
self.tx_inst=self.add_inst(name="rbl_access_tx",
|
||||
mod=self.access_tx)
|
||||
# D, G, S, B
|
||||
self.connect_inst(["vdd", "delayed_en", "bl[0]", "vdd"])
|
||||
self.connect_inst(["vdd", "delayed_en", "bl0[0]", "vdd"])
|
||||
# add the well and poly contact
|
||||
|
||||
self.dc_inst=self.add_inst(name="delay_chain",
|
||||
|
|
@ -124,26 +125,33 @@ class replica_bitline(design.design):
|
|||
|
||||
self.rbc_inst=self.add_inst(name="bitcell",
|
||||
mod=self.replica_bitcell)
|
||||
self.connect_inst(["bl[0]", "br[0]", "delayed_en", "vdd", "gnd"])
|
||||
temp = []
|
||||
for port in range(self.total_ports):
|
||||
temp.append("bl{}[0]".format(port))
|
||||
temp.append("br{}[0]".format(port))
|
||||
for port in range(self.total_ports):
|
||||
temp.append("delayed_en")
|
||||
temp.append("vdd")
|
||||
temp.append("gnd")
|
||||
self.connect_inst(temp)
|
||||
#self.connect_inst(["bl[0]", "br[0]", "delayed_en", "vdd", "gnd"])
|
||||
|
||||
self.rbl_inst=self.add_inst(name="load",
|
||||
mod=self.rbl)
|
||||
|
||||
total_ports = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports
|
||||
temp = []
|
||||
temp.append("bl[0]")
|
||||
temp.append("br[0]")
|
||||
for port in range(total_ports - 1):
|
||||
temp.append("gnd")
|
||||
temp.append("gnd")
|
||||
for port in range(self.total_ports):
|
||||
temp.append("bl{}[0]".format(port))
|
||||
temp.append("br{}[0]".format(port))
|
||||
for wl in range(self.bitcell_loads):
|
||||
for port in range(total_ports):
|
||||
for port in range(self.total_ports):
|
||||
temp.append("gnd")
|
||||
temp.append("vdd")
|
||||
temp.append("gnd")
|
||||
self.connect_inst(temp)
|
||||
|
||||
self.wl_list = self.rbl.cell.list_all_wl_names()
|
||||
self.bl_list = self.rbl.cell.list_write_bl_names()
|
||||
|
||||
def place_modules(self):
|
||||
""" Add all of the module instances in the logical netlist """
|
||||
|
|
@ -160,9 +168,6 @@ class replica_bitline(design.design):
|
|||
mirror="MX")
|
||||
|
||||
self.rbl_inst.place(self.rbl_offset)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def route(self):
|
||||
|
|
@ -178,15 +183,27 @@ class replica_bitline(design.design):
|
|||
wl = self.wl_list[0]+"[{}]".format(row)
|
||||
pin = self.rbl_inst.get_pin(wl)
|
||||
|
||||
# Route the connection to the right so that it doesn't interfere
|
||||
# with the cells
|
||||
# Route the connection to the right so that it doesn't interfere with the cells
|
||||
# Wordlines may be close to each other when tiled, so gnd connections are routed in opposite directions
|
||||
if row % 2 == 0:
|
||||
vertical_extension = vector(0, 1.5*drc["minwidth_metal1"] + 0.5*contact.m1m2.height)
|
||||
else:
|
||||
vertical_extension = vector(0, -1.5*drc["minwidth_metal1"] - 1.5*contact.m1m2.height)
|
||||
|
||||
pin_right = pin.rc()
|
||||
pin_extension = pin_right + vector(self.m1_pitch,0)
|
||||
pin_extension1 = pin_right + vector(self.m3_pitch,0)
|
||||
pin_extension2 = pin_extension1 + vertical_extension
|
||||
if pin.layer != "metal1":
|
||||
continue
|
||||
self.add_path("metal1", [pin_right, pin_extension])
|
||||
self.add_power_pin("gnd", pin_extension)
|
||||
|
||||
self.add_path("metal1", [pin_right, pin_extension1, pin_extension2])
|
||||
self.add_power_pin("gnd", pin_extension2)
|
||||
|
||||
# for multiport, need to short wordlines to each other so they all connect to gnd
|
||||
wl_last = self.wl_list[self.total_ports-1]+"[{}]".format(row)
|
||||
pin_last = self.rbl_inst.get_pin(wl_last)
|
||||
|
||||
correct = vector(0.5*drc["minwidth_metal1"], 0)
|
||||
self.add_path("metal1", [pin.rc()-correct, pin_last.rc()-correct])
|
||||
|
||||
def route_supplies(self):
|
||||
""" Propagate all vdd/gnd pins up to this level for all modules """
|
||||
|
|
@ -243,11 +260,22 @@ class replica_bitline(design.design):
|
|||
|
||||
# 3. Route the contact of previous route to the bitcell WL
|
||||
# route bend of previous net to bitcell WL
|
||||
wl_offset = self.rbc_inst.get_pin("wl").lc()
|
||||
xmid_point= 0.5*(wl_offset.x+contact_offset.x)
|
||||
wl_mid1 = vector(xmid_point,contact_offset.y)
|
||||
wl_mid2 = vector(xmid_point,wl_offset.y)
|
||||
self.add_path("metal1", [contact_offset, wl_mid1, wl_mid2, wl_offset])
|
||||
wl_offset = self.rbc_inst.get_pin(self.wl_list[0]).lc()
|
||||
wl_mid1 = wl_offset - vector(1.5*drc["minwidth_metal1"], 0)
|
||||
wl_mid2 = vector(wl_mid1.x, contact_offset.y)
|
||||
#xmid_point= 0.5*(wl_offset.x+contact_offset.x)
|
||||
#wl_mid1 = vector(xmid_point,contact_offset.y)
|
||||
#wl_mid2 = vector(xmid_point,wl_offset.y)
|
||||
self.add_path("metal1", [wl_offset, wl_mid1, wl_mid2, contact_offset])
|
||||
|
||||
# 4. Short wodlines if multiport
|
||||
wl = self.wl_list[0]
|
||||
wl_last = self.wl_list[self.total_ports-1]
|
||||
pin = self.rbc_inst.get_pin(wl)
|
||||
pin_last = self.rbc_inst.get_pin(wl_last)
|
||||
|
||||
correct = vector(0.5*drc["minwidth_metal1"], 0)
|
||||
self.add_path("metal1", [pin.lc()+correct, pin_last.lc()+correct])
|
||||
|
||||
# DRAIN ROUTE
|
||||
# Route the drain to the vdd rail
|
||||
|
|
@ -262,7 +290,7 @@ class replica_bitline(design.design):
|
|||
|
||||
# Route the connection of the source route to the RBL bitline (left)
|
||||
# Via will go halfway down from the bitcell
|
||||
bl_offset = self.rbc_inst.get_pin("bl").bc()
|
||||
bl_offset = self.rbc_inst.get_pin(self.bl_list[0]).bc()
|
||||
# Route down a pitch so we can use M2 routing
|
||||
bl_down_offset = bl_offset - vector(0, self.m2_pitch)
|
||||
self.add_path("metal2",[source_offset, bl_down_offset, bl_offset])
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
||||
|
|
@ -50,8 +50,6 @@ class options(optparse.Values):
|
|||
analytical_delay = True
|
||||
# Purge the temp directory after a successful run (doesn't purge on errors, anyhow)
|
||||
purge_temp = True
|
||||
# Determines whether multi-port portion of unit tests are run or not
|
||||
multiport_check = True
|
||||
|
||||
# These are the configuration parameters
|
||||
num_rw_ports = 1
|
||||
|
|
@ -66,9 +64,11 @@ class options(optparse.Values):
|
|||
# These are the main configuration parameters that should be over-ridden
|
||||
# in a configuration file.
|
||||
#num_words = 0
|
||||
#num_banks = 1
|
||||
#word_size = 0
|
||||
|
||||
# You can manually specify banks, but it is better to auto-detect it.
|
||||
num_banks = 1
|
||||
|
||||
# These are the default modules that can be over-riden
|
||||
decoder = "hierarchical_decoder"
|
||||
dff_array = "dff_array"
|
||||
|
|
|
|||
|
|
@ -41,8 +41,9 @@ class ptx(design.design):
|
|||
self.num_contacts = num_contacts
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
# We must always create ptx layout for pbitcell
|
||||
# some transistor sizes in other netlist depend on pbitcell
|
||||
self.create_layout()
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
word_size = 1
|
||||
num_words = 16
|
||||
num_banks = 1
|
||||
|
||||
tech_name = "freepdk45"
|
||||
process_corners = ["TT"]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
word_size = 1
|
||||
num_words = 16
|
||||
num_banks = 1
|
||||
|
||||
tech_name = "scn4m_subm"
|
||||
process_corners = ["TT"]
|
||||
|
|
|
|||
|
|
@ -34,9 +34,7 @@ class sram_1bank(sram_base):
|
|||
|
||||
self.bank_inst=self.create_bank(0)
|
||||
|
||||
self.control_logic_inst = [None] * self.total_ports
|
||||
for port in range(self.total_ports):
|
||||
self.control_logic_inst[port] = self.create_control_logic(port)
|
||||
self.control_logic_inst = self.create_control_logic()
|
||||
|
||||
self.row_addr_dff_inst = self.create_row_addr_dff()
|
||||
|
||||
|
|
@ -59,60 +57,60 @@ class sram_1bank(sram_base):
|
|||
# the sense amps/column mux and cell array)
|
||||
# The x-coordinate is placed to allow a single clock wire (plus an extra pitch)
|
||||
# up to the row address DFFs.
|
||||
control_pos = vector(-self.control_logic.width - 2*self.m2_pitch,
|
||||
self.bank.bank_center.y - self.control_logic.control_logic_center.y)
|
||||
self.control_logic_inst[0].place(control_pos)
|
||||
for port in range(self.total_ports):
|
||||
control_pos = vector(-self.control_logic.width - 2*self.m2_pitch,
|
||||
self.bank.bank_center.y - self.control_logic.control_logic_center.y)
|
||||
self.control_logic_inst[port].place(control_pos)
|
||||
|
||||
# The row address bits are placed above the control logic aligned on the right.
|
||||
row_addr_pos = vector(self.control_logic_inst[0].rx() - self.row_addr_dff.width,
|
||||
self.control_logic_inst[0].uy())
|
||||
self.row_addr_dff_inst.place(row_addr_pos)
|
||||
# The row address bits are placed above the control logic aligned on the right.
|
||||
row_addr_pos = vector(self.control_logic_inst[0].rx() - self.row_addr_dff.width,
|
||||
self.control_logic_inst[0].uy())
|
||||
self.row_addr_dff_inst[port].place(row_addr_pos)
|
||||
|
||||
# This is M2 pitch even though it is on M1 to help stem via spacings on the trunk
|
||||
data_gap = -self.m2_pitch*(self.word_size+1)
|
||||
|
||||
# Add the column address below the bank under the control
|
||||
# The column address flops are aligned with the data flops
|
||||
if self.col_addr_dff:
|
||||
col_addr_pos = vector(self.bank.bank_center.x - self.col_addr_dff.width - self.bank.central_bus_width,
|
||||
data_gap - self.col_addr_dff.height)
|
||||
self.col_addr_dff_inst.place(col_addr_pos)
|
||||
|
||||
# Add the data flops below the bank to the right of the center of bank:
|
||||
# This relies on the center point of the bank:
|
||||
# decoder in upper left, bank in upper right, sensing in lower right.
|
||||
# These flops go below the sensing and leave a gap to channel route to the
|
||||
# sense amps.
|
||||
data_pos = vector(self.bank.bank_center.x,
|
||||
data_gap - self.data_dff.height)
|
||||
self.data_dff_inst.place(data_pos)
|
||||
|
||||
# two supply rails are already included in the bank, so just 2 here.
|
||||
# self.width = self.bank.width + self.control_logic.width + 2*self.supply_rail_pitch
|
||||
# self.height = self.bank.height
|
||||
# This is M2 pitch even though it is on M1 to help stem via spacings on the trunk
|
||||
data_gap = -self.m2_pitch*(self.word_size+1)
|
||||
|
||||
# Add the column address below the bank under the control
|
||||
# The column address flops are aligned with the data flops
|
||||
if self.col_addr_dff:
|
||||
col_addr_pos = vector(self.bank.bank_center.x - self.col_addr_dff.width - self.bank.central_bus_width,
|
||||
data_gap - self.col_addr_dff.height)
|
||||
self.col_addr_dff_inst[port].place(col_addr_pos)
|
||||
|
||||
# Add the data flops below the bank to the right of the center of bank:
|
||||
# This relies on the center point of the bank:
|
||||
# decoder in upper left, bank in upper right, sensing in lower right.
|
||||
# These flops go below the sensing and leave a gap to channel route to the
|
||||
# sense amps.
|
||||
data_pos = vector(self.bank.bank_center.x,
|
||||
data_gap - self.data_dff.height)
|
||||
self.data_dff_inst[port].place(data_pos)
|
||||
|
||||
# two supply rails are already included in the bank, so just 2 here.
|
||||
# self.width = self.bank.width + self.control_logic.width + 2*self.supply_rail_pitch
|
||||
# self.height = self.bank.height
|
||||
|
||||
def add_layout_pins(self):
|
||||
"""
|
||||
Add the top-level pins for a single bank SRAM with control.
|
||||
"""
|
||||
# Connect the control pins as inputs
|
||||
for n in self.control_logic_inputs + ["clk"]:
|
||||
self.copy_layout_pin(self.control_logic_inst[0], n)
|
||||
for port in range(self.total_ports):
|
||||
# Connect the control pins as inputs
|
||||
for signal in self.control_logic_inputs[port] + ["clk"]:
|
||||
self.copy_layout_pin(self.control_logic_inst[port], signal, signal+"{}".format(port))
|
||||
|
||||
for i in range(self.word_size):
|
||||
dout_name = "dout0[{}]".format(i)
|
||||
self.copy_layout_pin(self.bank_inst, dout_name, "DOUT0[{}]".format(i))
|
||||
for bit in range(self.word_size):
|
||||
self.copy_layout_pin(self.bank_inst, "dout{0}[{1}]".format(port,bit), "DOUT{0}[{1}]".format(port,bit))
|
||||
|
||||
# Lower address bits
|
||||
for i in range(self.col_addr_size):
|
||||
self.copy_layout_pin(self.col_addr_dff_inst, "din[{}]".format(i),"ADDR0[{}]".format(i))
|
||||
# Upper address bits
|
||||
for i in range(self.row_addr_size):
|
||||
self.copy_layout_pin(self.row_addr_dff_inst, "din[{}]".format(i),"ADDR0[{}]".format(i+self.col_addr_size))
|
||||
# Lower address bits
|
||||
for bit in range(self.col_addr_size):
|
||||
self.copy_layout_pin(self.col_addr_dff_inst[port], "din[{}]".format(bit),"ADDR{0}[{1}]".format(port,bit))
|
||||
# Upper address bits
|
||||
for bit in range(self.row_addr_size):
|
||||
self.copy_layout_pin(self.row_addr_dff_inst[port], "din[{}]".format(bit),"ADDR{0}[{1}]".format(port,bit+self.col_addr_size))
|
||||
|
||||
for i in range(self.word_size):
|
||||
din_name = "din[{}]".format(i)
|
||||
self.copy_layout_pin(self.data_dff_inst, din_name, "DIN0[{}]".format(i))
|
||||
for bit in range(self.word_size):
|
||||
self.copy_layout_pin(self.data_dff_inst[port], "din[{}]".format(bit), "DIN{0}[{1}]".format(port,bit))
|
||||
|
||||
def route(self):
|
||||
""" Route a single bank SRAM """
|
||||
|
|
@ -134,102 +132,106 @@ class sram_1bank(sram_base):
|
|||
""" Route the clock network """
|
||||
|
||||
# This is the actual input to the SRAM
|
||||
self.copy_layout_pin(self.control_logic_inst[0], "clk")
|
||||
for port in range(self.total_ports):
|
||||
self.copy_layout_pin(self.control_logic_inst[port], "clk", "clk{}".format(port))
|
||||
|
||||
# Connect all of these clock pins to the clock in the central bus
|
||||
# This is something like a "spine" clock distribution. The two spines
|
||||
# are clk_buf and clk_buf_bar
|
||||
|
||||
bank_clk_buf_pin = self.bank_inst.get_pin("clk_buf")
|
||||
bank_clk_buf_pos = bank_clk_buf_pin.center()
|
||||
bank_clk_buf_bar_pin = self.bank_inst.get_pin("clk_buf_bar")
|
||||
bank_clk_buf_bar_pos = bank_clk_buf_bar_pin.center()
|
||||
# Connect all of these clock pins to the clock in the central bus
|
||||
# This is something like a "spine" clock distribution. The two spines
|
||||
# are clk_buf and clk_buf_bar
|
||||
|
||||
bank_clk_buf_pin = self.bank_inst.get_pin("clk_buf{}".format(port))
|
||||
bank_clk_buf_pos = bank_clk_buf_pin.center()
|
||||
bank_clk_buf_bar_pin = self.bank_inst.get_pin("clk_buf_bar{}".format(port))
|
||||
bank_clk_buf_bar_pos = bank_clk_buf_bar_pin.center()
|
||||
|
||||
if self.col_addr_dff:
|
||||
dff_clk_pin = self.col_addr_dff_inst.get_pin("clk")
|
||||
dff_clk_pos = dff_clk_pin.center()
|
||||
mid_pos = vector(bank_clk_buf_pos.x, dff_clk_pos.y)
|
||||
self.add_wire(("metal3","via2","metal2"),[dff_clk_pos, mid_pos, bank_clk_buf_pos])
|
||||
|
||||
data_dff_clk_pin = self.data_dff_inst.get_pin("clk")
|
||||
data_dff_clk_pos = data_dff_clk_pin.center()
|
||||
mid_pos = vector(bank_clk_buf_pos.x, data_dff_clk_pos.y)
|
||||
self.add_wire(("metal3","via2","metal2"),[data_dff_clk_pos, mid_pos, bank_clk_buf_pos])
|
||||
if self.col_addr_dff:
|
||||
dff_clk_pin = self.col_addr_dff_inst[port].get_pin("clk")
|
||||
dff_clk_pos = dff_clk_pin.center()
|
||||
mid_pos = vector(bank_clk_buf_pos.x, dff_clk_pos.y)
|
||||
self.add_wire(("metal3","via2","metal2"),[dff_clk_pos, mid_pos, bank_clk_buf_pos])
|
||||
|
||||
data_dff_clk_pin = self.data_dff_inst[port].get_pin("clk")
|
||||
data_dff_clk_pos = data_dff_clk_pin.center()
|
||||
mid_pos = vector(bank_clk_buf_pos.x, data_dff_clk_pos.y)
|
||||
self.add_wire(("metal3","via2","metal2"),[data_dff_clk_pos, mid_pos, bank_clk_buf_pos])
|
||||
|
||||
# This uses a metal2 track to the right of the control/row addr DFF
|
||||
# to route vertically.
|
||||
control_clk_buf_pin = self.control_logic_inst[0].get_pin("clk_buf")
|
||||
control_clk_buf_pos = control_clk_buf_pin.rc()
|
||||
row_addr_clk_pin = self.row_addr_dff_inst.get_pin("clk")
|
||||
row_addr_clk_pos = row_addr_clk_pin.rc()
|
||||
mid1_pos = vector(self.row_addr_dff_inst.rx() + self.m2_pitch,
|
||||
row_addr_clk_pos.y)
|
||||
mid2_pos = vector(mid1_pos.x,
|
||||
control_clk_buf_pos.y)
|
||||
# Note, the via to the control logic is taken care of when we route
|
||||
# the control logic to the bank
|
||||
self.add_wire(("metal3","via2","metal2"),[row_addr_clk_pos, mid1_pos, mid2_pos, control_clk_buf_pos])
|
||||
# This uses a metal2 track to the right of the control/row addr DFF
|
||||
# to route vertically.
|
||||
control_clk_buf_pin = self.control_logic_inst[port].get_pin("clk_buf")
|
||||
control_clk_buf_pos = control_clk_buf_pin.rc()
|
||||
row_addr_clk_pin = self.row_addr_dff_inst[port].get_pin("clk")
|
||||
row_addr_clk_pos = row_addr_clk_pin.rc()
|
||||
mid1_pos = vector(self.row_addr_dff_inst[port].rx() + self.m2_pitch,
|
||||
row_addr_clk_pos.y)
|
||||
mid2_pos = vector(mid1_pos.x,
|
||||
control_clk_buf_pos.y)
|
||||
# Note, the via to the control logic is taken care of when we route
|
||||
# the control logic to the bank
|
||||
self.add_wire(("metal3","via2","metal2"),[row_addr_clk_pos, mid1_pos, mid2_pos, control_clk_buf_pos])
|
||||
|
||||
|
||||
def route_control_logic(self):
|
||||
""" Route the outputs from the control logic module """
|
||||
for n in self.control_logic_outputs:
|
||||
src_pin = self.control_logic_inst[0].get_pin(n)
|
||||
dest_pin = self.bank_inst.get_pin(n)
|
||||
self.connect_rail_from_left_m2m3(src_pin, dest_pin)
|
||||
self.add_via_center(layers=("metal1","via1","metal2"),
|
||||
offset=src_pin.rc(),
|
||||
rotate=90)
|
||||
for port in range(self.total_ports):
|
||||
for signal in self.control_logic_outputs[port]:
|
||||
src_pin = self.control_logic_inst[port].get_pin(signal)
|
||||
dest_pin = self.bank_inst.get_pin(signal+"{}".format(port))
|
||||
self.connect_rail_from_left_m2m3(src_pin, dest_pin)
|
||||
self.add_via_center(layers=("metal1","via1","metal2"),
|
||||
offset=src_pin.rc(),
|
||||
rotate=90)
|
||||
|
||||
|
||||
def route_row_addr_dff(self):
|
||||
""" Connect the output of the row flops to the bank pins """
|
||||
for i in range(self.row_addr_size):
|
||||
flop_name = "dout[{}]".format(i)
|
||||
bank_name = "addr0[{}]".format(i+self.col_addr_size)
|
||||
flop_pin = self.row_addr_dff_inst.get_pin(flop_name)
|
||||
bank_pin = self.bank_inst.get_pin(bank_name)
|
||||
flop_pos = flop_pin.center()
|
||||
bank_pos = bank_pin.center()
|
||||
mid_pos = vector(bank_pos.x,flop_pos.y)
|
||||
self.add_wire(("metal3","via2","metal2"),[flop_pos, mid_pos,bank_pos])
|
||||
self.add_via_center(layers=("metal2","via2","metal3"),
|
||||
offset=flop_pos,
|
||||
rotate=90)
|
||||
for port in range(self.total_ports):
|
||||
for bit in range(self.row_addr_size):
|
||||
flop_name = "dout[{}]".format(bit)
|
||||
bank_name = "addr{0}[{1}]".format(port,bit+self.col_addr_size)
|
||||
flop_pin = self.row_addr_dff_inst[port].get_pin(flop_name)
|
||||
bank_pin = self.bank_inst.get_pin(bank_name)
|
||||
flop_pos = flop_pin.center()
|
||||
bank_pos = bank_pin.center()
|
||||
mid_pos = vector(bank_pos.x,flop_pos.y)
|
||||
self.add_wire(("metal3","via2","metal2"),[flop_pos, mid_pos,bank_pos])
|
||||
self.add_via_center(layers=("metal2","via2","metal3"),
|
||||
offset=flop_pos,
|
||||
rotate=90)
|
||||
|
||||
def route_col_addr_dff(self):
|
||||
""" Connect the output of the row flops to the bank pins """
|
||||
for port in range(self.total_ports):
|
||||
bus_names = ["addr[{}]".format(x) for x in range(self.col_addr_size)]
|
||||
col_addr_bus_offsets = self.create_horizontal_bus(layer="metal1",
|
||||
pitch=self.m1_pitch,
|
||||
offset=self.col_addr_dff_inst[port].ul() + vector(0, self.m1_pitch),
|
||||
names=bus_names,
|
||||
length=self.col_addr_dff_inst[port].width)
|
||||
|
||||
bus_names = ["addr[{}]".format(x) for x in range(self.col_addr_size)]
|
||||
col_addr_bus_offsets = self.create_horizontal_bus(layer="metal1",
|
||||
pitch=self.m1_pitch,
|
||||
offset=self.col_addr_dff_inst.ul() + vector(0, self.m1_pitch),
|
||||
names=bus_names,
|
||||
length=self.col_addr_dff_inst.width)
|
||||
|
||||
dff_names = ["dout[{}]".format(x) for x in range(self.col_addr_size)]
|
||||
data_dff_map = zip(dff_names, bus_names)
|
||||
self.connect_horizontal_bus(data_dff_map, self.col_addr_dff_inst, col_addr_bus_offsets)
|
||||
|
||||
bank_names = ["addr0[{}]".format(x) for x in range(self.col_addr_size)]
|
||||
data_bank_map = zip(bank_names, bus_names)
|
||||
self.connect_horizontal_bus(data_bank_map, self.bank_inst, col_addr_bus_offsets)
|
||||
dff_names = ["dout[{}]".format(x) for x in range(self.col_addr_size)]
|
||||
data_dff_map = zip(dff_names, bus_names)
|
||||
self.connect_horizontal_bus(data_dff_map, self.col_addr_dff_inst[port], col_addr_bus_offsets)
|
||||
|
||||
bank_names = ["addr{0}[{1}]".format(port,x) for x in range(self.col_addr_size)]
|
||||
data_bank_map = zip(bank_names, bus_names)
|
||||
self.connect_horizontal_bus(data_bank_map, self.bank_inst, col_addr_bus_offsets)
|
||||
|
||||
|
||||
def route_data_dff(self):
|
||||
""" Connect the output of the data flops to the write driver """
|
||||
# This is where the channel will start (y-dimension at least)
|
||||
offset = self.data_dff_inst.ul() + vector(0, self.m1_pitch)
|
||||
for port in range(self.total_write):
|
||||
offset = self.data_dff_inst[port].ul() + vector(0, self.m1_pitch)
|
||||
|
||||
dff_names = ["dout[{}]".format(x) for x in range(self.word_size)]
|
||||
bank_names = ["din0[{}]".format(x) for x in range(self.word_size)]
|
||||
dff_names = ["dout[{}]".format(x) for x in range(self.word_size)]
|
||||
bank_names = ["din{0}[{1}]".format(port,x) for x in range(self.word_size)]
|
||||
|
||||
route_map = list(zip(bank_names, dff_names))
|
||||
dff_pins = {key: self.data_dff_inst.get_pin(key) for key in dff_names }
|
||||
bank_pins = {key: self.bank_inst.get_pin(key) for key in bank_names }
|
||||
# Combine the dff and bank pins into a single dictionary of pin name to pin.
|
||||
all_pins = {**dff_pins, **bank_pins}
|
||||
self.create_horizontal_channel_route(route_map, all_pins, offset)
|
||||
route_map = list(zip(bank_names, dff_names))
|
||||
dff_pins = {key: self.data_dff_inst[port].get_pin(key) for key in dff_names }
|
||||
bank_pins = {key: self.bank_inst.get_pin(key) for key in bank_names }
|
||||
# Combine the dff and bank pins into a single dictionary of pin name to pin.
|
||||
all_pins = {**dff_pins, **bank_pins}
|
||||
self.create_horizontal_channel_route(route_map, all_pins, offset)
|
||||
|
||||
|
||||
|
||||
|
|
@ -240,7 +242,7 @@ class sram_1bank(sram_base):
|
|||
will show these as ports in the extracted netlist.
|
||||
"""
|
||||
|
||||
for n in self.control_logic_outputs:
|
||||
for n in self.control_logic_outputs[0]:
|
||||
pin = self.control_logic_inst[0].get_pin(n)
|
||||
self.add_label(text=n,
|
||||
layer=pin.layer,
|
||||
|
|
|
|||
|
|
@ -19,26 +19,11 @@ class sram_base(design):
|
|||
self.sram_config = sram_config
|
||||
sram_config.set_local_config(self)
|
||||
|
||||
self.total_write = OPTS.num_rw_ports + OPTS.num_w_ports
|
||||
self.total_read = OPTS.num_rw_ports + OPTS.num_r_ports
|
||||
self.total_ports = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports
|
||||
|
||||
self.bank_insts = []
|
||||
|
||||
|
||||
def add_pins(self):
|
||||
""" Add pins for entire SRAM. """
|
||||
self.read_index = []
|
||||
port_number = 0
|
||||
for port in range(OPTS.num_rw_ports):
|
||||
self.read_index.append("{}".format(port_number))
|
||||
port_number += 1
|
||||
for port in range(OPTS.num_w_ports):
|
||||
port_number += 1
|
||||
for port in range(OPTS.num_r_ports):
|
||||
self.read_index.append("{}".format(port_number))
|
||||
port_number += 1
|
||||
|
||||
for port in range(self.total_write):
|
||||
for bit in range(self.word_size):
|
||||
self.add_pin("DIN{0}[{1}]".format(port,bit),"INPUT")
|
||||
|
|
@ -47,15 +32,26 @@ class sram_base(design):
|
|||
for bit in range(self.addr_size):
|
||||
self.add_pin("ADDR{0}[{1}]".format(port,bit),"INPUT")
|
||||
|
||||
# These are used to create the physical pins too
|
||||
self.control_logic_inputs=self.control_logic.get_inputs()
|
||||
self.control_logic_outputs=self.control_logic.get_outputs()
|
||||
# These are used to create the physical pins
|
||||
self.control_logic_inputs = []
|
||||
self.control_logic_outputs = []
|
||||
for port in range(self.total_ports):
|
||||
if self.port_id[port] == "rw":
|
||||
self.control_logic_inputs.append(self.control_logic_rw.get_inputs())
|
||||
self.control_logic_outputs.append(self.control_logic_rw.get_outputs())
|
||||
elif self.port_id[port] == "w":
|
||||
self.control_logic_inputs.append(self.control_logic_w.get_inputs())
|
||||
self.control_logic_outputs.append(self.control_logic_w.get_outputs())
|
||||
else:
|
||||
self.control_logic_inputs.append(self.control_logic_r.get_inputs())
|
||||
self.control_logic_outputs.append(self.control_logic_r.get_outputs())
|
||||
|
||||
#self.add_pin_list(self.control_logic_inputs,"INPUT")
|
||||
self.add_pin("csb","INPUT")
|
||||
for port in range(self.total_write):
|
||||
for port in range(self.total_ports):
|
||||
self.add_pin("csb{}".format(port),"INPUT")
|
||||
for port in range(self.num_rw_ports):
|
||||
self.add_pin("web{}".format(port),"INPUT")
|
||||
self.add_pin("clk","INPUT")
|
||||
for port in range(self.total_ports):
|
||||
self.add_pin("clk{}".format(port),"INPUT")
|
||||
|
||||
for port in range(self.total_read):
|
||||
for bit in range(self.word_size):
|
||||
|
|
@ -75,6 +71,7 @@ class sram_base(design):
|
|||
# This is for the lib file if we don't create layout
|
||||
self.width=0
|
||||
self.height=0
|
||||
|
||||
|
||||
def create_layout(self):
|
||||
""" Layout creation """
|
||||
|
|
@ -151,65 +148,67 @@ class sram_base(design):
|
|||
"Bank is too small compared to control logic.")
|
||||
|
||||
|
||||
|
||||
def add_busses(self):
|
||||
""" Add the horizontal and vertical busses """
|
||||
# Vertical bus
|
||||
# The order of the control signals on the control bus:
|
||||
self.control_bus_names = ["clk_buf", "clk_buf_bar", "w_en0", "s_en0"]
|
||||
self.vert_control_bus_positions = self.create_vertical_bus(layer="metal2",
|
||||
pitch=self.m2_pitch,
|
||||
offset=self.vertical_bus_offset,
|
||||
names=self.control_bus_names,
|
||||
length=self.vertical_bus_height)
|
||||
self.control_bus_names = []
|
||||
for port in range(self.total_ports):
|
||||
self.control_bus_names[port] = ["clk_buf{}".format(port), "clk_buf_bar{}".format(port)]
|
||||
if (self.port_id[port] == "rw") or (self.port_id[port] == "w"):
|
||||
self.control_bus_names[port].append("w_en{}".format(port))
|
||||
if (self.port_id[port] == "rw") or (self.port_id[port] == "r"):
|
||||
self.control_bus_names[port].append("s_en{}".format(port))
|
||||
self.vert_control_bus_positions = self.create_vertical_bus(layer="metal2",
|
||||
pitch=self.m2_pitch,
|
||||
offset=self.vertical_bus_offset,
|
||||
names=self.control_bus_names[port],
|
||||
length=self.vertical_bus_height)
|
||||
|
||||
self.addr_bus_names=["A[{}]".format(i) for i in range(self.addr_size)]
|
||||
self.vert_control_bus_positions.update(self.create_vertical_pin_bus(layer="metal2",
|
||||
pitch=self.m2_pitch,
|
||||
offset=self.addr_bus_offset,
|
||||
names=self.addr_bus_names,
|
||||
length=self.addr_bus_height))
|
||||
self.addr_bus_names=["A{0}[{1}]".format(port,i) for i in range(self.addr_size)]
|
||||
self.vert_control_bus_positions.update(self.create_vertical_pin_bus(layer="metal2",
|
||||
pitch=self.m2_pitch,
|
||||
offset=self.addr_bus_offset,
|
||||
names=self.addr_bus_names,
|
||||
length=self.addr_bus_height))
|
||||
|
||||
|
||||
self.bank_sel_bus_names = ["bank_sel[{}]".format(i) for i in range(self.num_banks)]
|
||||
self.vert_control_bus_positions.update(self.create_vertical_pin_bus(layer="metal2",
|
||||
pitch=self.m2_pitch,
|
||||
offset=self.bank_sel_bus_offset,
|
||||
names=self.bank_sel_bus_names,
|
||||
length=self.vertical_bus_height))
|
||||
|
||||
|
||||
self.bank_sel_bus_names = ["bank_sel{0}[{1}]".format(port,i) for i in range(self.num_banks)]
|
||||
self.vert_control_bus_positions.update(self.create_vertical_pin_bus(layer="metal2",
|
||||
pitch=self.m2_pitch,
|
||||
offset=self.bank_sel_bus_offset,
|
||||
names=self.bank_sel_bus_names,
|
||||
length=self.vertical_bus_height))
|
||||
|
||||
|
||||
# Horizontal data bus
|
||||
self.data_bus_names = ["DATA[{}]".format(i) for i in range(self.word_size)]
|
||||
self.data_bus_positions = self.create_horizontal_pin_bus(layer="metal3",
|
||||
pitch=self.m3_pitch,
|
||||
offset=self.data_bus_offset,
|
||||
names=self.data_bus_names,
|
||||
length=self.data_bus_width)
|
||||
|
||||
# Horizontal control logic bus
|
||||
# vdd/gnd in bus go along whole SRAM
|
||||
# FIXME: Fatten these wires?
|
||||
self.horz_control_bus_positions = self.create_horizontal_bus(layer="metal1",
|
||||
pitch=self.m1_pitch,
|
||||
offset=self.supply_bus_offset,
|
||||
names=["vdd"],
|
||||
length=self.supply_bus_width)
|
||||
# The gnd rail must not be the entire width since we protrude the right-most vdd rail up for
|
||||
# the decoder in 4-bank SRAMs
|
||||
self.horz_control_bus_positions.update(self.create_horizontal_bus(layer="metal1",
|
||||
pitch=self.m1_pitch,
|
||||
offset=self.supply_bus_offset+vector(0,self.m1_pitch),
|
||||
names=["gnd"],
|
||||
length=self.supply_bus_width))
|
||||
self.horz_control_bus_positions.update(self.create_horizontal_bus(layer="metal1",
|
||||
pitch=self.m1_pitch,
|
||||
offset=self.control_bus_offset,
|
||||
names=self.control_bus_names,
|
||||
length=self.control_bus_width))
|
||||
|
||||
|
||||
# Horizontal data bus
|
||||
self.data_bus_names = ["DATA{0}[{1}]".format(port,i) for i in range(self.word_size)]
|
||||
self.data_bus_positions = self.create_horizontal_pin_bus(layer="metal3",
|
||||
pitch=self.m3_pitch,
|
||||
offset=self.data_bus_offset,
|
||||
names=self.data_bus_names,
|
||||
length=self.data_bus_width)
|
||||
|
||||
# Horizontal control logic bus
|
||||
# vdd/gnd in bus go along whole SRAM
|
||||
# FIXME: Fatten these wires?
|
||||
self.horz_control_bus_positions = self.create_horizontal_bus(layer="metal1",
|
||||
pitch=self.m1_pitch,
|
||||
offset=self.supply_bus_offset,
|
||||
names=["vdd"],
|
||||
length=self.supply_bus_width)
|
||||
# The gnd rail must not be the entire width since we protrude the right-most vdd rail up for
|
||||
# the decoder in 4-bank SRAMs
|
||||
self.horz_control_bus_positions.update(self.create_horizontal_bus(layer="metal1",
|
||||
pitch=self.m1_pitch,
|
||||
offset=self.supply_bus_offset+vector(0,self.m1_pitch),
|
||||
names=["gnd"],
|
||||
length=self.supply_bus_width))
|
||||
self.horz_control_bus_positions.update(self.create_horizontal_bus(layer="metal1",
|
||||
pitch=self.m1_pitch,
|
||||
offset=self.control_bus_offset,
|
||||
names=self.control_bus_names[port],
|
||||
length=self.control_bus_width))
|
||||
|
||||
|
||||
def route_vdd_gnd(self):
|
||||
|
|
@ -250,33 +249,41 @@ class sram_base(design):
|
|||
self.msb_decoder = self.bank.decoder.pre2_4
|
||||
self.add_mod(self.msb_decoder)
|
||||
|
||||
|
||||
def add_modules(self):
|
||||
""" Create all the modules that will be used """
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
||||
self.bitcell = self.mod_bitcell()
|
||||
|
||||
c = reload(__import__(OPTS.control_logic))
|
||||
self.mod_control_logic = getattr(c, OPTS.control_logic)
|
||||
#c = reload(__import__(OPTS.control_logic))
|
||||
#self.mod_control_logic = getattr(c, OPTS.control_logic)
|
||||
|
||||
|
||||
from control_logic import control_logic
|
||||
# Create the control logic module
|
||||
self.control_logic = self.mod_control_logic(num_rows=self.num_rows)
|
||||
self.add_mod(self.control_logic)
|
||||
# Create the control logic module for each port type
|
||||
if OPTS.num_rw_ports>0:
|
||||
self.control_logic = self.control_logic_rw = control_logic(num_rows=self.num_rows, port_type="rw")
|
||||
self.add_mod(self.control_logic_rw)
|
||||
if OPTS.num_w_ports>0:
|
||||
self.control_logic_w = control_logic(num_rows=self.num_rows, port_type="w")
|
||||
self.add_mod(self.control_logic_w)
|
||||
if OPTS.num_r_ports>0:
|
||||
self.control_logic_r = control_logic(num_rows=self.num_rows, port_type="r")
|
||||
self.add_mod(self.control_logic_r)
|
||||
|
||||
# Create the address and control flops (but not the clk)
|
||||
from dff_array import dff_array
|
||||
self.row_addr_dff = dff_array(name="row_addr_dff", rows=self.row_addr_size*self.total_ports, columns=1)
|
||||
self.row_addr_dff = dff_array(name="row_addr_dff", rows=self.row_addr_size, columns=1)
|
||||
self.add_mod(self.row_addr_dff)
|
||||
|
||||
if self.col_addr_size > 0:
|
||||
self.col_addr_dff = dff_array(name="col_addr_dff", rows=1, columns=self.col_addr_size*self.total_ports)
|
||||
self.col_addr_dff = dff_array(name="col_addr_dff", rows=1, columns=self.col_addr_size)
|
||||
self.add_mod(self.col_addr_dff)
|
||||
else:
|
||||
self.col_addr_dff = None
|
||||
|
||||
self.data_dff = dff_array(name="data_dff", rows=1, columns=self.word_size*self.total_write)
|
||||
self.data_dff = dff_array(name="data_dff", rows=1, columns=self.word_size)
|
||||
self.add_mod(self.data_dff)
|
||||
|
||||
# Create the bank module (up to four are instantiated)
|
||||
|
|
@ -295,7 +302,6 @@ class sram_base(design):
|
|||
self.supply_rail_pitch = self.bank.supply_rail_pitch
|
||||
|
||||
|
||||
|
||||
def create_bank(self,bank_num):
|
||||
""" Create a bank """
|
||||
self.bank_insts.append(self.add_inst(name="bank{0}".format(bank_num),
|
||||
|
|
@ -318,7 +324,10 @@ class sram_base(design):
|
|||
temp.append("s_en{0}".format(self.read_index[port]))
|
||||
for port in range(self.total_write):
|
||||
temp.append("w_en{0}".format(port))
|
||||
temp.extend(["clk_buf_bar","clk_buf" , "vdd", "gnd"])
|
||||
for port in range(self.total_ports):
|
||||
temp.append("clk_buf_bar{0}".format(port))
|
||||
temp.append("clk_buf{0}".format(port))
|
||||
temp.extend(["vdd", "gnd"])
|
||||
self.connect_inst(temp)
|
||||
|
||||
return self.bank_insts[-1]
|
||||
|
|
@ -357,68 +366,87 @@ class sram_base(design):
|
|||
|
||||
def create_row_addr_dff(self):
|
||||
""" Add all address flops for the main decoder """
|
||||
inst = self.add_inst(name="row_address",
|
||||
mod=self.row_addr_dff)
|
||||
|
||||
# inputs, outputs/output/bar
|
||||
inputs = []
|
||||
outputs = []
|
||||
insts = []
|
||||
for port in range(self.total_ports):
|
||||
for i in range(self.row_addr_size):
|
||||
inputs.append("ADDR{}[{}]".format(port,i+self.col_addr_size))
|
||||
outputs.append("A{}[{}]".format(port,i+self.col_addr_size))
|
||||
insts.append(self.add_inst(name="row_address{}".format(port),
|
||||
mod=self.row_addr_dff))
|
||||
|
||||
# inputs, outputs/output/bar
|
||||
inputs = []
|
||||
outputs = []
|
||||
for bit in range(self.row_addr_size):
|
||||
inputs.append("ADDR{}[{}]".format(port,bit+self.col_addr_size))
|
||||
outputs.append("A{}[{}]".format(port,bit+self.col_addr_size))
|
||||
|
||||
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port), "vdd", "gnd"])
|
||||
|
||||
return insts
|
||||
|
||||
self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"])
|
||||
return inst
|
||||
|
||||
def create_col_addr_dff(self):
|
||||
""" Add and place all address flops for the column decoder """
|
||||
inst = self.add_inst(name="col_address",
|
||||
mod=self.col_addr_dff)
|
||||
|
||||
# inputs, outputs/output/bar
|
||||
inputs = []
|
||||
outputs = []
|
||||
insts = []
|
||||
for port in range(self.total_ports):
|
||||
for i in range(self.col_addr_size):
|
||||
inputs.append("ADDR{}[{}]".format(port,i))
|
||||
outputs.append("A{}[{}]".format(port,i))
|
||||
insts.append(self.add_inst(name="col_address{}".format(port),
|
||||
mod=self.col_addr_dff))
|
||||
|
||||
# inputs, outputs/output/bar
|
||||
inputs = []
|
||||
outputs = []
|
||||
for bit in range(self.col_addr_size):
|
||||
inputs.append("ADDR{}[{}]".format(port,bit))
|
||||
outputs.append("A{}[{}]".format(port,bit))
|
||||
|
||||
self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"])
|
||||
return inst
|
||||
|
||||
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port), "vdd", "gnd"])
|
||||
|
||||
return insts
|
||||
|
||||
|
||||
def create_data_dff(self):
|
||||
""" Add and place all data flops """
|
||||
inst = self.add_inst(name="data_dff",
|
||||
mod=self.data_dff)
|
||||
|
||||
# inputs, outputs/output/bar
|
||||
inputs = []
|
||||
outputs = []
|
||||
insts = []
|
||||
for port in range(self.total_write):
|
||||
for i in range(self.word_size):
|
||||
inputs.append("DIN{}[{}]".format(port,i))
|
||||
outputs.append("BANK_DIN{}[{}]".format(port,i))
|
||||
insts.append(self.add_inst(name="data_dff{}".format(port),
|
||||
mod=self.data_dff))
|
||||
|
||||
# inputs, outputs/output/bar
|
||||
inputs = []
|
||||
outputs = []
|
||||
for bit in range(self.word_size):
|
||||
inputs.append("DIN{}[{}]".format(port,bit))
|
||||
outputs.append("BANK_DIN{}[{}]".format(port,bit))
|
||||
|
||||
self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"])
|
||||
return inst
|
||||
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port), "vdd", "gnd"])
|
||||
|
||||
def create_control_logic(self, port):
|
||||
return insts
|
||||
|
||||
|
||||
def create_control_logic(self):
|
||||
""" Add and place control logic """
|
||||
inst = self.add_inst(name="control",
|
||||
mod=self.control_logic)
|
||||
|
||||
self.connect_inst(["csb", "web{}".format(port), "clk",
|
||||
"s_en{}".format(port), "w_en{}".format(port), "clk_buf_bar", "clk_buf",
|
||||
"vdd", "gnd"])
|
||||
insts = []
|
||||
for port in range(self.total_ports):
|
||||
if self.port_id[port] == "rw":
|
||||
mod = self.control_logic_rw
|
||||
elif self.port_id[port] == "w":
|
||||
mod = self.control_logic_w
|
||||
else:
|
||||
mod = self.control_logic_r
|
||||
|
||||
insts.append(self.add_inst(name="control{}".format(port),
|
||||
mod=mod))
|
||||
|
||||
temp = ["csb{}".format(port)]
|
||||
if self.port_id[port] == "rw":
|
||||
temp.append("web{}".format(port))
|
||||
temp.append("clk{}".format(port))
|
||||
if (self.port_id[port] == "rw") or (self.port_id[port] == "r"):
|
||||
temp.append("s_en{}".format(port))
|
||||
if (self.port_id[port] == "rw") or (self.port_id[port] == "w"):
|
||||
temp.append("w_en{}".format(port))
|
||||
temp.extend(["clk_buf_bar{}".format(port), "clk_buf{}".format(port), "vdd", "gnd"])
|
||||
self.connect_inst(temp)
|
||||
|
||||
#self.connect_inst(self.control_logic_inputs + self.control_logic_outputs + ["vdd", "gnd"])
|
||||
return inst
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return insts
|
||||
|
||||
|
||||
def connect_rail_from_left_m2m3(self, src_pin, dest_pin):
|
||||
|
|
@ -429,14 +457,14 @@ class sram_base(design):
|
|||
self.add_via_center(layers=("metal2","via2","metal3"),
|
||||
offset=src_pin.rc(),
|
||||
rotate=90)
|
||||
|
||||
|
||||
|
||||
def connect_rail_from_left_m2m1(self, src_pin, dest_pin):
|
||||
""" Helper routine to connect an unrotated/mirrored oriented instance to the rails """
|
||||
in_pos = src_pin.rc()
|
||||
out_pos = vector(dest_pin.cx(), in_pos.y)
|
||||
self.add_wire(("metal2","via1","metal1"),[in_pos, out_pos, out_pos - vector(0,self.m2_pitch)])
|
||||
|
||||
|
||||
|
||||
def sp_write(self, sp_name):
|
||||
# Write the entire spice of the object to the file
|
||||
|
|
@ -462,6 +490,7 @@ class sram_base(design):
|
|||
del usedMODS
|
||||
sp.close()
|
||||
|
||||
|
||||
def analytical_delay(self,slew,load):
|
||||
""" LH and HL are the same in analytical model. """
|
||||
return self.bank.analytical_delay(slew,load)
|
||||
|
|
|
|||
|
|
@ -18,24 +18,24 @@ class precharge_test(openram_test):
|
|||
import precharge
|
||||
import tech
|
||||
|
||||
# check precharge in single port
|
||||
debug.info(2, "Checking precharge for handmade bitcell")
|
||||
tx = precharge.precharge(name="precharge_driver", size=1)
|
||||
self.local_check(tx)
|
||||
|
||||
if OPTS.multiport_check:
|
||||
debug.info(2, "Checking precharge for pbitcell")
|
||||
OPTS.bitcell = "pbitcell"
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_r_ports = 1
|
||||
OPTS.num_w_ports = 1
|
||||
tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="bl0", bitcell_br="br0")
|
||||
self.local_check(tx)
|
||||
|
||||
tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="bl1", bitcell_br="br1")
|
||||
self.local_check(tx)
|
||||
|
||||
tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="bl2", bitcell_br="br2")
|
||||
self.local_check(tx)
|
||||
# check precharge in multi-port
|
||||
OPTS.bitcell = "pbitcell"
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_r_ports = 1
|
||||
OPTS.num_w_ports = 1
|
||||
|
||||
debug.info(2, "Checking precharge for pbitcell (innermost connections)")
|
||||
tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="bl0", bitcell_br="br0")
|
||||
self.local_check(tx)
|
||||
|
||||
debug.info(2, "Checking precharge for pbitcell (outermost connections)")
|
||||
tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="bl2", bitcell_br="br2")
|
||||
self.local_check(tx)
|
||||
|
||||
globals.end_openram()
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
@ -19,25 +19,25 @@ class single_level_column_mux_test(openram_test):
|
|||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
import single_level_column_mux
|
||||
import tech
|
||||
|
||||
|
||||
# check single level column mux in single port
|
||||
debug.info(2, "Checking column mux")
|
||||
tx = single_level_column_mux.single_level_column_mux(tx_size=8)
|
||||
self.local_check(tx)
|
||||
|
||||
if OPTS.multiport_check:
|
||||
debug.info(2, "Checking column mux for pbitcell")
|
||||
OPTS.bitcell = "pbitcell"
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_r_ports = 1
|
||||
OPTS.num_w_ports = 1
|
||||
tx = single_level_column_mux.single_level_column_mux(tx_size=8, bitcell_bl="bl0", bitcell_br="br0")
|
||||
self.local_check(tx)
|
||||
|
||||
tx = single_level_column_mux.single_level_column_mux(tx_size=8, bitcell_bl="bl1", bitcell_br="br1")
|
||||
self.local_check(tx)
|
||||
|
||||
tx = single_level_column_mux.single_level_column_mux(tx_size=8, bitcell_bl="bl2", bitcell_br="br2")
|
||||
self.local_check(tx)
|
||||
# check single level column mux in multi-port
|
||||
OPTS.bitcell = "pbitcell"
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_r_ports = 1
|
||||
OPTS.num_w_ports = 1
|
||||
|
||||
debug.info(2, "Checking column mux for pbitcell (innermost connections)")
|
||||
tx = single_level_column_mux.single_level_column_mux(tx_size=8, bitcell_bl="bl0", bitcell_br="br0")
|
||||
self.local_check(tx)
|
||||
|
||||
debug.info(2, "Checking column mux for pbitcell (outermost connections)")
|
||||
tx = single_level_column_mux.single_level_column_mux(tx_size=8, bitcell_bl="bl2", bitcell_br="br2")
|
||||
self.local_check(tx)
|
||||
|
||||
globals.end_openram()
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ class hierarchical_decoder_test(openram_test):
|
|||
# a = hierarchical_decoder.hierarchical_decoder(rows=8)
|
||||
# self.local_check(a)
|
||||
|
||||
# check hierarchical decoder for single port
|
||||
debug.info(1, "Testing 16 row sample for hierarchical_decoder")
|
||||
a = hierarchical_decoder.hierarchical_decoder(rows=16)
|
||||
self.local_check(a)
|
||||
|
|
@ -43,6 +44,28 @@ class hierarchical_decoder_test(openram_test):
|
|||
debug.info(1, "Testing 512 row sample for hierarchical_decoder")
|
||||
a = hierarchical_decoder.hierarchical_decoder(rows=512)
|
||||
self.local_check(a)
|
||||
|
||||
# check hierarchical decoder for multi-port
|
||||
OPTS.bitcell = "pbitcell"
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_w_ports = 0
|
||||
OPTS.num_r_ports = 0
|
||||
|
||||
debug.info(1, "Testing 16 row sample for hierarchical_decoder (multi-port case)")
|
||||
a = hierarchical_decoder.hierarchical_decoder(rows=16)
|
||||
self.local_check(a)
|
||||
|
||||
debug.info(1, "Testing 32 row sample for hierarchical_decoder (multi-port case)")
|
||||
a = hierarchical_decoder.hierarchical_decoder(rows=32)
|
||||
self.local_check(a)
|
||||
|
||||
debug.info(1, "Testing 128 row sample for hierarchical_decoder (multi-port case)")
|
||||
a = hierarchical_decoder.hierarchical_decoder(rows=128)
|
||||
self.local_check(a)
|
||||
|
||||
debug.info(1, "Testing 512 row sample for hierarchical_decoder (multi-port case)")
|
||||
a = hierarchical_decoder.hierarchical_decoder(rows=512)
|
||||
self.local_check(a)
|
||||
|
||||
globals.end_openram()
|
||||
|
||||
|
|
|
|||
|
|
@ -18,10 +18,21 @@ class hierarchical_predecode2x4_test(openram_test):
|
|||
import hierarchical_predecode2x4 as pre
|
||||
import tech
|
||||
|
||||
# checking hierarchical precode 2x4 for single port
|
||||
debug.info(1, "Testing sample for hierarchy_predecode2x4")
|
||||
a = pre.hierarchical_predecode2x4()
|
||||
self.local_check(a)
|
||||
|
||||
# checking hierarchical precode 2x4 for multi-port
|
||||
OPTS.bitcell = "pbitcell"
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_w_ports = 0
|
||||
OPTS.num_r_ports = 0
|
||||
|
||||
debug.info(1, "Testing sample for hierarchy_predecode2x4 (multi-port case)")
|
||||
a = pre.hierarchical_predecode2x4()
|
||||
self.local_check(a)
|
||||
|
||||
globals.end_openram()
|
||||
|
||||
# instantiate a copdsay of the class to actually run the test
|
||||
|
|
|
|||
|
|
@ -18,9 +18,20 @@ class hierarchical_predecode3x8_test(openram_test):
|
|||
import hierarchical_predecode3x8 as pre
|
||||
import tech
|
||||
|
||||
# checking hierarchical precode 3x8 for single port
|
||||
debug.info(1, "Testing sample for hierarchy_predecode3x8")
|
||||
a = pre.hierarchical_predecode3x8()
|
||||
self.local_check(a)
|
||||
|
||||
# checking hierarchical precode 3x8 for multi-port
|
||||
OPTS.bitcell = "pbitcell"
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_w_ports = 0
|
||||
OPTS.num_r_ports = 0
|
||||
|
||||
debug.info(1, "Testing sample for hierarchy_predecode3x8 (multi-port case)")
|
||||
a = pre.hierarchical_predecode3x8()
|
||||
self.local_check(a)
|
||||
|
||||
globals.end_openram()
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ class single_level_column_mux_test(openram_test):
|
|||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
import single_level_column_mux_array
|
||||
|
||||
# check single level column mux array in single port
|
||||
debug.info(1, "Testing sample for 2-way column_mux_array")
|
||||
a = single_level_column_mux_array.single_level_column_mux_array(columns=16, word_size=8)
|
||||
self.local_check(a)
|
||||
|
|
@ -28,32 +29,27 @@ class single_level_column_mux_test(openram_test):
|
|||
a = single_level_column_mux_array.single_level_column_mux_array(columns=32, word_size=4)
|
||||
self.local_check(a)
|
||||
|
||||
if OPTS.multiport_check:
|
||||
debug.info(2, "Checking column mux array for pbitcell")
|
||||
OPTS.bitcell = "pbitcell"
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_r_ports = 1
|
||||
OPTS.num_w_ports = 1
|
||||
|
||||
debug.info(1, "Testing sample for 2-way column_mux_array")
|
||||
a = single_level_column_mux_array.single_level_column_mux_array(columns=16, word_size=8, bitcell_bl="bl0", bitcell_br="br0")
|
||||
self.local_check(a)
|
||||
# check single level column mux array in multi-port
|
||||
OPTS.bitcell = "pbitcell"
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_r_ports = 1
|
||||
OPTS.num_w_ports = 1
|
||||
|
||||
debug.info(1, "Testing sample for 2-way column_mux_array in multi-port")
|
||||
a = single_level_column_mux_array.single_level_column_mux_array(columns=16, word_size=8, bitcell_bl="bl0", bitcell_br="br0")
|
||||
self.local_check(a)
|
||||
|
||||
debug.info(1, "Testing sample for 4-way column_mux_array")
|
||||
a = single_level_column_mux_array.single_level_column_mux_array(columns=16, word_size=4, bitcell_bl="bl0", bitcell_br="br0")
|
||||
self.local_check(a)
|
||||
debug.info(1, "Testing sample for 4-way column_mux_array in multi-port")
|
||||
a = single_level_column_mux_array.single_level_column_mux_array(columns=16, word_size=4, bitcell_bl="bl0", bitcell_br="br0")
|
||||
self.local_check(a)
|
||||
|
||||
debug.info(1, "Testing sample for 8-way column_mux_array")
|
||||
a = single_level_column_mux_array.single_level_column_mux_array(columns=32, word_size=4, bitcell_bl="bl0", bitcell_br="br0")
|
||||
self.local_check(a)
|
||||
|
||||
debug.info(1, "Testing sample for 8-way column_mux_array")
|
||||
a = single_level_column_mux_array.single_level_column_mux_array(columns=32, word_size=4, bitcell_bl="bl1", bitcell_br="br1")
|
||||
self.local_check(a)
|
||||
|
||||
debug.info(1, "Testing sample for 8-way column_mux_array")
|
||||
a = single_level_column_mux_array.single_level_column_mux_array(columns=32, word_size=4, bitcell_bl="bl2", bitcell_br="br2")
|
||||
self.local_check(a)
|
||||
debug.info(1, "Testing sample for 8-way column_mux_array in multi-port (innermost connections)")
|
||||
a = single_level_column_mux_array.single_level_column_mux_array(columns=32, word_size=4, bitcell_bl="bl0", bitcell_br="br0")
|
||||
self.local_check(a)
|
||||
|
||||
debug.info(1, "Testing sample for 8-way column_mux_array in multi-port (outermost connections)")
|
||||
a = single_level_column_mux_array.single_level_column_mux_array(columns=32, word_size=4, bitcell_bl="bl2", bitcell_br="br2")
|
||||
self.local_check(a)
|
||||
|
||||
globals.end_openram()
|
||||
|
||||
|
|
|
|||
|
|
@ -18,25 +18,24 @@ class precharge_test(openram_test):
|
|||
import precharge_array
|
||||
import tech
|
||||
|
||||
# check precharge array in single port
|
||||
debug.info(2, "Checking 3 column precharge")
|
||||
pc = precharge_array.precharge_array(columns=3)
|
||||
self.local_check(pc)
|
||||
|
||||
if OPTS.multiport_check:
|
||||
debug.info(2, "Checking precharge array for pbitcell")
|
||||
OPTS.bitcell = "pbitcell"
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_r_ports = 1
|
||||
OPTS.num_w_ports = 1
|
||||
|
||||
pc = precharge_array.precharge_array(columns=3, bitcell_bl="bl0", bitcell_br="br0")
|
||||
self.local_check(pc)
|
||||
|
||||
pc = precharge_array.precharge_array(columns=3, bitcell_bl="bl1", bitcell_br="br1")
|
||||
self.local_check(pc)
|
||||
|
||||
pc = precharge_array.precharge_array(columns=3, bitcell_bl="bl2", bitcell_br="br2")
|
||||
self.local_check(pc)
|
||||
# check precharge array in multi-port
|
||||
OPTS.bitcell = "pbitcell"
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_r_ports = 1
|
||||
OPTS.num_w_ports = 1
|
||||
|
||||
debug.info(2, "Checking 3 column precharge array for pbitcell (innermost connections)")
|
||||
pc = precharge_array.precharge_array(columns=3, bitcell_bl="bl0", bitcell_br="br0")
|
||||
self.local_check(pc)
|
||||
|
||||
debug.info(2, "Checking 3 column precharge array for pbitcell (outermost connections)")
|
||||
pc = precharge_array.precharge_array(columns=3, bitcell_bl="bl2", bitcell_br="br2")
|
||||
self.local_check(pc)
|
||||
|
||||
globals.end_openram()
|
||||
|
||||
|
|
|
|||
|
|
@ -20,19 +20,20 @@ class wordline_driver_test(openram_test):
|
|||
import wordline_driver
|
||||
import tech
|
||||
|
||||
# check wordline driver for single port
|
||||
debug.info(2, "Checking driver")
|
||||
tx = wordline_driver.wordline_driver(rows=8)
|
||||
self.local_check(tx)
|
||||
|
||||
if OPTS.multiport_check:
|
||||
OPTS.bitcell = "pbitcell"
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_w_ports = 0
|
||||
OPTS.num_r_ports = 0
|
||||
|
||||
debug.info(2, "Checking driver (multi-port case)")
|
||||
tx = wordline_driver.wordline_driver(rows=8)
|
||||
self.local_check(tx)
|
||||
# check wordline driver for multi-port
|
||||
OPTS.bitcell = "pbitcell"
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_w_ports = 0
|
||||
OPTS.num_r_ports = 0
|
||||
|
||||
debug.info(2, "Checking driver (multi-port case)")
|
||||
tx = wordline_driver.wordline_driver(rows=8)
|
||||
self.local_check(tx)
|
||||
|
||||
globals.end_openram()
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ class sense_amp_test(openram_test):
|
|||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
import sense_amp_array
|
||||
|
||||
# check sense amp array for single port
|
||||
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2")
|
||||
a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=2)
|
||||
self.local_check(a)
|
||||
|
|
@ -25,19 +26,19 @@ class sense_amp_test(openram_test):
|
|||
a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=4)
|
||||
self.local_check(a)
|
||||
|
||||
if OPTS.multiport_check:
|
||||
OPTS.bitcell = "pbitcell"
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_w_ports = 0
|
||||
OPTS.num_r_ports = 0
|
||||
|
||||
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2 (multi-port case)")
|
||||
a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=2)
|
||||
self.local_check(a)
|
||||
# check sense amp array for multi-port
|
||||
OPTS.bitcell = "pbitcell"
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_w_ports = 0
|
||||
OPTS.num_r_ports = 0
|
||||
|
||||
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2 (multi-port case)")
|
||||
a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=2)
|
||||
self.local_check(a)
|
||||
|
||||
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=4 (multi-port case)")
|
||||
a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=4)
|
||||
self.local_check(a)
|
||||
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=4 (multi-port case)")
|
||||
a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=4)
|
||||
self.local_check(a)
|
||||
|
||||
globals.end_openram()
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ class write_driver_test(openram_test):
|
|||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
import write_driver_array
|
||||
|
||||
# check write driver array for single port
|
||||
debug.info(2, "Testing write_driver_array for columns=8, word_size=8")
|
||||
a = write_driver_array.write_driver_array(columns=8, word_size=8)
|
||||
self.local_check(a)
|
||||
|
|
@ -25,19 +26,19 @@ class write_driver_test(openram_test):
|
|||
a = write_driver_array.write_driver_array(columns=16, word_size=8)
|
||||
self.local_check(a)
|
||||
|
||||
if OPTS.multiport_check:
|
||||
OPTS.bitcell = "pbitcell"
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_w_ports = 0
|
||||
OPTS.num_r_ports = 0
|
||||
|
||||
debug.info(2, "Testing write_driver_array for columns=8, word_size=8 (multi-port case)")
|
||||
a = write_driver_array.write_driver_array(columns=8, word_size=8)
|
||||
self.local_check(a)
|
||||
# check write driver array for multi-port
|
||||
OPTS.bitcell = "pbitcell"
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_w_ports = 0
|
||||
OPTS.num_r_ports = 0
|
||||
|
||||
debug.info(2, "Testing write_driver_array for columns=8, word_size=8 (multi-port case)")
|
||||
a = write_driver_array.write_driver_array(columns=8, word_size=8)
|
||||
self.local_check(a)
|
||||
|
||||
debug.info(2, "Testing write_driver_array for columns=16, word_size=8 (multi-port case)")
|
||||
a = write_driver_array.write_driver_array(columns=16, word_size=8)
|
||||
self.local_check(a)
|
||||
debug.info(2, "Testing write_driver_array for columns=16, word_size=8 (multi-port case)")
|
||||
a = write_driver_array.write_driver_array(columns=16, word_size=8)
|
||||
self.local_check(a)
|
||||
|
||||
globals.end_openram()
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,44 @@ class replica_bitline_test(openram_test):
|
|||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
import replica_bitline
|
||||
|
||||
# check replica bitline in single port
|
||||
stages=4
|
||||
fanout=4
|
||||
rows=13
|
||||
debug.info(2, "Testing RBL with {0} FO4 stages, {1} rows".format(stages,rows))
|
||||
a = replica_bitline.replica_bitline(stages,fanout,rows)
|
||||
self.local_check(a)
|
||||
|
||||
stages=8
|
||||
rows=100
|
||||
debug.info(2, "Testing RBL with {0} FO4 stages, {1} rows".format(stages,rows))
|
||||
a = replica_bitline.replica_bitline(stages,fanout,rows)
|
||||
self.local_check(a)
|
||||
|
||||
# check replica bitline in multi-port
|
||||
OPTS.bitcell = "pbitcell"
|
||||
OPTS.replica_bitcell = "replica_pbitcell"
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_w_ports = 0
|
||||
OPTS.num_r_ports = 0
|
||||
|
||||
stages=4
|
||||
fanout=4
|
||||
rows=13
|
||||
debug.info(2, "Testing RBL with {0} FO4 stages, {1} rows".format(stages,rows))
|
||||
a = replica_bitline.replica_bitline(stages,fanout,rows)
|
||||
self.local_check(a)
|
||||
|
||||
stages=8
|
||||
rows=100
|
||||
debug.info(2, "Testing RBL with {0} FO4 stages, {1} rows".format(stages,rows))
|
||||
a = replica_bitline.replica_bitline(stages,fanout,rows)
|
||||
self.local_check(a)
|
||||
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_w_ports = 1
|
||||
OPTS.num_r_ports = 1
|
||||
|
||||
stages=4
|
||||
fanout=4
|
||||
rows=13
|
||||
|
|
|
|||
|
|
@ -18,9 +18,38 @@ class control_logic_test(openram_test):
|
|||
import control_logic
|
||||
import tech
|
||||
|
||||
# check control logic for single port
|
||||
debug.info(1, "Testing sample for control_logic")
|
||||
a = control_logic.control_logic(num_rows=128)
|
||||
self.local_check(a)
|
||||
|
||||
# check control logic for multi-port
|
||||
OPTS.bitcell = "pbitcell"
|
||||
OPTS.replica_bitcell = "replica_pbitcell"
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_w_ports = 0
|
||||
OPTS.num_r_ports = 0
|
||||
|
||||
debug.info(1, "Testing sample for control_logic for multiport")
|
||||
a = control_logic.control_logic(num_rows=128)
|
||||
self.local_check(a)
|
||||
|
||||
# Check port specific control logic
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_w_ports = 1
|
||||
OPTS.num_r_ports = 1
|
||||
|
||||
debug.info(1, "Testing sample for control_logic for multiport, only write control logic")
|
||||
a = control_logic.control_logic(num_rows=128, port_type="rw")
|
||||
self.local_check(a)
|
||||
|
||||
debug.info(1, "Testing sample for control_logic for multiport, only write control logic")
|
||||
a = control_logic.control_logic(num_rows=128, port_type="w")
|
||||
self.local_check(a)
|
||||
|
||||
debug.info(1, "Testing sample for control_logic for multiport, only read control logic")
|
||||
a = control_logic.control_logic(num_rows=128, port_type="r")
|
||||
self.local_check(a)
|
||||
|
||||
globals.end_openram()
|
||||
|
||||
|
|
|
|||
|
|
@ -17,8 +17,25 @@ class bank_select_test(openram_test):
|
|||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
import bank_select
|
||||
|
||||
debug.info(1, "No column mux")
|
||||
a = bank_select.bank_select()
|
||||
debug.info(1, "No column mux, rw control logic")
|
||||
a = bank_select.bank_select(port="rw")
|
||||
self.local_check(a)
|
||||
|
||||
OPTS.bitcell = "pbitcell"
|
||||
debug.info(1, "No column mux, rw control logic")
|
||||
a = bank_select.bank_select(port="rw")
|
||||
self.local_check(a)
|
||||
|
||||
OPTS.num_rw_ports = 0
|
||||
OPTS.num_w_ports = 1
|
||||
OPTS.num_r_ports = 1
|
||||
|
||||
debug.info(1, "No column mux, w control logic")
|
||||
a = bank_select.bank_select(port="w")
|
||||
self.local_check(a)
|
||||
|
||||
debug.info(1, "No column mux, r control logic")
|
||||
a = bank_select.bank_select(port="r")
|
||||
self.local_check(a)
|
||||
|
||||
globals.end_openram()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
@ -52,18 +52,14 @@ class psingle_bank_test(openram_test):
|
|||
a = bank(c, name="bank1_1rw_0w_0r_single")
|
||||
self.local_check(a)
|
||||
|
||||
|
||||
# testing bank using pbitcell in various port combinations
|
||||
# layout for multiple ports does not work yet
|
||||
"""
|
||||
# multiport can't generate layout yet on the bank level
|
||||
OPTS.netlist_only = True
|
||||
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_w_ports = 1
|
||||
OPTS.num_r_ports = 1
|
||||
|
||||
debug.info(1, "No column mux")
|
||||
name = "bank1_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports)
|
||||
a = bank(c, name=name)
|
||||
self.local_check(a)
|
||||
|
||||
c.num_words=16
|
||||
c.words_per_row=1
|
||||
|
||||
OPTS.num_rw_ports = c.num_rw_ports = 2
|
||||
OPTS.num_w_ports = c.num_w_ports = 2
|
||||
|
|
@ -139,7 +135,7 @@ class psingle_bank_test(openram_test):
|
|||
self.local_check(a)
|
||||
"""
|
||||
|
||||
#globals.end_openram()
|
||||
globals.end_openram()
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import globals
|
|||
from globals import OPTS
|
||||
import debug
|
||||
|
||||
@unittest.skip("SKIPPING 20_psram_1bank_test, multiport layout not complete")
|
||||
#@unittest.skip("SKIPPING 20_psram_1bank_test, multiport layout not complete")
|
||||
class sram_1bank_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
|
|
@ -19,8 +19,9 @@ class sram_1bank_test(openram_test):
|
|||
from sram import sram
|
||||
from sram_config import sram_config
|
||||
OPTS.bitcell = "pbitcell"
|
||||
OPTS.replica_bitcell="replica_pbitcell"
|
||||
|
||||
# testing layout of bank using pbitcell with 1 RW port (a 6T-cell equivalent)
|
||||
# testing layout of sram using pbitcell with 1 RW port (a 6T-cell equivalent)
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_w_ports = 0
|
||||
OPTS.num_r_ports = 0
|
||||
|
|
@ -33,17 +34,79 @@ class sram_1bank_test(openram_test):
|
|||
debug.info(1, "Single bank, no column mux with control logic")
|
||||
a = sram(c, "sram1")
|
||||
self.local_check(a, final_verification=True)
|
||||
|
||||
|
||||
c.num_words=32
|
||||
c.words_per_row=2
|
||||
debug.info(1, "Single bank two way column mux with control logic")
|
||||
a = sram(c, "sram2")
|
||||
self.local_check(a, final_verification=True)
|
||||
"""
|
||||
c.num_words=64
|
||||
c.words_per_row=4
|
||||
debug.info(1, "Single bank, four way column mux with control logic")
|
||||
a = sram(c, "sram3")
|
||||
self.local_check(a, final_verification=True)
|
||||
|
||||
c.word_size=2
|
||||
c.num_words=128
|
||||
c.words_per_row=8
|
||||
debug.info(1, "Single bank, eight way column mux with control logic")
|
||||
a = sram(c, "sram4")
|
||||
self.local_check(a, final_verification=True)
|
||||
|
||||
# testing sram using pbitcell in various port combinations
|
||||
# layout for multiple ports does not work yet
|
||||
"""
|
||||
OPTS.rw_ports = 1
|
||||
OPTS.w_ports = 1
|
||||
OPTS.r_ports = 1
|
||||
OPTS.netlist_only = True
|
||||
|
||||
c.num_words=16
|
||||
c.words_per_row=1
|
||||
|
||||
OPTS.num_rw_ports = 2
|
||||
OPTS.num_w_ports = 2
|
||||
OPTS.num_r_ports = 2
|
||||
|
||||
debug.info(1, "Single bank, no column mux with control logic")
|
||||
a = sram(c, "sram1")
|
||||
self.local_check(a, final_verification=True)
|
||||
"""
|
||||
OPTS.num_rw_ports = 0
|
||||
OPTS.num_w_ports = 2
|
||||
OPTS.num_r_ports = 2
|
||||
|
||||
debug.info(1, "Single bank, no column mux with control logic")
|
||||
a = sram(c, "sram1")
|
||||
self.local_check(a, final_verification=True)
|
||||
|
||||
OPTS.num_rw_ports = 2
|
||||
OPTS.num_w_ports = 0
|
||||
OPTS.num_r_ports = 2
|
||||
|
||||
debug.info(1, "Single bank, no column mux with control logic")
|
||||
a = sram(c, "sram1")
|
||||
self.local_check(a, final_verification=True)
|
||||
|
||||
OPTS.num_rw_ports = 2
|
||||
OPTS.num_w_ports = 2
|
||||
OPTS.num_r_ports = 0
|
||||
|
||||
debug.info(1, "Single bank, no column mux with control logic")
|
||||
a = sram(c, "sram1")
|
||||
self.local_check(a, final_verification=True)
|
||||
|
||||
OPTS.num_rw_ports = 2
|
||||
OPTS.num_w_ports = 0
|
||||
OPTS.num_r_ports = 0
|
||||
|
||||
debug.info(1, "Single bank, no column mux with control logic")
|
||||
a = sram(c, "sram1")
|
||||
self.local_check(a, final_verification=True)
|
||||
|
||||
# testing with various column muxes
|
||||
OPTS.num_rw_ports = c.num_rw_ports = 2
|
||||
OPTS.num_w_ports = c.num_w_ports = 2
|
||||
OPTS.num_r_ports = c.num_r_ports = 2
|
||||
|
||||
c.num_words=32
|
||||
c.words_per_row=2
|
||||
debug.info(1, "Single bank two way column mux with control logic")
|
||||
|
|
@ -63,7 +126,7 @@ class sram_1bank_test(openram_test):
|
|||
a = sram(c, "sram4")
|
||||
self.local_check(a, final_verification=True)
|
||||
"""
|
||||
#globals.end_openram()
|
||||
globals.end_openram()
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
|
|
@ -48,31 +48,33 @@ class timing_sram_test(openram_test):
|
|||
import tech
|
||||
loads = [tech.spice["msflop_in_cap"]*4]
|
||||
slews = [tech.spice["rise_time"]*2]
|
||||
data = d.analyze(probe_address, probe_data, slews, loads)
|
||||
|
||||
data, port_data = d.analyze(probe_address, probe_data, slews, loads)
|
||||
#Combine info about port into all data
|
||||
data.update(port_data[0])
|
||||
|
||||
#Assumes single rw port (6t sram)
|
||||
if OPTS.tech_name == "freepdk45":
|
||||
golden_data = {'delay_hl0': [2.5829000000000004],
|
||||
'delay_lh0': [0.2255964],
|
||||
golden_data = {'delay_hl': [2.5829000000000004],
|
||||
'delay_lh': [0.2255964],
|
||||
'leakage_power': 0.0019498999999999996,
|
||||
'min_period': 4.844,
|
||||
'read0_power0': [0.055371399999999994],
|
||||
'read1_power0': [0.0520225],
|
||||
'slew_hl0': [0.0794261],
|
||||
'slew_lh0': [0.0236264],
|
||||
'write0_power0': [0.06545659999999999],
|
||||
'write1_power0': [0.057846299999999996]}
|
||||
'read0_power': [0.055371399999999994],
|
||||
'read1_power': [0.0520225],
|
||||
'slew_hl': [0.0794261],
|
||||
'slew_lh': [0.0236264],
|
||||
'write0_power': [0.06545659999999999],
|
||||
'write1_power': [0.057846299999999996]}
|
||||
elif OPTS.tech_name == "scn4m_subm":
|
||||
golden_data = {'delay_hl0': [3.452],
|
||||
'delay_lh0': [1.3792000000000002],
|
||||
golden_data = {'delay_hl': [3.452],
|
||||
'delay_lh': [1.3792000000000002],
|
||||
'leakage_power': 0.0257065,
|
||||
'min_period': 4.688,
|
||||
'read0_power0': [15.0755],
|
||||
'read1_power0': [14.4526],
|
||||
'slew_hl0': [0.6137363],
|
||||
'slew_lh0': [0.3381045],
|
||||
'write0_power0': [16.9203],
|
||||
'write1_power0': [15.367]}
|
||||
'read0_power': [15.0755],
|
||||
'read1_power': [14.4526],
|
||||
'slew_hl': [0.6137363],
|
||||
'slew_lh': [0.3381045],
|
||||
'write0_power': [16.9203],
|
||||
'write1_power': [15.367]}
|
||||
else:
|
||||
self.assertTrue(False) # other techs fail
|
||||
# Check if no too many or too few results
|
||||
|
|
|
|||
|
|
@ -48,30 +48,32 @@ class timing_sram_test(openram_test):
|
|||
import tech
|
||||
loads = [tech.spice["msflop_in_cap"]*4]
|
||||
slews = [tech.spice["rise_time"]*2]
|
||||
data = d.analyze(probe_address, probe_data, slews, loads)
|
||||
data, port_data = d.analyze(probe_address, probe_data, slews, loads)
|
||||
#Combine info about port into all data
|
||||
data.update(port_data[0])
|
||||
|
||||
if OPTS.tech_name == "freepdk45":
|
||||
golden_data = {'delay_hl0': [2.584251],
|
||||
'delay_lh0': [0.22870469999999998],
|
||||
golden_data = {'delay_hl': [2.584251],
|
||||
'delay_lh': [0.22870469999999998],
|
||||
'leakage_power': 0.0009567935,
|
||||
'min_period': 4.844,
|
||||
'read0_power0': [0.0547588],
|
||||
'read1_power0': [0.051159970000000006],
|
||||
'slew_hl0': [0.08164099999999999],
|
||||
'slew_lh0': [0.025474979999999998],
|
||||
'write0_power0': [0.06513271999999999],
|
||||
'write1_power0': [0.058057000000000004]}
|
||||
'read0_power': [0.0547588],
|
||||
'read1_power': [0.051159970000000006],
|
||||
'slew_hl': [0.08164099999999999],
|
||||
'slew_lh': [0.025474979999999998],
|
||||
'write0_power': [0.06513271999999999],
|
||||
'write1_power': [0.058057000000000004]}
|
||||
elif OPTS.tech_name == "scn4m_subm":
|
||||
golden_data = {'delay_hl0': [3.644147],
|
||||
'delay_lh0': [1.629815],
|
||||
golden_data = {'delay_hl': [3.644147],
|
||||
'delay_lh': [1.629815],
|
||||
'leakage_power': 0.0009299118999999999,
|
||||
'min_period': 4.688,
|
||||
'read0_power0': [16.28732],
|
||||
'read1_power0': [15.75155],
|
||||
'slew_hl0': [0.6722473],
|
||||
'slew_lh0': [0.3386347],
|
||||
'write0_power0': [18.545450000000002],
|
||||
'write1_power0': [16.81084]}
|
||||
'read0_power': [16.28732],
|
||||
'read1_power': [15.75155],
|
||||
'slew_hl': [0.6722473],
|
||||
'slew_lh': [0.3386347],
|
||||
'write0_power': [18.545450000000002],
|
||||
'write1_power': [16.81084]}
|
||||
else:
|
||||
self.assertTrue(False) # other techs fail
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
40
compiler/tests/22_sram_func_test.py → compiler/tests/22_hspice_sram_func_test.py
Executable file → Normal file
40
compiler/tests/22_sram_func_test.py → compiler/tests/22_hspice_sram_func_test.py
Executable file → Normal file
|
|
@ -11,49 +11,41 @@ import globals
|
|||
from globals import OPTS
|
||||
import debug
|
||||
|
||||
@unittest.skip("SKIPPING 22_sram_func_test")
|
||||
#@unittest.skip("SKIPPING 22_sram_func_test")
|
||||
class sram_func_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
OPTS.spice_name="hspice"
|
||||
OPTS.analytical_delay = False
|
||||
|
||||
|
||||
# This is a hack to reload the characterizer __init__ with the spice version
|
||||
from importlib import reload
|
||||
import characterizer
|
||||
reload(characterizer)
|
||||
from characterizer import delay
|
||||
from characterizer import functional
|
||||
if not OPTS.spice_exe:
|
||||
debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1)
|
||||
|
||||
import sram
|
||||
|
||||
debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
|
||||
s = sram.sram(word_size=1,
|
||||
num_words=16,
|
||||
num_banks=1,
|
||||
name="sram_func_test")
|
||||
from sram import sram
|
||||
from sram_config import sram_config
|
||||
c = sram_config(word_size=4,
|
||||
num_words=32,
|
||||
num_banks=1)
|
||||
c.words_per_row=2
|
||||
debug.info(1, "Functional test for 1bit, 16word SRAM, with 1 bank")
|
||||
s = sram(c, name="sram1")
|
||||
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
s.sp_write(tempspice)
|
||||
|
||||
probe_address = "1" * s.addr_size
|
||||
probe_data = s.word_size - 1
|
||||
debug.info(1, "Probe address {0} probe data {1}".format(probe_address, probe_data))
|
||||
|
||||
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||
d = delay(s,tempspice,corner)
|
||||
d.set_probe(probe_address,probe_data)
|
||||
f = functional(s.s, tempspice, corner)
|
||||
f.num_cycles = 10
|
||||
(fail, error) = f.run()
|
||||
|
||||
# This will exit if it doesn't find a feasible period
|
||||
import tech
|
||||
d.load = tech.spice["msflop_in_cap"]*4
|
||||
d.slew = tech.spice["rise_time"]*2
|
||||
feasible_period = d.find_feasible_period()
|
||||
self.assertTrue(fail,error)
|
||||
|
||||
os.remove(tempspice)
|
||||
|
||||
reload(characterizer)
|
||||
globals.end_openram()
|
||||
|
||||
# instantiate a copdsay of the class to actually run the test
|
||||
|
|
@ -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()
|
||||
|
|
@ -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()
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
word_size = 1
|
||||
num_words = 16
|
||||
num_banks = 1
|
||||
|
||||
tech_name = "freepdk45"
|
||||
process_corners = ["TT"]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
word_size = 1
|
||||
num_words = 16
|
||||
num_banks = 1
|
||||
|
||||
tech_name = "scn3me_subm"
|
||||
process_corners = ["TT"]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
word_size = 1
|
||||
num_words = 16
|
||||
num_banks = 1
|
||||
|
||||
tech_name = "scn4m_subm"
|
||||
process_corners = ["TT"]
|
||||
|
|
|
|||
|
|
@ -29,17 +29,19 @@ class openram_test(unittest.TestCase):
|
|||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
|
||||
a.sp_write(tempspice)
|
||||
a.gds_write(tempgds)
|
||||
# cannot write gds in netlist_only mode
|
||||
if not OPTS.netlist_only:
|
||||
a.gds_write(tempgds)
|
||||
|
||||
import verify
|
||||
result=verify.run_drc(a.name, tempgds)
|
||||
if result != 0:
|
||||
self.fail("DRC failed: {}".format(a.name))
|
||||
import verify
|
||||
result=verify.run_drc(a.name, tempgds)
|
||||
if result != 0:
|
||||
self.fail("DRC failed: {}".format(a.name))
|
||||
|
||||
|
||||
result=verify.run_lvs(a.name, tempgds, tempspice, final_verification)
|
||||
if result != 0:
|
||||
self.fail("LVS mismatch: {}".format(a.name))
|
||||
result=verify.run_lvs(a.name, tempgds, tempspice, final_verification)
|
||||
if result != 0:
|
||||
self.fail("LVS mismatch: {}".format(a.name))
|
||||
|
||||
if OPTS.purge_temp:
|
||||
self.cleanup()
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
@ -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]
|
||||
|
|
@ -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]
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
word_size = 32
|
||||
num_words = 1024
|
||||
num_banks = 1
|
||||
|
||||
tech_name = "freepdk45"
|
||||
process_corners = ["TT"]
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
word_size = 32
|
||||
num_words = 2048
|
||||
num_banks = 1
|
||||
|
||||
tech_name = "freepdk45"
|
||||
process_corners = ["TT"]
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
word_size = 32
|
||||
num_words = 256
|
||||
num_banks = 1
|
||||
|
||||
tech_name = "freepdk45"
|
||||
process_corners = ["TT"]
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
word_size = 32
|
||||
num_words = 512
|
||||
num_banks = 1
|
||||
|
||||
tech_name = "freepdk45"
|
||||
process_corners = ["TT"]
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
word_size = 64
|
||||
num_words = 1024
|
||||
num_banks = 1
|
||||
|
||||
tech_name = "freepdk45"
|
||||
process_corners = ["TT"]
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
word_size = 8
|
||||
num_words = 1024
|
||||
num_banks = 4
|
||||
|
||||
tech_name = "freepdk45"
|
||||
process_corners = ["TT"]
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
word_size = 8
|
||||
num_words = 256
|
||||
num_banks = 1
|
||||
|
||||
tech_name = "freepdk45"
|
||||
process_corners = ["TT"]
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
word_size = 8
|
||||
num_words = 512
|
||||
num_banks = 4
|
||||
|
||||
tech_name = "freepdk45"
|
||||
process_corners = ["TT"]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
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
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
Loading…
Reference in New Issue