Merge branch 'master' into router

This commit is contained in:
Matt Guthaus 2017-05-31 12:09:04 -07:00
commit 8cc63560f8
28 changed files with 1091 additions and 6 deletions

View File

@ -38,3 +38,17 @@ timing code too.
Convert characterizer into a Python package Convert characterizer into a Python package
cal_delay_over_path functions in hierarchy_spice
can wire as output(it only take capcitance now).
maybe consider make rc_net a class
dont use dictionary in analytical model make it like vector class
add wire delay model for bank connection
#may 15
-explain why nand_2 fail lef
-add bank seg for delay
-build better sense amp

View File

@ -228,6 +228,7 @@ class bank(design.design):
self.wordline_driver = self.mod_wordline_driver(name="wordline_driver", self.wordline_driver = self.mod_wordline_driver(name="wordline_driver",
rows=self.num_rows) rows=self.num_rows)
#self.wordline_driver.logic_effort_sizing(self.num_cols)
self.add_mod(self.wordline_driver) self.add_mod(self.wordline_driver)
self.inv = pinv(name="pinv", self.inv = pinv(name="pinv",
@ -1516,3 +1517,26 @@ class bank(design.design):
offset=[x_offset + drc["minwidth_metal1"], offset=[x_offset + drc["minwidth_metal1"],
y_offset], y_offset],
mirror="R90") mirror="R90")
def delay(self, slope):
""" return analytical delay of the bank"""
msf_addr_delay = self.msf_address.delay(slope,
self.decoder.input_load())
decoder_delay = self.decoder.delay(msf_addr_delay.slope,
self.wordline_driver.input_load())
word_driver_delay = self.wordline_driver.delay(decoder_delay.slope,
self.bitcell_array.input_load())
bitcell_array_delay = self.bitcell_array.delay(word_driver_delay.slope)
bl_t_data_out_delay = self.sens_amp_array.delay(bitcell_array_delay.slope,
self.bitcell_array.output_load())
# output load of bitcell_array is set to be only small part of bl for sense amp.
data_t_DATA_delay = self.tri_gate_array.delay(bl_t_data_out_delay.slope)
result = msf_addr_delay + decoder_delay + word_driver_delay \
+ bitcell_array_delay + bl_t_data_out_delay + data_t_DATA_delay
return result

View File

@ -21,3 +21,14 @@ class bitcell(design.design):
self.width = bitcell.chars["width"] self.width = bitcell.chars["width"]
self.height = bitcell.chars["height"] self.height = bitcell.chars["height"]
def delay(self, slope, load=0, swing = 0.5):
# delay of bit cell is not like a driver(from WL)
# so the slope used should be 0
# it should not be slope dependent?
# because the value is there
# the delay is only over half transsmission gate
from tech import spice
r = spice["min_tx_r"]*3
c_para = spice["min_tx_c_para"]#ff
result = self.cal_delay_with_rc(r = r, c = c_para+load, slope = slope, swing = swing)
return result

View File

