From b8061d3a4e03684ff22d9b5fe93d87cab2a774e3 Mon Sep 17 00:00:00 2001 From: Hunter Nichols Date: Thu, 8 Nov 2018 00:10:51 -0800 Subject: [PATCH] Added initial code for determining the logical effort delay of the wordline. --- compiler/bitcells/bitcell.py | 7 +++++- compiler/characterizer/logical_effort.py | 16 ++++++++++++ compiler/modules/bank.py | 14 +++++++++++ compiler/modules/bitcell_array.py | 7 ++++++ compiler/modules/control_logic.py | 10 ++++++++ compiler/modules/dff.py | 12 ++++++--- compiler/modules/dff_array.py | 6 +++++ compiler/modules/dff_inv.py | 3 +++ compiler/modules/dff_inv_array.py | 6 +++++ compiler/modules/wordline_driver.py | 23 +++++++++++++++++ compiler/pgates/pinv.py | 13 +++++++++- compiler/pgates/pinvbuf.py | 11 ++++++++ compiler/pgates/pnand2.py | 11 ++++++++ compiler/sram_base.py | 32 ++++++++++++++++++++++++ technology/freepdk45/tech/tech.py | 4 +++ technology/scn4m_subm/tech/tech.py | 5 ++++ 16 files changed, 174 insertions(+), 6 deletions(-) create mode 100644 compiler/characterizer/logical_effort.py diff --git a/compiler/bitcells/bitcell.py b/compiler/bitcells/bitcell.py index 5df86c87..ef0e8e9d 100644 --- a/compiler/bitcells/bitcell.py +++ b/compiler/bitcells/bitcell.py @@ -1,7 +1,7 @@ import design import debug import utils -from tech import GDS,layer +from tech import GDS,layer, parameter class bitcell(design.design): """ @@ -93,3 +93,8 @@ class bitcell(design.design): total_power = self.return_power(dynamic, leakage) return total_power + def get_wl_cin(self): + """Return the total capacitance (in relative units) that the clock is loaded by in the dff""" + #This is a handmade cell so the value must be entered in the tech.py file or estimated. + #Calculated in the tech file by summing the widths of all the gates and dividing by the minimum width. + return parameter["6tcell_wl_cin"] diff --git a/compiler/characterizer/logical_effort.py b/compiler/characterizer/logical_effort.py new file mode 100644 index 00000000..ac6ccbc5 --- /dev/null +++ b/compiler/characterizer/logical_effort.py @@ -0,0 +1,16 @@ +import debug +from tech import drc, parameter, spice + +class logical_effort(): + """ + Class to support the values behind logical effort. Useful for storing the different components + such as logical effort, electrical effort, and parasitic delay. + """ + beta = parameter["beta"] + min_inv_cin = 1+beta + def __init__(self, size, cin, cout, parasitic): + self.cin = cin + self.cout = cout + self.logical_effort = (self.cin/size)/logical_effort.min_inv_cin + self.eletrical_effort = self.cout/self.cin + self.parasitic = parasitic \ No newline at end of file diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 1e9401b8..a369266d 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -950,4 +950,18 @@ class bank(design.design): results.append(decoder_delay + word_driver_delay + bitcell_array_delay + column_mux_delay + bl_t_data_out_delay) return results + + def determine_wordline_stage_efforts(self, external_cout): + """Get the all the stage efforts for each stage in the path within the bank clk_buf to a wordline""" + #Decoder is assumed to have settled before the negative edge of the clock. Delay model relies on this assumption + stage_effort_list = [] + wordline_cout = self.bitcell_array.get_wordline_cin() + external_cout + stage_effort_list += self.wordline_driver.determine_wordline_stage_efforts(wordline_cout) + return stage_effort_list + + def get_clk_cin(self): + """Get the relative capacitance of all the clk connections in the bank""" + #Current bank only uses clock (clk_buf) as an enable for the wordline driver. + total_clk_cin = self.wordline_driver.get_clk_cin() + return total_clk_cin \ No newline at end of file diff --git a/compiler/modules/bitcell_array.py b/compiler/modules/bitcell_array.py index 8328a0cf..b7c8ffc8 100644 --- a/compiler/modules/bitcell_array.py +++ b/compiler/modules/bitcell_array.py @@ -225,3 +225,10 @@ class bitcell_array(design.design): def input_load(self): wl_wire = self.gen_wl_wire() return wl_wire.return_input_cap() + + def get_wordline_cin(self): + """Get the relative input capacitance from the wordline connections in all the bitcell""" + #A single wordline is connected to all the bitcells in a single row meaning the capacitance depends on the # of columns + bitcell_wl_cin = self.cell.get_wl_cin() + total_cin = bitcell_wl_cin * self.column_size + return total_cin \ No newline at end of file diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index 4ac32967..a2b1dd8d 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -596,4 +596,14 @@ class control_logic(design.design): height=pin.height(), width=pin.width()) + def determine_wordline_stage_efforts(self, external_cout): + """Follows the clock signal to the clk_buf signal adding each stages stage effort to a list""" + stage_effort_list = [] + #Calculate the load on clk_buf within the module and add it to external load + internal_cout = self.ctrl_dff_array.get_clk_cin() + clk_buf_cap = internal_cout+external_cout + #First stage is the clock buffer + stage_effort_list += self.clkbuf.determine_wordline_stage_efforts(clk_buf_cap) + return stage_effort_list + \ No newline at end of file diff --git a/compiler/modules/dff.py b/compiler/modules/dff.py index 936bc822..19077689 100644 --- a/compiler/modules/dff.py +++ b/compiler/modules/dff.py @@ -2,7 +2,7 @@ import globals import design from math import log import design -from tech import GDS,layer +from tech import GDS,layer,spice,parameter import utils class dff(design.design): @@ -23,7 +23,6 @@ class dff(design.design): def analytical_power(self, proc, vdd, temp, load): """Returns dynamic and leakage power. Results in nW""" - from tech import spice c_eff = self.calculate_effective_capacitance(load) f = spice["default_event_rate"] power_dyn = c_eff*vdd*vdd*f @@ -34,7 +33,7 @@ class dff(design.design): def calculate_effective_capacitance(self, load): """Computes effective capacitance. Results in fF""" - from tech import spice, parameter + from tech import parameter c_load = load c_para = spice["flop_para_cap"]#ff transition_prob = spice["flop_transition_prob"] @@ -42,7 +41,12 @@ class dff(design.design): def analytical_delay(self, slew, load = 0.0): # dont know how to calculate this now, use constant in tech file - from tech import spice result = self.return_delay(spice["dff_delay"], spice["dff_slew"]) return result + + def get_clk_cin(self): + """Return the total capacitance (in relative units) that the clock is loaded by in the dff""" + #This is a handmade cell so the value must be entered in the tech.py file or estimated. + #Calculated in the tech file by summing the widths of all the gates and dividing by the minimum width. + return parameter["dff_clk_cin"] diff --git a/compiler/modules/dff_array.py b/compiler/modules/dff_array.py index 97e82e24..37d1ad29 100644 --- a/compiler/modules/dff_array.py +++ b/compiler/modules/dff_array.py @@ -157,3 +157,9 @@ class dff_array(design.design): def analytical_delay(self, slew, load=0.0): return self.dff.analytical_delay(slew=slew, load=load) + + def get_clk_cin(self): + """Return the total capacitance (in relative units) that the clock is loaded by in the dff array""" + dff_clk_cin = self.dff.get_clk_cin() + total_cin = dff_clk_cin * self.rows * self.columns + return total_cin \ No newline at end of file diff --git a/compiler/modules/dff_inv.py b/compiler/modules/dff_inv.py index 3a06c9c9..366d8647 100644 --- a/compiler/modules/dff_inv.py +++ b/compiler/modules/dff_inv.py @@ -148,3 +148,6 @@ class dff_inv(design.design): inv1_delay = self.inv1.analytical_delay(slew=dff_delay.slew, load=load) return dff_delay + inv1_delay + def get_clk_cin(self): + """Return the total capacitance (in relative units) that the clock is loaded by in the dff""" + return self.dff.get_clk_cin() \ No newline at end of file diff --git a/compiler/modules/dff_inv_array.py b/compiler/modules/dff_inv_array.py index aafe87e2..36231b26 100644 --- a/compiler/modules/dff_inv_array.py +++ b/compiler/modules/dff_inv_array.py @@ -182,3 +182,9 @@ class dff_inv_array(design.design): def analytical_delay(self, slew, load=0.0): return self.dff.analytical_delay(slew=slew, load=load) + + def get_clk_cin(self): + """Return the total capacitance (in relative units) that the clock is loaded by in the dff array""" + dff_clk_cin = self.dff.get_clk_cin() + total_cin = dff_clk_cin * self.rows * self.columns + return total_cin \ No newline at end of file diff --git a/compiler/modules/wordline_driver.py b/compiler/modules/wordline_driver.py index dd1039b0..8bc89734 100644 --- a/compiler/modules/wordline_driver.py +++ b/compiler/modules/wordline_driver.py @@ -238,4 +238,27 @@ class wordline_driver(design.design): def input_load(self): + """Gets the capacitance of the wordline driver in absolute units (fF)""" return self.nand2.input_load() + + def determine_wordline_stage_efforts(self, external_cout): + """Follows the clk_buf to a wordline signal adding each stages stage effort to a list""" + stage_effort_list = [] + stage1_cout = self.nand2.get_cin() + stage1 = self.inv_no_output.get_effort_stage(stage1_cout) + stage_effort_list.append(stage1) + + stage2_cout = self.inv.get_cin() + stage2 = self.nand2.get_effort_stage(stage2_cout) + stage_effort_list.append(stage2) + + stage3 = self.inv.get_effort_stage(external_cout) + stage_effort_list.append(stage3) + + return stage_effort_list + + def get_clk_cin(self): + """Get the relative capacitance of all the clk connections in the bank""" + #Clock is connected as an input to 1 inverter per row + total_cin = self.inv_no_output.get_cin() * self.rows + return total_cin \ No newline at end of file diff --git a/compiler/pgates/pinv.py b/compiler/pgates/pinv.py index 0ffd4f66..4d59b715 100644 --- a/compiler/pgates/pinv.py +++ b/compiler/pgates/pinv.py @@ -7,6 +7,7 @@ from vector import vector from math import ceil from globals import OPTS from utils import round_to_grid +import logical_effort class pinv(pgate.pgate): """ @@ -29,7 +30,8 @@ class pinv(pgate.pgate): pinv.unique_id += 1 pgate.pgate.__init__(self, name, height) debug.info(2, "create pinv structure {0} with size of {1}".format(name, size)) - + + self.size = size self.nmos_size = size self.pmos_size = beta*size self.beta = beta @@ -281,3 +283,12 @@ class pinv(pgate.pgate): c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff transition_prob = spice["inv_transition_prob"] return transition_prob*(c_load + c_para) + + def get_cin(self): + """Return the capacitance of the gate connection in generic capacitive units relative to the minimum width of a transistor""" + return self.nmos_size + self.pmos_size + + def get_effort_stage(self, cout): + """Returns an object representing the parameters for delay in tau units.""" + parasitic_delay = 1 + return logical_effort.logical_effort(self.size, self.get_cin(), cout, parasitic_delay) \ No newline at end of file diff --git a/compiler/pgates/pinvbuf.py b/compiler/pgates/pinvbuf.py index 76b3c929..490812ad 100644 --- a/compiler/pgates/pinvbuf.py +++ b/compiler/pgates/pinvbuf.py @@ -187,3 +187,14 @@ class pinvbuf(design.design): inv2_delay = self.inv2.analytical_delay(slew=inv1_delay.slew, load=load) return inv1_delay + inv2_delay + def determine_wordline_stage_efforts(self, external_cout): + """Get the stage efforts of the clk -> clk_buf path""" + stage_effort_list = [] + stage1_cout = self.inv1.get_cin() + self.inv2.get_cin() + stage1 = self.inv.get_effort_stage(stage1_cout) + stage_effort_list.append(stage1) + + stage2 = self.inv2.get_effort_stage(external_cout) + stage_effort_list.append(stage2) + + return stage_effort_list \ No newline at end of file diff --git a/compiler/pgates/pnand2.py b/compiler/pgates/pnand2.py index 1a31e3be..a79a7264 100644 --- a/compiler/pgates/pnand2.py +++ b/compiler/pgates/pnand2.py @@ -5,6 +5,7 @@ from tech import drc, parameter, spice from ptx import ptx from vector import vector from globals import OPTS +import logical_effort class pnand2(pgate.pgate): """ @@ -21,6 +22,7 @@ class pnand2(pgate.pgate): pgate.pgate.__init__(self, name, height) debug.info(2, "create pnand2 structure {0} with size of {1}".format(name, size)) + self.size = size self.nmos_size = 2*size self.pmos_size = parameter["beta"]*size self.nmos_width = self.nmos_size*drc("minwidth_tx") @@ -242,3 +244,12 @@ class pnand2(pgate.pgate): c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff transition_prob = spice["nand2_transition_prob"] return transition_prob*(c_load + c_para) + + def get_cin(self): + """Return the relative input capacitance of a single input""" + return self.nmos_size+self.pmos_size + + def get_effort_stage(self, cout): + """Returns an object representing the parameters for delay in tau units.""" + parasitic_delay = 2 + return logical_effort.logical_effort(self.size, self.get_cin(), cout, parasitic_delay) \ No newline at end of file diff --git a/compiler/sram_base.py b/compiler/sram_base.py index a1be1f30..de755f90 100644 --- a/compiler/sram_base.py +++ b/compiler/sram_base.py @@ -455,4 +455,36 @@ class sram_base(design): """ LH and HL are the same in analytical model. """ return self.bank.analytical_delay(vdd,slew,load) + def calculate_delay_to_wl(self): + stage_efforts = self.determine_wordline_stage_efforts() + return 0 + def determine_wordline_stage_efforts(self): + """Get the all the stage efforts for each stage in the path from clk to a wordline""" + stage_effort_list = [] + clk_buf_cout = self.get_clk_cin() + #Assume rw only. There are important differences with multiport that will need to be accounted for. + if self.control_logic_rw != None: + stage_effort_list += self.control_logic_rw.determine_wordline_stage_efforts(clk_buf_cout) + else: + stage_effort_list += self.control_logic_r.determine_wordline_stage_efforts(clk_buf_cout) + + #Clk_buf then move to the bank/wordline driver. Get the delay stages there. + external_wordline_cout = 0 #No loading on the wordline other than in the bank. + stage_effort_list += self.bank.determine_wordline_stage_efforts(external_wordline_cout) + + return stage_effort_list + + def get_clk_cin(self): + """Gets the capacitive load the of clock (clk_buf) for the sram""" + #As clk_buf is an output of the control logic. The cap for that module is not determined here. + row_addr_clk_cin = self.row_addr_dff.get_clk_cin() + data_clk_cin = self.data_dff.get_clk_cin() + col_addr_clk_cin = 0 + if self.col_addr_size > 0: + col_addr_clk_cin = self.col_addr_dff.get_clk_cin() + + #Bank cin... + bank_clk_cin = self.bank.get_clk_cin() + + return row_addr_clk_cin + data_clk_cin + col_addr_clk_cin + bank_clk_cin diff --git a/technology/freepdk45/tech/tech.py b/technology/freepdk45/tech/tech.py index 6cbeabdd..dd83793b 100644 --- a/technology/freepdk45/tech/tech.py +++ b/technology/freepdk45/tech/tech.py @@ -328,6 +328,10 @@ spice["nand2_transition_prob"] = .1875 # Transition probability of 2-input na spice["nand3_transition_prob"] = .1094 # Transition probability of 3-input nand. spice["nor2_transition_prob"] = .1875 # Transition probability of 2-input nor. +#Logical Effort relative values for the Handmade cells +spice["dff_clk_cin"] = 30.6 +parameter["6tcell_wl_cin"] = 3 + ################################################### ##END Spice Simulation Parameters ################################################### diff --git a/technology/scn4m_subm/tech/tech.py b/technology/scn4m_subm/tech/tech.py index 25afd844..d61ea5a4 100755 --- a/technology/scn4m_subm/tech/tech.py +++ b/technology/scn4m_subm/tech/tech.py @@ -293,6 +293,11 @@ spice["inv_transition_prob"] = .5 # Transition probability of inverter. spice["nand2_transition_prob"] = .1875 # Transition probability of 2-input nand. spice["nand3_transition_prob"] = .1094 # Transition probability of 3-input nand. spice["nor2_transition_prob"] = .1875 # Transition probability of 2-input nor. + +#Logical Effort relative values for the Handmade cells +parameter["dff_clk_cin"] = 27.5 +parameter["6tcell_wl_cin"] = 2 + ################################################### ##END Spice Simulation Parameters ###################################################