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
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",
rows=self.num_rows)
#self.wordline_driver.logic_effort_sizing(self.num_cols)
self.add_mod(self.wordline_driver)
self.inv = pinv(name="pinv",
@ -1516,3 +1517,26 @@ class bank(design.design):
offset=[x_offset + drc["minwidth_metal1"],
y_offset],
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.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 design
from tech import drc, spice
from vector import vector
from globals import OPTS
class bitcell_array(design.design):
"""
Creates a rows x cols array of memory cells. Assumes bit-lines
@ -140,3 +142,44 @@ class bitcell_array(design.design):
offset.y += self.cell.height
# increments to the next column 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:
""" 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.num_words = sram.num_words
self.word_size = sram.word_size
@ -61,7 +61,11 @@ class lib:
probe_address = "1" * self.addr_size
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():
if i == "read_power" or i == "write_power":
continue

View File

@ -51,7 +51,9 @@ def parse_args():
help="Spice simulator name"),
# TODO: Why is this -f?
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.

View File

@ -601,3 +601,30 @@ class hierarchical_decoder(design.design):
offset=[xoffset + self.gap_between_rails,
yoffset - self.via_shift],
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):
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
- 0.5 * drc["minwidth_metal1"])
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 re
import os
import math
class spice:
@ -146,3 +147,108 @@ class spice:
self.sp_write_file(spfile, usedMODS)
del usedMODS
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.dout_offset = ms_flop.chars["dout"]
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",
offset=[self.width / 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 design
import debug
from tech import drc
from tech import drc, parameter, spice
from ptx import ptx
from vector import vector
from globals import OPTS
@ -438,3 +438,12 @@ class nand_2(design.design):
self.Z_position = self.Z_position = self.output_position
self.vdd_position = self.vdd_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 ptx import ptx
from vector import vector
from tech import parameter, spice
from globals import OPTS
class nand_3(design.design):
@ -525,3 +526,11 @@ class nand_3(design.design):
self.Z_position = self.Z_position
self.vdd_position = self.vdd_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 = ""
# Define the output file base name
out_name = ""
analytical_delay = True

View File

@ -1,7 +1,7 @@
import contact
import design
import debug
from tech import drc, parameter
from tech import drc, parameter, spice
from ptx import ptx
from vector import vector
from math import ceil
@ -401,3 +401,12 @@ class pinv(design.design):
def setup_layout_offsets(self):
self.A_position = self.input_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.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,
height=drc["minwidth_metal1"])
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)
del usedMODS
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"
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
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.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",
offset=[self.width / 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.vdd_positions.append(vdd_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
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
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