@ -1,9 +1,11 @@
import debug import debug
import design import design
from tech import drc, spice
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
class bitcell_array(design.design): class bitcell_array(design.design):
""" """
Creates a rows x cols array of memory cells. Assumes bit-lines Creates a rows x cols array of memory cells. Assumes bit-lines
@ -140,3 +142,44 @@ class bitcell_array(design.design):
offset.y += self.cell.height offset.y += self.cell.height
# increments to the next column width # increments to the next column width
offset.x += self.cell.width offset.x += self.cell.width
def delay(self, slope, load=0):
from tech import drc
wl_wire = self.gen_wl_wire()
wl_wire.return_delay_over_wire(slope)
wl_to_cell_delay = wl_wire.return_delay_over_wire(slope)
# hypothetical delay from cell to bl end without sense amp
bl_wire = self.gen_bl_wire()
cell_load = 2 * bl_wire.return_input_cap() # we ingore the wire r
# hence just use the whole c
bl_swing = 0.1
cell_delay = self.cell.delay(wl_to_cell_delay.slope, cell_load, swing = bl_swing)
#we do not consider the delay over the wire for now
#bl_wire_delay = bl_wire.return_delay_over_wire(cell_delay.slope, swing = bl_swing)
#return [wl_to_cell_delay, cell_delay, bl_wire_delay]
#return self.return_delay(cell_delay.delay+wl_to_cell_delay.delay+bl_wire_delay.delay,
# bl_wire_delay.slope)
return self.return_delay(cell_delay.delay+wl_to_cell_delay.delay,
wl_to_cell_delay.slope)
def gen_wl_wire(self):
wl_wire = self.generate_rc_net(int(self.column_size), self.width, drc["minwidth_metal1"])
wl_wire.wire_c = 2*spice["min_tx_gate_c"] + wl_wire.wire_c # 2 access tx gate per cell
return wl_wire
def gen_bl_wire(self):
bl_pos = 0
bl_wire = self.generate_rc_net(int(self.row_size-bl_pos), self.height, drc["minwidth_metal1"])
bl_wire.wire_c =spice["min_tx_c_para"] + bl_wire.wire_c # 1 access tx d/s per cell
return bl_wire
def output_load(self, bl_pos=0):
bl_wire = self.gen_bl_wire()
return bl_wire.wire_c # sense amp only need to charge small portion of the bl
# set as one segment for now
def input_load(self):
wl_wire = self.gen_wl_wire()
return wl_wire.return_input_cap()

View File

@ -15,7 +15,7 @@ OPTS = globals.get_opts()
class lib: class lib:
""" lib file generation.""" """ lib file generation."""
def __init__(self, libname, sram, spfile): def __init__(self, libname, sram, spfile, use_model=OPTS.analytical_delay):
self.name = sram.name self.name = sram.name
self.num_words = sram.num_words self.num_words = sram.num_words
self.word_size = sram.word_size self.word_size = sram.word_size
@ -61,7 +61,11 @@ class lib:
probe_address = "1" * self.addr_size probe_address = "1" * self.addr_size
probe_data = self.word_size - 1 probe_data = self.word_size - 1
data = self.d.analyze(probe_address, probe_data) if use_model:
data = sram.analytical_model(slope=0.001)
else:
data = self.d.analyze(probe_address, probe_data)
for i in data.keys(): for i in data.keys():
if i == "read_power" or i == "write_power": if i == "read_power" or i == "write_power":
continue continue

View File

@ -51,7 +51,9 @@ def parse_args():
help="Spice simulator name"), help="Spice simulator name"),
# TODO: Why is this -f? # TODO: Why is this -f?
optparse.make_option("-f", "--trim_noncritical", dest="trim_noncritical", optparse.make_option("-f", "--trim_noncritical", dest="trim_noncritical",
help="Trim noncritical memory cells during simulation") help="Trim noncritical memory cells during simulation"),
optparse.make_option("-a", "--analyticaldelay", dest="analytical_delay",
help="Use analytical model to calculate delay or not")
} }
# -h --help is implicit. # -h --help is implicit.

View File

@ -601,3 +601,30 @@ class hierarchical_decoder(design.design):
offset=[xoffset + self.gap_between_rails, offset=[xoffset + self.gap_between_rails,
yoffset - self.via_shift], yoffset - self.via_shift],
rotate=90) rotate=90)
def delay(self, slope, load = 0.0):
# A -> out
if self.determine_predecodes(self.num_inputs)[1]==0:
pre = self.pre2_4
nand = self.nand2
else:
pre = self.pre3_8
nand = self.nand3
a_t_out_delay = pre.delay(slope=slope,load = nand.input_load())
# out -> z
out_t_z_delay = nand.delay(slope= a_t_out_delay.slope,
load = self.inv.input_load())
result = a_t_out_delay + out_t_z_delay
# Z -> decode_out
z_t_decodeout_delay = self.inv.delay(slope = out_t_z_delay.slope , load = load)
result = result + z_t_decodeout_delay
return result
def input_load(self):
if self.determine_predecodes(self.num_inputs)[1]==0:
pre = self.pre2_4
else:
pre = self.pre3_8
return pre.input_load()

View File

