From 34e180b901becc520811e3690a676e90aee52a0e Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Tue, 30 May 2017 12:50:07 -0700 Subject: [PATCH] Analytical delay model from Bin Wu. Unit test not passing. --- compiler/TODO | 14 +++ compiler/bank.py | 24 +++++ compiler/bitcell.py | 11 +++ compiler/bitcell_array.py | 43 +++++++++ compiler/characterizer/lib.py | 8 +- compiler/globals.py | 4 +- compiler/hierarchical_decoder.py | 27 ++++++ compiler/hierarchical_predecode2x4.py | 18 ++++ compiler/hierarchical_predecode3x8.py | 14 +++ compiler/hierarchy_spice.py | 106 +++++++++++++++++++++++ compiler/ms_flop.py | 17 ++++ compiler/ms_flop_array.py | 5 ++ compiler/nand_2.py | 11 ++- compiler/nand_3.py | 9 ++ compiler/options.py | 1 + compiler/pinv.py | 11 ++- compiler/sense_amp.py | 7 ++ compiler/sense_amp_array.py | 4 + compiler/sram.py | 10 +++ compiler/tests/23_lib_sram_model_test.py | 70 +++++++++++++++ compiler/tri_gate.py | 11 +++ compiler/tri_gate_array.py | 5 ++ compiler/wordline_driver.py | 13 +++ technology/freepdk45/tech/tech.py | 8 ++ technology/scn3me_subm/tech/tech.py | 11 +++ 25 files changed, 457 insertions(+), 5 deletions(-) create mode 100644 compiler/tests/23_lib_sram_model_test.py diff --git a/compiler/TODO b/compiler/TODO index 5526f91a..3d7d7255 100644 --- a/compiler/TODO +++ b/compiler/TODO @@ -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 + + diff --git a/compiler/bank.py b/compiler/bank.py index 8c60c9d9..d464587c 100644 --- a/compiler/bank.py +++ b/compiler/bank.py @@ -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 diff --git a/compiler/bitcell.py b/compiler/bitcell.py index 56509875..81127a4f 100644 --- a/compiler/bitcell.py +++ b/compiler/bitcell.py @@ -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 diff --git a/compiler/bitcell_array.py b/compiler/bitcell_array.py index c6a2265a..9dec605f 100644 --- a/compiler/bitcell_array.py +++ b/compiler/bitcell_array.py @@ -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() diff --git a/compiler/characterizer/lib.py b/compiler/characterizer/lib.py index d6c5e21d..25d46ac0 100644 --- a/compiler/characterizer/lib.py +++ b/compiler/characterizer/lib.py @@ -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 diff --git a/compiler/globals.py b/compiler/globals.py index 79b04835..489783dd 100644 --- a/compiler/globals.py +++ b/compiler/globals.py @@ -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. diff --git a/compiler/hierarchical_decoder.py b/compiler/hierarchical_decoder.py index ace1792f..72199b9f 100644 --- a/compiler/hierarchical_decoder.py +++ b/compiler/hierarchical_decoder.py @@ -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() diff --git a/compiler/hierarchical_predecode2x4.py b/compiler/hierarchical_predecode2x4.py index 411a5c95..a83ed33c 100644 --- a/compiler/hierarchical_predecode2x4.py +++ b/compiler/hierarchical_predecode2x4.py @@ -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() diff --git a/compiler/hierarchical_predecode3x8.py b/compiler/hierarchical_predecode3x8.py index 622a3268..7b6e6f23 100644 --- a/compiler/hierarchical_predecode3x8.py +++ b/compiler/hierarchical_predecode3x8.py @@ -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() diff --git a/compiler/hierarchy_spice.py b/compiler/hierarchy_spice.py index 78fc56e0..f818626c 100644 --- a/compiler/hierarchy_spice.py +++ b/compiler/hierarchy_spice.py @@ -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 + diff --git a/compiler/ms_flop.py b/compiler/ms_flop.py index 05763bbe..d1342817 100644 --- a/compiler/ms_flop.py +++ b/compiler/ms_flop.py @@ -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 diff --git a/compiler/ms_flop_array.py b/compiler/ms_flop_array.py index 904eebd1..95418227 100644 --- a/compiler/ms_flop_array.py +++ b/compiler/ms_flop_array.py @@ -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 diff --git a/compiler/nand_2.py b/compiler/nand_2.py index 4db2324e..3f593313 100644 --- a/compiler/nand_2.py +++ b/compiler/nand_2.py @@ -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) diff --git a/compiler/nand_3.py b/compiler/nand_3.py index 2e16d8da..265ab34c 100644 --- a/compiler/nand_3.py +++ b/compiler/nand_3.py @@ -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) diff --git a/compiler/options.py b/compiler/options.py index ffe7f01d..1155ffbb 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -36,3 +36,4 @@ class options(optparse.Values): out_path = "" # Define the output file base name out_name = "" + analytical_delay = True diff --git a/compiler/pinv.py b/compiler/pinv.py index 03575f4b..50356d7a 100644 --- a/compiler/pinv.py +++ b/compiler/pinv.py @@ -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) diff --git a/compiler/sense_amp.py b/compiler/sense_amp.py index 1f440e4f..4c2be560 100644 --- a/compiler/sense_amp.py +++ b/compiler/sense_amp.py @@ -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) + diff --git a/compiler/sense_amp_array.py b/compiler/sense_amp_array.py index c843cca1..6f5f4de2 100644 --- a/compiler/sense_amp_array.py +++ b/compiler/sense_amp_array.py @@ -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 diff --git a/compiler/sram.py b/compiler/sram.py index 420ac873..22242fa2 100644 --- a/compiler/sram.py +++ b/compiler/sram.py @@ -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 diff --git a/compiler/tests/23_lib_sram_model_test.py b/compiler/tests/23_lib_sram_model_test.py new file mode 100644 index 00000000..ad4f3896 --- /dev/null +++ b/compiler/tests/23_lib_sram_model_test.py @@ -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() + + + + + + diff --git a/compiler/tri_gate.py b/compiler/tri_gate.py index cefc51fe..2a98c2fd 100644 --- a/compiler/tri_gate.py +++ b/compiler/tri_gate.py @@ -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"] + diff --git a/compiler/tri_gate_array.py b/compiler/tri_gate_array.py index ffc1b057..e6fc41e3 100644 --- a/compiler/tri_gate_array.py +++ b/compiler/tri_gate_array.py @@ -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 diff --git a/compiler/wordline_driver.py b/compiler/wordline_driver.py index 5a7de1b7..376afd08 100644 --- a/compiler/wordline_driver.py +++ b/compiler/wordline_driver.py @@ -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() diff --git a/technology/freepdk45/tech/tech.py b/technology/freepdk45/tech/tech.py index e19c8fa7..ef7f952c 100644 --- a/technology/freepdk45/tech/tech.py +++ b/technology/freepdk45/tech/tech.py @@ -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 diff --git a/technology/scn3me_subm/tech/tech.py b/technology/scn3me_subm/tech/tech.py index e473c882..72eda0e8 100755 --- a/technology/scn3me_subm/tech/tech.py +++ b/technology/scn3me_subm/tech/tech.py @@ -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