@ -108,3 +108,21 @@ class hierarchical_predecode2x4(hierarchical_predecode):
def get_via_y(self): def get_via_y(self):
return self.rail_height return self.rail_height
def delay(self, slope, load = 0.0 ):
#print "pre2x4 consist:"
# A -> B
a_t_b_delay = self.inv.delay(slope=slope,load = self.nand.input_load())
# out -> z
b_t_z_delay = self.nand.delay(slope=a_t_b_delay.slope,load = self.inv.input_load())
result = a_t_b_delay + b_t_z_delay
# Z -> out
a_t_out_delay = self.inv.delay(slope=b_t_z_delay.slope,load = load)
result = result + a_t_out_delay
#print "end of pre2x4"
return result
def input_load(self):
return self.inv.input_load()

View File

@ -90,3 +90,17 @@ class hierarchical_predecode3x8(hierarchical_predecode):
yoffset = (self.number_of_outputs * self.inv.height yoffset = (self.number_of_outputs * self.inv.height
- 0.5 * drc["minwidth_metal1"]) - 0.5 * drc["minwidth_metal1"])
return yoffset return yoffset
def delay(self, slope, load = 0.0 ):
# A -> z
b_t_z_delay = self.nand.delay(slope=slope,
load = self.input_load())
# Z -> out
a_t_out_delay = self.inv.delay(slope=b_t_z_delay.slope,
load = load)
result = b_t_z_delay + a_t_out_delay
return result
def input_load(self):
return self.nand.input_load()

View File

@ -1,6 +1,7 @@
import debug import debug
import re import re
import os import os
import math
class spice: class spice:
@ -146,3 +147,108 @@ class spice:
self.sp_write_file(spfile, usedMODS) self.sp_write_file(spfile, usedMODS)
del usedMODS del usedMODS
spfile.close() spfile.close()
def delay(self, slope, load=0.0):
"""Inform users undefined delay module while building new modules"""
debug.warning("Design Class {0} delay function needs to be defined"
.format(self.__class__.__name__))
debug.warning("Class {0} name {1}"
.format(self.__class__.__name__,
self.name))
# return 0 to keep code running while building
return delay_data(0.0, 0.0)
def cal_delay_with_rc(self, r, c ,slope, swing = 0.5):
"""
Calculate the delay of a mosfet by
modeling it as a resistance driving a capacitance
"""
swing_factor = abs(math.log(1-swing)) # time constant based on swing
delay = swing_factor * r * c #c is in ff and delay is in fs
delay = delay * 0.001 #make the unit to ps
# Output slope should be linear to input slope which is described
# as 0.005* slope.
# The slope will be also influenced by the delay.
# If no input slope(or too small to make impact)
# The mimum slope should be the time to charge RC.
# Delay * 2 is from 0 to 100% swing. 0.6*2*delay is from 20%-80%.
slope = delay * 0.6 * 2 + 0.005 * slope
return delay_data(delay = delay, slope = slope)
def return_delay(self, delay, slope):
return delay_data(delay, slope)
def generate_rc_net(self,lump_num, wire_length, wire_width):
return wire_spice_model(lump_num, wire_length, wire_width)
class delay_data:
"""
This is the delay class to represent the delay information
Time is 50% of the signal to 50% of reference signal delay.
Slope is the 20% of the signal to 80% of signal
"""
def __init__(self, delay=0.0, slope=0.0):
""" init function support two init method"""
# will take single input as a coordinate
self.delay = delay
self.slope = slope
def __str__(self):
""" override print function output """
return "Delay Data: Delay "+str(self.delay)+", Slope "+str(self.slope)+""
def __add__(self, other):
"""
Override - function (left), for delay_data: a+b != b+a
"""
assert isinstance(other,delay_data)
return delay_data(other.delay + self.delay,
other.slope)
def __radd__(self, other):
"""
Override - function (right), for delay_data: a+b != b+a
"""
assert isinstance(other,delay_data)
return delay_data(other.delay + self.delay,
self.slope)
class wire_spice_model:
"""
This is the spice class to represent a wire
"""
def __init__(self, lump_num, wire_length, wire_width):
self.lump_num = lump_num # the number of segment the wire delay has
self.wire_c = self.cal_wire_c(wire_length, wire_width) # c in each segment
self.wire_r = self.cal_wire_r(wire_length, wire_width) # r in each segment
def cal_wire_c(self, wire_length, wire_width):
from tech import spice
total_c = spice["wire_unit_c"] * wire_length * wire_width
wire_c = total_c / self.lump_num
return wire_c
def cal_wire_r(self, wire_length, wire_width):
from tech import spice
total_r = spice["wire_unit_r"] * wire_length / wire_width
wire_r = total_r / self.lump_num
return wire_r
def return_input_cap(self):
return 0.5 * self.wire_c * self.lump_num
def return_delay_over_wire(self, slope, swing = 0.5):
# delay will be sum of arithmetic sequence start from
# rc to self.lump_num*rc with step of rc
swing_factor = abs(math.log(1-swing)) # time constant based on swing
sum_factor = (1+self.lump_num) * self.lump_num * 0.5 # sum of the arithmetic sequence
delay = sum_factor * swing_factor * self.wire_r * self.wire_c
slope = delay * 2 + slope
result= delay_data(delay, slope)
return result

View File

@ -23,3 +23,20 @@ class ms_flop(design.design):
self.din_offset = ms_flop.chars["din"] self.din_offset = ms_flop.chars["din"]
self.dout_offset = ms_flop.chars["dout"] self.dout_offset = ms_flop.chars["dout"]
self.dout_bar_offset = ms_flop.chars["dout_bar"] self.dout_bar_offset = ms_flop.chars["dout_bar"]
def delay(self, slope, load = 0.0):
#import pinv
# use inv to mimic the delay
# din -> mout
#ref = pinv.pinv("reference_inv")
#mid_load = ref.input_load()
#din_t_mout_delay = ref.delay(slope = slope, load = mid_load)
# mout -> out
#mout_t_out_delay = ref.delay(slope = slope, load = load)
#result = din_t_mout_delay + mout_t_out_delay
# dont k how to calculate this now, use constant in tech file
from tech import spice
result = self.return_delay(spice["msflop_delay"], spice["msflop_slope"])
return result

View File

@ -163,3 +163,8 @@ class ms_flop_array(design.design):
layer="text", layer="text",
offset=[self.width / 2.0, offset=[self.width / 2.0,
self.height / 2.0]) self.height / 2.0])
def delay(self, slope, load=0.0):
result = self.ms_flop.delay(slope = slope,
load = load)
return result

View File

@ -1,7 +1,7 @@
import contact import contact
import design import design
import debug import debug
from tech import drc from tech import drc, parameter, spice
from ptx import ptx from ptx import ptx
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
@ -438,3 +438,12 @@ class nand_2(design.design):
self.Z_position = self.Z_position = self.output_position self.Z_position = self.Z_position = self.output_position
self.vdd_position = self.vdd_position self.vdd_position = self.vdd_position
self.gnd_position = self.gnd_position self.gnd_position = self.gnd_position
def input_load(self):
from tech import spice
return ((self.nmos_size+self.pmos_size)/parameter["min_tx_size"])*spice["min_tx_gate_c"]
def delay(self, slope, load=0.0):
r = spice["min_tx_r"]/(self.nmos_size/parameter["min_tx_size"])
c_para = spice["min_tx_c_para"]*(self.nmos_size/parameter["min_tx_size"])#ff
return self.cal_delay_with_rc(r = r, c = c_para+load, slope =slope)

View File

@ -4,6 +4,7 @@ import debug
from tech import drc from tech import drc
from ptx import ptx from ptx import ptx
from vector import vector from vector import vector
from tech import parameter, spice
from globals import OPTS from globals import OPTS
class nand_3(design.design): class nand_3(design.design):
@ -525,3 +526,11 @@ class nand_3(design.design):
self.Z_position = self.Z_position self.Z_position = self.Z_position
self.vdd_position = self.vdd_position self.vdd_position = self.vdd_position
self.gnd_position = self.gnd_position self.gnd_position = self.gnd_position
def input_load(self):
return ((self.nmos_size+self.pmos_size)/parameter["min_tx_size"])*spice["min_tx_gate_c"]
def delay(self, slope, load=0.0):
r = spice["min_tx_r"]/(self.nmos_size/parameter["min_tx_size"])
c_para = spice["min_tx_c_para"]*(self.nmos_size/parameter["min_tx_size"])#ff
return self.cal_delay_with_rc(r = r, c = c_para+load, slope =slope)

View File

@ -36,3 +36,4 @@ class options(optparse.Values):
out_path = "" out_path = ""
# Define the output file base name # Define the output file base name
out_name = "" out_name = ""
analytical_delay = True

View File

@ -1,7 +1,7 @@
import contact import contact
import design import design
import debug import debug
from tech import drc, parameter from tech import drc, parameter, spice
from ptx import ptx from ptx import ptx
from vector import vector from vector import vector
from math import ceil from math import ceil
@ -401,3 +401,12 @@ class pinv(design.design):
def setup_layout_offsets(self): def setup_layout_offsets(self):
self.A_position = self.input_position self.A_position = self.input_position
self.Z_position = self.output_position self.Z_position = self.output_position
def input_load(self):
return ((self.nmos_size+self.pmos_size)/parameter["min_tx_size"])*spice["min_tx_gate_c"]
def delay(self, slope, load=0.0):
from tech import spice
r = spice["min_tx_r"]/(self.nmos_size/parameter["min_tx_size"])
c_para = spice["min_tx_c_para"]*(self.nmos_size/parameter["min_tx_size"])#ff
return self.cal_delay_with_rc(r = r, c = c_para+load, slope =slope)

View File

@ -21,3 +21,10 @@ class sense_amp(design.design):
self.width = sense_amp.chars["width"] self.width = sense_amp.chars["width"]
self.height = sense_amp.chars["height"] self.height = sense_amp.chars["height"]
def delay(self, slope, load=0.0):
from tech import spice
r = spice["min_tx_r"]/(10)
c_para = spice["min_tx_c_para"]#ff
result = self.cal_delay_with_rc(r = r, c = c_para+load, slope =slope)
return self.return_delay(result.delay , result.slope)

View File

@ -131,3 +131,7 @@ class sense_amp_array(design.design):
width=self.width, width=self.width,
height=drc["minwidth_metal1"]) height=drc["minwidth_metal1"])
self.SCLK_positions.append(sclk_offset) self.SCLK_positions.append(sclk_offset)
def delay(self, slope, load =0.0):
result = self.amp.delay(slope=slope, load =load)
return result

View File

@ -1170,3 +1170,13 @@ class sram(design.design):
self.sp_write_file(sp, usedMODS) self.sp_write_file(sp, usedMODS)
del usedMODS del usedMODS
sp.close() sp.close()
def analytical_model(self,slope):
#control_delay = self.control.delay(slope=slope)
bank_delay = self.bank.delay(slope = slope)
data ={'delay1': bank_delay.delay, 'delay0': bank_delay.delay,
'min_period1': 0,
'min_period0': 0,
'read_power': 0,
'write_power': 0}
return data

View File

@ -0,0 +1,70 @@
#!/usr/bin/env python2.7
"""
Check the .lib file for an SRAM
"""
import unittest
from testutils import header,isapproxdiff
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
import debug
import calibre
OPTS = globals.get_opts()
class lib_test(unittest.TestCase):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
OPTS.check_lvsdrc = False
import sram
import lib
debug.info(1, "Testing timing for sample 2 bit, 16 words SRAM with 1 bank")
total_size = 1024
for word_size in [1,2,4,8,16,32,64]:
num_words = total_size/word_size# OPTS.config.num_words
s = sram.sram(word_size=word_size,
num_words=num_words,
num_banks=OPTS.config.num_banks,
name="sram_2_16_1_{0}".format(OPTS.tech_name))
delay = s.analytical_model(0.1)
OPTS.check_lvsdrc = True
tempspice = OPTS.openram_temp + "temp.sp"
s.sp_write(tempspice)
filename = s.name + ".lib"
libname = OPTS.openram_temp + filename
use_model = True
lib.lib(libname,s,tempspice,use_model)
# let's diff the result with a golden model
golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),filename)
# Randomly decided 10% difference between spice simulators is ok.
if use_model != True:
self.assertEqual(isapproxdiff(libname,golden,0.10),True)
os.system("rm {0}".format(libname))
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()

View File

@ -34,7 +34,10 @@ class lib_test(unittest.TestCase):
tempspice = OPTS.openram_temp + "temp.sp" tempspice = OPTS.openram_temp + "temp.sp"
s.sp_write(tempspice) s.sp_write(tempspice)
filename = s.name + ".lib" if OPTS.analytical_delay == True:
filename = s.name + "_analytical.lib"
else:
filename = s.name + ".lib"
libname = OPTS.openram_temp + filename libname = OPTS.openram_temp + filename
lib.lib(libname,s,tempspice) lib.lib(libname,s,tempspice)

View File

@ -0,0 +1,315 @@
library (sram_2_16_1_freepdk45_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(TT){
voltage : 1.0 ;
temperature : 25.000 ;
}
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 ;
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_UP_FOR_CLOCK){
variable_1 : input_net_transition;
variable_2 : total_output_net_capacitance;
index_1 ("0.5");
index_2 ("0.5");
}
lu_table_template(CELL_DN_FOR_CLOCK){
variable_1 : input_net_transition;
variable_2 : total_output_net_capacitance;
index_1 ("0.5");
index_2 ("0.5");
}
lu_table_template(CONSTRAINT_HIGH_POS){
variable_1 : related_pin_transition;
variable_2 : constrained_pin_transition;
index_1 ("0.5");
index_2 ("0.5");
}
lu_table_template(CONSTRAINT_LOW_POS){
variable_1 : related_pin_transition;
variable_2 : constrained_pin_transition;
index_1 ("0.5");
index_2 ("0.5");
}
lu_table_template(CLK_TRAN) {
variable_1 : constrained_pin_transition;
index_1 ("0.5");
}
lu_table_template(TRAN) {
variable_1 : total_output_net_capacitance;
index_1 ("0.5");
}
power_lut_template(INPUT_BY_TRANS_FOR_CLOCK){
variable_1 : input_transition_time;
index_1 ("0.5");
}
power_lut_template(INPUT_BY_TRANS_FOR_SIGNAL){
variable_1 : input_transition_time;
index_1 ("0.5");
}
default_operating_conditions : TT;
type (DATA){
base_type : array;
data_type : bit;
bit_width : 2;
bit_from : 0;
bit_to : 1;
}
type (ADDR){
base_type : array;
data_type : bit;
bit_width : 4;
bit_from : 0;
bit_to : 3;
}
cell (sram_2_16_1_freepdk45){
memory(){
type : ram;
address_width : 4;
word_width : 2;
}
interface_timing : true;
dont_use : true;
map_only : true;
dont_touch : true;
area : 799.659625;
bus(DATA){
bus_type : DATA;
direction : inout;
max_capacitance : 0.62166;
pin(DATA[1:0]){
}
three_state : "!OEb & !clk";
memory_write(){
address : ADDR;
clocked_on : clk;
}
internal_power(){
when : "OEb & !clk";
rise_power(INPUT_BY_TRANS_FOR_SIGNAL){
values("0.0");
}
fall_power(INPUT_BY_TRANS_FOR_SIGNAL){
values("0.0");
}
}
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.015");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("0.009");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("-0.005");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.011");
}
}
memory_read(){
address : ADDR;
}
internal_power(){
when : "!OEb & !clk";
rise_power(INPUT_BY_TRANS_FOR_SIGNAL){
values("0.0");
}
fall_power(INPUT_BY_TRANS_FOR_SIGNAL){
values("0.0");
}
}
timing(){
timing_sense : non_unate;
related_pin : "clk";
timing_type : rising_edge;
cell_rise(CELL_UP_FOR_CLOCK) {
values("120.044");
}
cell_fall(CELL_DN_FOR_CLOCK) {
values("120.044");
}
rise_transition(TRAN) {
values("120.044");
}
fall_transition(TRAN) {
values("120.044");
}
}
}
bus(ADDR){
bus_type : ADDR;
direction : input;
capacitance : 0.2091;
max_transition : 0.5;
fanout_load : 1.000000;
pin(ADDR[3:0]){
}
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.015");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("0.009");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("-0.005");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.011");
}
}
}
pin(CSb){
direction : input;
capacitance : 0.2091;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.015");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("0.009");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("-0.005");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.011");
}
}
}
pin(OEb){
direction : input;
capacitance : 0.2091;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.015");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("0.009");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("-0.005");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.011");
}
}
}
pin(WEb){
direction : input;
capacitance : 0.2091;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.015");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("0.009");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("-0.005");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.011");
}
}
}
pin(clk){
clock : true;
direction : input;
capacitance : 0.2091;
timing(){
timing_type :"min_pulse_width";
related_pin : clk;
rise_constraint(CLK_TRAN) {
values("0.0");
}
fall_constraint(CLK_TRAN) {
values("0.0");
}
}
timing(){
timing_type :"minimum_period";
related_pin : clk;
rise_constraint(CLK_TRAN) {
values("0.0");
}
fall_constraint(CLK_TRAN) {
values("0.0");
}
}
}
}
}

View File

@ -0,0 +1,315 @@
library (sram_2_16_1_scn3me_subm_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(TT){
voltage : 5.0 ;
temperature : 25.000 ;
}
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 ;
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_UP_FOR_CLOCK){
variable_1 : input_net_transition;
variable_2 : total_output_net_capacitance;
index_1 ("0.5");
index_2 ("0.5");
}
lu_table_template(CELL_DN_FOR_CLOCK){
variable_1 : input_net_transition;
variable_2 : total_output_net_capacitance;
index_1 ("0.5");
index_2 ("0.5");
}
lu_table_template(CONSTRAINT_HIGH_POS){
variable_1 : related_pin_transition;
variable_2 : constrained_pin_transition;
index_1 ("0.5");
index_2 ("0.5");
}
lu_table_template(CONSTRAINT_LOW_POS){
variable_1 : related_pin_transition;
variable_2 : constrained_pin_transition;
index_1 ("0.5");
index_2 ("0.5");
}
lu_table_template(CLK_TRAN) {
variable_1 : constrained_pin_transition;
index_1 ("0.5");
}
lu_table_template(TRAN) {
variable_1 : total_output_net_capacitance;
index_1 ("0.5");
}
power_lut_template(INPUT_BY_TRANS_FOR_CLOCK){
variable_1 : input_transition_time;
index_1 ("0.5");
}
power_lut_template(INPUT_BY_TRANS_FOR_SIGNAL){
variable_1 : input_transition_time;
index_1 ("0.5");
}
default_operating_conditions : TT;
type (DATA){
base_type : array;
data_type : bit;
bit_width : 2;
bit_from : 0;
bit_to : 1;
}
type (ADDR){
base_type : array;
data_type : bit;
bit_width : 4;
bit_from : 0;
bit_to : 3;
}
cell (sram_2_16_1_scn3me_subm){
memory(){
type : ram;
address_width : 4;
word_width : 2;
}
interface_timing : true;
dont_use : true;
map_only : true;
dont_touch : true;
area : 102102.39;
bus(DATA){
bus_type : DATA;
direction : inout;
max_capacitance : 11.3222;
pin(DATA[1:0]){
}
three_state : "!OEb & !clk";
memory_write(){
address : ADDR;
clocked_on : clk;
}
internal_power(){
when : "OEb & !clk";
rise_power(INPUT_BY_TRANS_FOR_SIGNAL){
values("0.0");
}
fall_power(INPUT_BY_TRANS_FOR_SIGNAL){
values("0.0");
}
}
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.093");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.024");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.046");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.083");
}
}
memory_read(){
address : ADDR;
}
internal_power(){
when : "!OEb & !clk";
rise_power(INPUT_BY_TRANS_FOR_SIGNAL){
values("0.0");
}
fall_power(INPUT_BY_TRANS_FOR_SIGNAL){
values("0.0");
}
}
timing(){
timing_sense : non_unate;
related_pin : "clk";
timing_type : rising_edge;
cell_rise(CELL_UP_FOR_CLOCK) {
values("553.907");
}
cell_fall(CELL_DN_FOR_CLOCK) {
values("553.907");
}
rise_transition(TRAN) {
values("553.907");
}
fall_transition(TRAN) {
values("553.907");
}
}
}
bus(ADDR){
bus_type : ADDR;
direction : input;
capacitance : 9.8242;
max_transition : 0.5;
fanout_load : 1.000000;
pin(ADDR[3:0]){
}
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.093");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.024");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.046");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.083");
}
}
}
pin(CSb){
direction : input;
capacitance : 9.8242;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.093");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.024");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.046");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.083");
}
}
}
pin(OEb){
direction : input;
capacitance : 9.8242;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.093");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.024");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.046");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.083");
}
}
}
pin(WEb){
direction : input;
capacitance : 9.8242;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.093");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.024");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.046");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.083");
}
}
}
pin(clk){
clock : true;
direction : input;
capacitance : 9.8242;
timing(){
timing_type :"min_pulse_width";
related_pin : clk;
rise_constraint(CLK_TRAN) {
values("0.0");
}
fall_constraint(CLK_TRAN) {
values("0.0");
}
}
timing(){
timing_type :"minimum_period";
related_pin : clk;
rise_constraint(CLK_TRAN) {
values("0.0");
}
fall_constraint(CLK_TRAN) {
values("0.0");
}
}
}
}
}

View File

@ -20,3 +20,14 @@ class tri_gate(design.design):
self.width = tri_gate.chars["width"] self.width = tri_gate.chars["width"]
self.height = tri_gate.chars["height"] self.height = tri_gate.chars["height"]
def delay(self, slope, load=0.0):
from tech import spice
r = spice["min_tx_r"]
c_para = spice["min_tx_c_para"]#ff
return self.cal_delay_with_rc(r = r, c = c_para+load, slope =slope)
def input_load(self):
return 9*spice["min_tx_gate_c"]

View File

@ -134,3 +134,8 @@ class tri_gate_array(design.design):
layer="text", layer="text",
offset=[self.width / 2.0, offset=[self.width / 2.0,
self.height / 2.0]) self.height / 2.0])
def delay(self, slope, load=0.0):
result = self.tri.delay(slope = slope,
load = load)
return result

View File

@ -211,3 +211,16 @@ class wordline_driver(design.design):
self.WL_positions.append(wl_offset) self.WL_positions.append(wl_offset)
self.vdd_positions.append(vdd_offset) self.vdd_positions.append(vdd_offset)
self.gnd_positions.append(gnd_offset) self.gnd_positions.append(gnd_offset)
def delay(self, slope, load=0):
# decode_out -> net
decode_t_net = self.NAND2.delay(slope = slope, load = self.inv.input_load())
# net -> wl
net_t_wl = self.inv.delay(slope = decode_t_net.slope, load = load)
result = decode_t_net + net_t_wl
return result
def input_load(self):
return self.NAND2.input_load()

View File

@ -291,3 +291,11 @@ spice["clk"] = "clk"
# estimated feasible period in ns # estimated feasible period in ns
spice["feasible_period"] = 5 spice["feasible_period"] = 5
# analytical delay parameter
spice["wire_unit_r"] = 0.075 #ohm
spice["wire_unit_c"] = 0.64 #ff/um^2
spice["min_tx_r"] = 9250.0
spice["min_tx_c_para"] = 0.7 #ff
spice["min_tx_gate_c"] = 0.2
spice["msflop_delay"] = 20.5171565446#ps
spice["msflop_slope"] = 13.0801872972#ps

View File

@ -208,3 +208,14 @@ spice["clk"] = "clk"
# estimated feasible period in ns # estimated feasible period in ns
spice["feasible_period"] = 5 spice["feasible_period"] = 5
# analytical delay parameter
# these numbers are copied from freepdk
# need to measure them in scn cmos
spice["wire_unit_r"] = 0.075 #ohm
spice["wire_unit_c"] = 0.64 #ff/um^2
spice["min_tx_r"] = 9250.0
spice["min_tx_c_para"] = 0.7 #ff
spice["min_tx_gate_c"] = 0.1
spice["msflop_delay"] = 20.5171565446#ps
spice["msflop_slope"] = 13.0801872972#ps