summaryrefslogtreecommitdiff
path: root/src/mem/ruby/network/orion/power_array.cc
diff options
context:
space:
mode:
authorNathan Binkert <nate@binkert.org>2009-05-11 10:38:43 -0700
committerNathan Binkert <nate@binkert.org>2009-05-11 10:38:43 -0700
commit2f30950143cc70bc42a3c8a4111d7cf8198ec881 (patch)
tree708f6c22edb3c6feb31dd82866c26623a5329580 /src/mem/ruby/network/orion/power_array.cc
parentc70241810d4e4f523f173c1646b008dc40faad8e (diff)
downloadgem5-2f30950143cc70bc42a3c8a4111d7cf8198ec881.tar.xz
ruby: Import ruby and slicc from GEMS
We eventually plan to replace the m5 cache hierarchy with the GEMS hierarchy, but for now we will make both live alongside eachother.
Diffstat (limited to 'src/mem/ruby/network/orion/power_array.cc')
-rw-r--r--src/mem/ruby/network/orion/power_array.cc2158
1 files changed, 2158 insertions, 0 deletions
diff --git a/src/mem/ruby/network/orion/power_array.cc b/src/mem/ruby/network/orion/power_array.cc
new file mode 100644
index 000000000..225f45377
--- /dev/null
+++ b/src/mem/ruby/network/orion/power_array.cc
@@ -0,0 +1,2158 @@
+/*
+ * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <math.h>
+
+#include "power_array.hh"
+#include "power_ll.hh"
+#include "parm_technology.hh"
+#include "SIM_port.hh"
+#include "power_static.hh"
+#include "power_utils.hh"
+
+/* local macros */
+
+#define IS_DIRECT_MAP( info ) ((info)->assoc == 1)
+#define IS_FULLY_ASSOC( info ) ((info)->n_set == 1 && (info)->assoc > 1)
+#define IS_WRITE_THROUGH( info ) (! (info)->write_policy)
+#define IS_WRITE_BACK( info ) ((info)->write_policy)
+
+/* sufficient (not necessary) condition */
+#define HAVE_TAG( info ) ((info)->tag_mem_model)
+#define HAVE_USE_BIT( info ) ((info)->use_bit_width)
+#define HAVE_COL_DEC( info ) ((info)->col_dec_model)
+#define HAVE_COL_MUX( info ) ((info)->mux_model)
+
+
+/* ----------------------------- CAM ---------------------------------- */
+/*============================== wordlines ==============================*/
+
+/* each time one wordline 1->0, another wordline 0->1, so no 1/2 */
+double SIM_cam_wordline_cap( unsigned cols, double wire_cap, double tx_width )
+{
+ double Ctotal, Cline, psize, nsize;
+
+ /* part 1: line cap, including gate cap of pass tx's and metal cap */
+ Ctotal = Cline = SIM_power_gatecappass( tx_width, 2 ) * cols + wire_cap;
+
+ /* part 2: input driver */
+ psize = SIM_power_driver_size( Cline, Period / 8 );
+ nsize = psize * Wdecinvn / Wdecinvp;
+ /* WHS: 20 should go to PARM */
+ Ctotal += SIM_power_draincap( nsize, NCH, 1 ) + SIM_power_draincap( psize, PCH, 1 ) +
+ SIM_power_gatecap( nsize + psize, 20 );
+
+ return Ctotal;
+}
+
+/*============================== wordlines ==============================*/
+
+
+
+/*============================== tag comparator ==============================*/
+
+/* tag and tagbar switch simultaneously, so no 1/2 */
+double SIM_cam_comp_tagline_cap( unsigned rows, double taglinelength )
+{
+ double Ctotal;
+
+ /* part 1: line cap, including drain cap of pass tx's and metal cap */
+ Ctotal = rows * SIM_power_gatecap( Wcomparen2, 2 ) + CC3M2metal * taglinelength;
+
+ /* part 2: input driver */
+ Ctotal += SIM_power_draincap( Wcompdrivern, NCH, 1 ) + SIM_power_draincap( Wcompdriverp, PCH, 1 ) +
+ SIM_power_gatecap( Wcompdrivern + Wcompdriverp, 1 );
+
+ return Ctotal;
+}
+
+
+/* upon mismatch, matchline 1->0, then 0->1 on next precharging, so no 1/2 */
+double SIM_cam_comp_mismatch_cap( unsigned n_bits, unsigned n_pre, double matchline_len )
+{
+ double Ctotal;
+
+ /* part 1: drain cap of precharge tx */
+ Ctotal = n_pre * SIM_power_draincap( Wmatchpchg, PCH, 1 );
+
+ /* part 2: drain cap of comparator tx */
+ Ctotal += n_bits * ( SIM_power_draincap( Wcomparen1, NCH, 1 ) + SIM_power_draincap( Wcomparen1, NCH, 2 ));
+
+ /* part 3: metal cap of matchline */
+ Ctotal += CC3M3metal * matchline_len;
+
+ /* FIXME: I don't understand the Wattch code here */
+ /* part 4: nor gate of valid output */
+ Ctotal += SIM_power_gatecap( Wmatchnorn + Wmatchnorp, 10 );
+
+ return Ctotal;
+}
+
+
+/* WHS: subtle difference of valid output between cache and inst window:
+ * fully-associative cache: nor all matchlines of the same port
+ * instruction window: nor all matchlines of the same tag line */
+/* upon miss, valid output switches twice in one cycle, so no 1/2 */
+double SIM_cam_comp_miss_cap( unsigned assoc )
+{
+ /* drain cap of valid output */
+ return ( assoc * SIM_power_draincap( Wmatchnorn, NCH, 1 ) + SIM_power_draincap( Wmatchnorp, PCH, assoc ));
+}
+
+/*============================== tag comparator ==============================*/
+
+
+
+/*============================== memory cell ==============================*/
+
+/* WHS: use Wmemcella and Wmemcellbscale to compute tx width of memory cell */
+double SIM_cam_tag_mem_cap( unsigned read_ports, unsigned write_ports, int share_rw, unsigned end, int only_write )
+{
+ double Ctotal;
+
+ /* part 1: drain capacitance of pass transistors */
+ if ( only_write )
+ Ctotal = SIM_power_draincap( Wmemcellw, NCH, 1 ) * write_ports;
+ else {
+ Ctotal = SIM_power_draincap( Wmemcellr, NCH, 1 ) * read_ports * end / 2;
+ if ( ! share_rw )
+ Ctotal += SIM_power_draincap( Wmemcellw, NCH, 1 ) * write_ports;
+ }
+
+ /* has coefficient ( 1/2 * 2 ) */
+ /* part 2: drain capacitance of memory cell */
+ Ctotal += SIM_power_draincap( Wmemcella, NCH, 1 ) + SIM_power_draincap( Wmemcella * Wmemcellbscale, PCH, 1 );
+
+ /* has coefficient ( 1/2 * 2 ) */
+ /* part 3: gate capacitance of memory cell */
+ Ctotal += SIM_power_gatecap( Wmemcella, 1 ) + SIM_power_gatecap( Wmemcella * Wmemcellbscale, 1 );
+
+ /* has coefficient ( 1/2 * 2 ) */
+ /* part 4: gate capacitance of comparator */
+ Ctotal += SIM_power_gatecap( Wcomparen1, 2 ) * read_ports;
+
+ return Ctotal;
+}
+
+
+double SIM_cam_data_mem_cap( unsigned read_ports, unsigned write_ports )
+{
+ double Ctotal;
+
+ /* has coefficient ( 1/2 * 2 ) */
+ /* part 1: drain capacitance of pass transistors */
+ Ctotal = SIM_power_draincap( Wmemcellw, NCH, 1 ) * write_ports;
+
+ /* has coefficient ( 1/2 * 2 ) */
+ /* part 2: drain capacitance of memory cell */
+ Ctotal += SIM_power_draincap( Wmemcella, NCH, 1 ) + SIM_power_draincap( Wmemcella * Wmemcellbscale, PCH, 1 );
+
+ /* has coefficient ( 1/2 * 2 ) */
+ /* part 3: gate capacitance of memory cell */
+ Ctotal += SIM_power_gatecap( Wmemcella, 1 ) + SIM_power_gatecap( Wmemcella * Wmemcellbscale, 1 );
+
+ /* part 4: gate capacitance of output driver */
+ Ctotal += ( SIM_power_gatecap( Woutdrvnandn, 1 ) + SIM_power_gatecap( Woutdrvnandp, 1 ) +
+ SIM_power_gatecap( Woutdrvnorn, 1 ) + SIM_power_gatecap( Woutdrvnorp, 1 )) / 2 * read_ports;
+
+ return Ctotal;
+}
+
+/*============================== memory cell ==============================*/
+
+
+
+
+
+
+
+/* ---------- buffer model ------------ */
+
+// ------- Decoder begin
+
+/*#
+ * compute switching cap when decoder changes output (select signal)
+ *
+ * Parameters:
+ * n_input -- fanin of 1 gate of last level decoder
+ *
+ * Return value: switching cap
+ *
+ * NOTES: 2 select signals switch, so no 1/2
+ */
+static double SIM_array_dec_select_cap( unsigned n_input )
+{
+ double Ctotal = 0;
+
+ /* FIXME: why? */
+ // if ( numstack > 5 ) numstack = 5;
+
+ /* part 1: drain cap of last level decoders */
+ Ctotal = n_input * SIM_power_draincap( WdecNORn, NCH, 1 ) + SIM_power_draincap( WdecNORp, PCH, n_input );
+
+ /* part 2: output inverter */
+ /* WHS: 20 should go to PARM */
+ Ctotal += SIM_power_draincap( Wdecinvn, NCH, 1 ) + SIM_power_draincap( Wdecinvp, PCH, 1) +
+ SIM_power_gatecap( Wdecinvn + Wdecinvp, 20 );
+
+ return Ctotal;
+}
+
+
+/*#
+ * compute switching cap when 1 input bit of decoder changes
+ *
+ * Parameters:
+ * n_gates -- fanout of 1 addr signal
+ *
+ * Return value: switching cap
+ *
+ * NOTES: both addr and its complement change, so no 1/2
+ */
+static double SIM_array_dec_chgaddr_cap( unsigned n_gates )
+{
+ double Ctotal;
+
+ /* stage 1: input driver */
+ Ctotal = SIM_power_draincap( Wdecdrivep, PCH, 1 ) + SIM_power_draincap( Wdecdriven, NCH, 1 ) +
+ SIM_power_gatecap( Wdecdrivep, 1 ) + SIM_power_gatecap( Wdecdriven, 1 );
+ /* inverter to produce complement addr, this needs 1/2 */
+ /* WHS: assume Wdecinv(np) for this inverter */
+ Ctotal += ( SIM_power_draincap( Wdecinvp, PCH, 1 ) + SIM_power_draincap( Wdecinvn, NCH, 1 ) +
+ SIM_power_gatecap( Wdecinvp, 1 ) + SIM_power_gatecap( Wdecinvn, 1 )) / 2;
+
+ /* stage 2: gate cap of level-1 decoder */
+ /* WHS: 10 should go to PARM */
+ Ctotal += n_gates * SIM_power_gatecap( Wdec3to8n + Wdec3to8p, 10 );
+
+ return Ctotal;
+}
+
+
+/*#
+ * compute switching cap when 1st-level decoder changes output
+ *
+ * Parameters:
+ * n_in_1st -- fanin of 1 gate of 1st-level decoder
+ * n_in_2nd -- fanin of 1 gate of 2nd-level decoder
+ * n_gates -- # of gates of 2nd-level decoder, i.e.
+ * fanout of 1 gate of 1st-level decoder
+ *
+ * Return value: switching cap
+ *
+ * NOTES: 2 complementary signals switch, so no 1/2
+ */
+static double SIM_array_dec_chgl1_cap( unsigned n_in_1st, unsigned n_in_2nd, unsigned n_gates )
+{
+ double Ctotal;
+
+ /* part 1: drain cap of level-1 decoder */
+ Ctotal = n_in_1st * SIM_power_draincap( Wdec3to8p, PCH, 1 ) + SIM_power_draincap( Wdec3to8n, NCH, n_in_1st );
+
+ /* part 2: gate cap of level-2 decoder */
+ /* WHS: 40 and 20 should go to PARM */
+ Ctotal += n_gates * SIM_power_gatecap( WdecNORn + WdecNORp, n_in_2nd * 40 + 20 );
+
+ return Ctotal;
+}
+
+
+static int SIM_array_dec_clear_stat(power_decoder *dec)
+{
+ dec->n_chg_output = dec->n_chg_l1 = dec->n_chg_addr = 0;
+
+ return 0;
+}
+
+
+/*#
+ * initialize decoder
+ *
+ * Parameters:
+ * dec -- decoder structure
+ * model -- decoder model type
+ * n_bits -- decoder width
+ *
+ * Side effects:
+ * initialize dec structure if model type is valid
+ *
+ * Return value: -1 if model type is invalid
+ * 0 otherwise
+ */
+static int SIM_array_dec_init(power_decoder *dec, int model, unsigned n_bits )
+{
+ if ((dec->model = model) && model < DEC_MAX_MODEL) {
+ dec->n_bits = n_bits;
+ /* redundant field */
+ dec->addr_mask = HAMM_MASK(n_bits);
+
+ SIM_array_dec_clear_stat(dec);
+ dec->e_chg_output = dec->e_chg_l1 = dec->e_chg_addr = 0;
+
+ /* compute geometry parameters */
+ if ( n_bits >= 4 ) { /* 2-level decoder */
+ /* WHS: inaccurate for some n_bits */
+ dec->n_in_1st = ( n_bits == 4 ) ? 2:3;
+ dec->n_out_0th = BIGONE << ( dec->n_in_1st - 1 );
+ dec->n_in_2nd = (unsigned)ceil((double)n_bits / dec->n_in_1st );
+ dec->n_out_1st = BIGONE << ( n_bits - dec->n_in_1st );
+ }
+ else if ( n_bits >= 2 ) { /* 1-level decoder */
+ dec->n_in_1st = n_bits;
+ dec->n_out_0th = BIGONE << ( n_bits - 1 );
+ dec->n_in_2nd = dec->n_out_1st = 0;
+ }
+ else { /* no decoder basically */
+ dec->n_in_1st = dec->n_in_2nd = dec->n_out_0th = dec->n_out_1st = 0;
+ }
+
+ /* compute energy constants */
+ if ( n_bits >= 2 ) {
+ dec->e_chg_l1 = SIM_array_dec_chgl1_cap( dec->n_in_1st, dec->n_in_2nd, dec->n_out_1st ) * EnergyFactor;
+ if ( n_bits >= 4 )
+ dec->e_chg_output = SIM_array_dec_select_cap( dec->n_in_2nd ) * EnergyFactor;
+ }
+ dec->e_chg_addr = SIM_array_dec_chgaddr_cap( dec->n_out_0th ) * EnergyFactor;
+
+ return 0;
+ }
+ else
+ return -1;
+}
+
+
+/*#
+ * record decoder power stats
+ *
+ * Parameters:
+ * dec -- decoder structure
+ * prev_addr -- previous input
+ * curr_addr -- current input
+ *
+ * Side effects:
+ * update counters in dec structure
+ *
+ * Return value: 0
+ */
+int SIM_array_dec_record(power_decoder *dec, unsigned long int prev_addr, unsigned long int curr_addr )
+{
+ unsigned n_chg_bits, n_chg_l1 = 0, n_chg_output = 0;
+ unsigned i;
+ unsigned long int mask;
+
+ /* compute Hamming distance */
+ n_chg_bits = SIM_power_Hamming( prev_addr, curr_addr, dec->addr_mask );
+ if ( n_chg_bits ) {
+ if ( dec->n_bits >= 4 ) { /* 2-level decoder */
+ /* WHS: inaccurate for some n_bits */
+ n_chg_output ++;
+ /* count addr group changes */
+ mask = HAMM_MASK(dec->n_in_1st);
+ for ( i = 0; i < dec->n_in_2nd; i ++ ) {
+ if ( SIM_power_Hamming( prev_addr, curr_addr, mask ))
+ n_chg_l1 ++;
+ mask = mask << dec->n_in_1st;
+ }
+ }
+ else if ( dec->n_bits >= 2 ) { /* 1-level decoder */
+ n_chg_l1 ++;
+ }
+
+ dec->n_chg_addr += n_chg_bits;
+ dec->n_chg_l1 += n_chg_l1;
+ dec->n_chg_output += n_chg_output;
+ }
+
+ return 0;
+}
+
+
+/*#
+ * report decoder power stats
+ *
+ * Parameters:
+ * dec -- decoder structure
+ *
+ * Return value: total energy consumption of this decoder
+ *
+ * TODO: add more report functionality, currently only total energy is reported
+ */
+double SIM_array_dec_report(power_decoder *dec )
+{
+ double Etotal;
+
+ Etotal = dec->n_chg_output * dec->e_chg_output + dec->n_chg_l1 * dec->e_chg_l1 +
+ dec->n_chg_addr * dec->e_chg_addr;
+
+ /* bonus energy for dynamic decoder :) */
+ //if ( is_dynamic_dec( dec->model )) Etotal += Etotal;
+
+ return Etotal;
+}
+
+// ------- Decoder end
+
+
+
+// ------- Wordlines begin
+
+/*#
+ * compute wordline switching cap
+ *
+ * Parameters:
+ * cols -- # of pass transistors, i.e. # of bitlines
+ * wordlinelength -- length of wordline
+ * tx_width -- width of pass transistor
+ *
+ * Return value: switching cap
+ *
+ * NOTES: upon address change, one wordline 1->0, another 0->1, so no 1/2
+ */
+static double SIM_array_wordline_cap( unsigned cols, double wire_cap, double tx_width )
+{
+ double Ctotal, Cline, psize, nsize;
+
+ /* part 1: line cap, including gate cap of pass tx's and metal cap */
+ Ctotal = Cline = SIM_power_gatecappass( tx_width, BitWidth / 2 - tx_width ) * cols + wire_cap;
+
+ /* part 2: input driver */
+ psize = SIM_power_driver_size( Cline, Period / 16 );
+ nsize = psize * Wdecinvn / Wdecinvp;
+ /* WHS: 20 should go to PARM */
+ Ctotal += SIM_power_draincap( nsize, NCH, 1 ) + SIM_power_draincap( psize, PCH, 1 ) +
+ SIM_power_gatecap( nsize + psize, 20 );
+
+ return Ctotal;
+}
+
+
+static int SIM_array_wordline_clear_stat(power_wordline *wordline)
+{
+ wordline->n_read = wordline->n_write = 0;
+
+ return 0;
+}
+
+
+/*#
+ * initialize wordline
+ *
+ * Parameters:
+ * wordline -- wordline structure
+ * model -- wordline model type
+ * share_rw -- 1 if shared R/W wordlines, 0 if separate R/W wordlines
+ * cols -- # of array columns, NOT # of bitlines
+ * wire_cap -- wordline wire capacitance
+ * end -- end of bitlines
+ *
+ * Return value: -1 if invalid model type
+ * 0 otherwise
+ *
+ * Side effects:
+ * initialize wordline structure if model type is valid
+ *
+ * TODO: add error handler
+ */
+static int SIM_array_wordline_init(power_wordline *wordline, int model, int share_rw, unsigned cols, double wire_cap, unsigned end )
+{
+ if ((wordline->model = model) && model < WORDLINE_MAX_MODEL) {
+ SIM_array_wordline_clear_stat(wordline);
+
+ switch ( model ) {
+ case CAM_RW_WORDLINE:
+ wordline->e_read = SIM_cam_wordline_cap( cols * end, wire_cap, Wmemcellr ) * EnergyFactor;
+ if ( wordline->share_rw = share_rw )
+ wordline->e_write = wordline->e_read;
+ else
+ /* write bitlines are always double-ended */
+ wordline->e_write = SIM_cam_wordline_cap( cols * 2, wire_cap, Wmemcellw ) * EnergyFactor;
+ break;
+
+ case CAM_WO_WORDLINE: /* only have write wordlines */
+ wordline->share_rw = 0;
+ wordline->e_read = 0;
+ wordline->e_write = SIM_cam_wordline_cap( cols * 2, wire_cap, Wmemcellw ) * EnergyFactor;
+ break;
+
+ case CACHE_WO_WORDLINE: /* only have write wordlines */
+ wordline->share_rw = 0;
+ wordline->e_read = 0;
+ wordline->e_write = SIM_array_wordline_cap( cols * 2, wire_cap, Wmemcellw ) * EnergyFactor;
+ break;
+
+ case CACHE_RW_WORDLINE:
+ wordline->e_read = SIM_array_wordline_cap( cols * end, wire_cap, Wmemcellr ) * EnergyFactor;
+ if ( wordline->share_rw = share_rw )
+ wordline->e_write = wordline->e_read;
+ else
+ wordline->e_write = SIM_array_wordline_cap( cols * 2, wire_cap, Wmemcellw ) * EnergyFactor;
+
+ /* static power */
+ /* input driver */
+ wordline->i_leakage = (Woutdrivern * NMOS_TAB[0] + Woutdriverp * PMOS_TAB[0]) / PARM_TECH_POINT * 100;
+ break;
+
+ default: break;/* some error handler */
+ }
+
+ return 0;
+ }
+ else
+ return -1;
+}
+
+
+/*#
+ * record wordline power stats
+ *
+ * Parameters:
+ * wordline -- wordline structure
+ * rw -- 1 if write operation, 0 if read operation
+ * n_switch -- switching times
+ *
+ * Return value: 0
+ *
+ * Side effects:
+ * update counters of wordline structure
+ */
+int SIM_array_wordline_record(power_wordline *wordline, int rw, unsigned long int n_switch )
+{
+ if ( rw ) wordline->n_write += n_switch;
+ else wordline->n_read += n_switch;
+
+ return 0;
+}
+
+
+/*#
+ * report wordline power stats
+ *
+ * Parameters:
+ * wordline -- wordline structure
+ *
+ * Return value: total energy consumption of all wordlines of this array
+ *
+ * TODO: add more report functionality, currently only total energy is reported
+ */
+double SIM_array_wordline_report(power_wordline *wordline )
+{
+ return ( wordline->n_read * wordline->e_read +
+ wordline->n_write * wordline->e_write );
+}
+
+// ------- Wordlines end
+
+
+
+// ------- Bitlines begin
+
+/*#
+ * compute switching cap of reading 1 separate bitline column
+ *
+ * Parameters:
+ * rows -- # of array rows, i.e. # of wordlines
+ * wire_cap -- bitline wire capacitance
+ * end -- end of bitlines
+ * n_share_amp -- # of columns who share one sense amp
+ * n_bitline_pre -- # of precharge transistor drains for 1 bitline column
+ * n_colsel_pre -- # of precharge transistor drains for 1 column selector, if any
+ * pre_size -- width of precharge transistors
+ * outdrv_model -- output driver model type
+ *
+ * Return value: switching cap
+ *
+ * NOTES: one bitline 1->0, then 0->1 on next precharging, so no 1/2
+ */
+static double SIM_array_column_read_cap(unsigned rows, double wire_cap, unsigned end, unsigned n_share_amp, unsigned n_bitline_pre, unsigned n_colsel_pre, double pre_size, int outdrv_model)
+{
+ double Ctotal=0, Cprecharge=0, Cpass=0, Cwire=0, Ccol_sel=0, Csense=0;
+
+ /* part 1: drain cap of precharge tx's */
+ Cprecharge = n_bitline_pre * SIM_power_draincap( pre_size, PCH, 1 );
+// printf("Precharge = %g\n", Cprecharge);
+ Ctotal = Cprecharge;
+
+ /* part 2: drain cap of pass tx's */
+ Cpass = rows * SIM_power_draincap( Wmemcellr, NCH, 1 );
+// printf("Pass = %g\n", Cpass);
+ Ctotal += Cpass;
+
+ /* part 3: metal cap */
+ Cwire = wire_cap;
+// printf("Wire = %g\n", Cwire);
+ Ctotal += Cwire;
+
+ /* part 4: column selector or bitline inverter */
+ if ( end == 1 ) { /* bitline inverter */
+ /* FIXME: magic numbers */
+ Ccol_sel = SIM_power_gatecap( MSCALE * ( 29.9 + 7.8 ), 0 ) +
+ SIM_power_gatecap( MSCALE * ( 47.0 + 12.0), 0 );
+ }
+ else if ( n_share_amp > 1 ) { /* column selector */
+ /* drain cap of pass tx's */
+ Ccol_sel = ( n_share_amp + 1 ) * SIM_power_draincap( Wbitmuxn, NCH, 1 );
+ /* drain cap of column selector precharge tx's */
+ Ccol_sel += n_colsel_pre * SIM_power_draincap( pre_size, PCH, 1 );
+ /* FIXME: no way to count activity factor on gates of column selector */
+ }
+// printf("Col selector = %g\n", Ccol_sel);
+
+ Ctotal += Ccol_sel;
+
+ /* part 5: gate cap of sense amplifier or output driver */
+ if (end == 2) /* sense amplifier */
+ Csense = 2 * SIM_power_gatecap( WsenseQ1to4, 10 );
+ else if (outdrv_model) /* end == 1, output driver */
+ Csense = SIM_power_gatecap( Woutdrvnandn, 1 ) + SIM_power_gatecap( Woutdrvnandp, 1 ) +
+ SIM_power_gatecap( Woutdrvnorn, 1 ) + SIM_power_gatecap( Woutdrvnorp, 1 );
+// printf("Sense = %g\n", Csense);
+ Ctotal += Csense;
+
+ return Ctotal;
+}
+
+
+/*#
+ * compute switching cap of selecting 1 column selector
+ *
+ * Parameters:
+ *
+ * Return value: switching cap
+ *
+ * NOTES: select one, deselect another, so no 1/2
+ */
+static double SIM_array_column_select_cap( void )
+{
+ return SIM_power_gatecap( Wbitmuxn, 1 );
+}
+
+
+/*#
+ * compute switching cap of writing 1 separate bitline column
+ *
+ * Parameters:
+ * rows -- # of array rows, i.e. # of wordlines
+ * wire_cap -- bitline wire capacitance
+ *
+ * Return value: switching cap
+ *
+ * NOTES: bit and bitbar switch simultaneously, so no 1/2
+ */
+static double SIM_array_column_write_cap( unsigned rows, double wire_cap )
+{
+ double Ctotal=0, Cwire=0, Cpass=0, Cdriver=0, psize, nsize;
+
+ Cwire = wire_cap;
+// printf("WRITE wire cap = %g\n", Cwire);
+ Ctotal = Cwire;
+
+ /* part 1: line cap, including drain cap of pass tx's and metal cap */
+ Cpass = rows * SIM_power_draincap( Wmemcellw, NCH, 1 );
+// printf("WRITE pass tx cap = %g\n", Cpass);
+ Ctotal += Cpass;
+
+
+ /* part 2: write driver */
+ psize = SIM_power_driver_size( Ctotal, Period / 8 );
+ nsize = psize * Wdecinvn / Wdecinvp;
+ Cdriver = SIM_power_draincap( psize, PCH, 1 ) + SIM_power_draincap( nsize, NCH, 1 ) +
+ SIM_power_gatecap( psize + nsize, 1 );
+// printf("WRITE driver cap = %g\n", Cdriver);
+ Ctotal += Cdriver;
+
+ return Ctotal;
+}
+
+
+/* one bitline switches twice in one cycle, so no 1/2 */
+static double SIM_array_share_column_write_cap( unsigned rows, double wire_cap, unsigned n_share_amp, unsigned n_bitline_pre, double pre_size )
+{
+ double Ctotal, psize, nsize;
+
+ /* part 1: drain cap of precharge tx's */
+ Ctotal = n_bitline_pre * SIM_power_draincap( pre_size, PCH, 1 );
+
+ /* part 2: drain cap of pass tx's */
+ Ctotal += rows * SIM_power_draincap( Wmemcellr, NCH, 1 );
+
+ /* part 3: metal cap */
+ Ctotal += wire_cap;
+
+ /* part 4: column selector or sense amplifier */
+ if ( n_share_amp > 1 ) Ctotal += SIM_power_draincap( Wbitmuxn, NCH, 1 );
+ else Ctotal += 2 * SIM_power_gatecap( WsenseQ1to4, 10 );
+
+ /* part 5: write driver */
+ psize = SIM_power_driver_size( Ctotal, Period / 8 );
+ nsize = psize * Wdecinvn / Wdecinvp;
+ /* WHS: omit gate cap of driver due to modeling difficulty */
+ Ctotal += SIM_power_draincap( psize, PCH, 1 ) + SIM_power_draincap( nsize, NCH, 1 );
+
+ return Ctotal;
+}
+
+
+/* one bitline switches twice in one cycle, so no 1/2 */
+static double SIM_array_share_column_read_cap( unsigned rows, double wire_cap, unsigned n_share_amp, unsigned n_bitline_pre, unsigned n_colsel_pre, double pre_size )
+{
+ double Ctotal;
+
+ /* part 1: same portion as write */
+ Ctotal = SIM_array_share_column_write_cap( rows, wire_cap, n_share_amp, n_bitline_pre, pre_size );
+
+ /* part 2: column selector and sense amplifier */
+ if ( n_share_amp > 1 ) {
+ /* bottom part of drain cap of pass tx's */
+ Ctotal += n_share_amp * SIM_power_draincap( Wbitmuxn, NCH, 1 );
+ /* drain cap of column selector precharge tx's */
+ Ctotal += n_colsel_pre * SIM_power_draincap( pre_size, PCH, 1 );
+
+ /* part 3: gate cap of sense amplifier */
+ Ctotal += 2 * SIM_power_gatecap( WsenseQ1to4, 10 );
+ }
+
+ return Ctotal;
+}
+
+
+static int SIM_array_bitline_clear_stat(power_bitline *bitline)
+{
+ bitline->n_col_write = bitline->n_col_read = bitline->n_col_sel = 0;
+
+ return 0;
+}
+
+
+static int SIM_array_bitline_init(power_bitline *bitline, int model, int share_rw, unsigned end, unsigned rows, double wire_cap, unsigned n_share_amp, unsigned n_bitline_pre, unsigned n_colsel_pre, double pre_size, int outdrv_model)
+{
+ if ((bitline->model = model) && model < BITLINE_MAX_MODEL) {
+ bitline->end = end;
+ SIM_array_bitline_clear_stat(bitline);
+
+ switch ( model ) {
+ case RW_BITLINE:
+ if ( end == 2 )
+ bitline->e_col_sel = SIM_array_column_select_cap() * EnergyFactor;
+ else /* end == 1 implies register file */
+ bitline->e_col_sel = 0;
+// printf("BUFFER INTERNAL bitline sel energy = %g\n", bitline->e_col_sel);
+
+ if ( bitline->share_rw = share_rw ) {
+ /* shared bitlines are double-ended, so SenseEnergyFactor */
+ bitline->e_col_read = SIM_array_share_column_read_cap( rows, wire_cap, n_share_amp, n_bitline_pre, n_colsel_pre, pre_size ) * SenseEnergyFactor;
+ bitline->e_col_write = SIM_array_share_column_write_cap( rows, wire_cap, n_share_amp, n_bitline_pre, pre_size ) * EnergyFactor;
+ }
+ else {
+ bitline->e_col_read = SIM_array_column_read_cap(rows, wire_cap, end, n_share_amp, n_bitline_pre, n_colsel_pre, pre_size, outdrv_model) * (end == 2 ? SenseEnergyFactor : EnergyFactor);
+// printf("BUFFER INTERNAL bitline read energy = %g\n", bitline->e_col_read);
+ bitline->e_col_write = SIM_array_column_write_cap( rows, wire_cap ) * EnergyFactor;
+// printf("BUFFER INTERNAL bitline write energy = %g\n", bitline->e_col_write);
+
+ /* static power */
+ bitline->i_leakage = 2 * (Wdecinvn * NMOS_TAB[0] + Wdecinvp * PMOS_TAB[0]) / PARM_TECH_POINT * 100;
+// printf("BUFFER INTERNAL bitline leakage current = %g\n", bitline->i_leakage);
+ }
+
+ break;
+
+ case WO_BITLINE: /* only have write bitlines */
+ bitline->share_rw = 0;
+ bitline->e_col_sel = bitline->e_col_read = 0;
+ bitline->e_col_write = SIM_array_column_write_cap( rows, wire_cap ) * EnergyFactor;
+ break;
+
+ default: break;/* some error handler */
+ }
+
+ return 0;
+ }
+ else
+ return -1;
+}
+
+
+static int is_rw_bitline( int model )
+{
+ return ( model == RW_BITLINE );
+}
+
+
+/* WHS: no way to count activity factor on column selector gates */
+int SIM_array_bitline_record(power_bitline *bitline, int rw, unsigned cols, unsigned long int old_value, unsigned long int new_value )
+{
+ /* FIXME: should use variable rather than computing each time */
+ unsigned long int mask = HAMM_MASK(cols);
+
+ if ( rw ) { /* write */
+ if ( bitline->share_rw ) /* share R/W bitlines */
+ bitline->n_col_write += cols;
+ else /* separate R/W bitlines */
+ bitline->n_col_write += SIM_power_Hamming( old_value, new_value, mask );
+ }
+ else { /* read */
+ if ( bitline->end == 2 ) /* double-ended bitline */
+ bitline->n_col_read += cols;
+ else /* single-ended bitline */
+ /* WHS: read ~new_value due to the bitline inverter */
+ bitline->n_col_read += SIM_power_Hamming( mask, ~new_value, mask );
+ }
+
+ return 0;
+}
+
+
+double SIM_array_bitline_report(power_bitline *bitline )
+{
+ return ( bitline->n_col_write * bitline->e_col_write +
+ bitline->n_col_read * bitline->e_col_read +
+ bitline->n_col_sel * bitline->e_col_sel );
+}
+
+// ------- Bitlines end
+
+
+
+// ------- Sense amplifier begin
+
+/* estimate senseamp power dissipation in cache structures (Zyuban's method) */
+static double SIM_array_amp_energy( void )
+{
+ return ( (double)Vdd / 8.0 * (double )(Period) * (double )(PARM_amp_Idsat));
+}
+
+
+static int SIM_array_amp_clear_stat(power_amp *amp)
+{
+ amp->n_access = 0;
+
+ return 0;
+}
+
+
+static int SIM_array_amp_init(power_amp *amp, int model )
+{
+ if ((amp->model = model) && model < AMP_MAX_MODEL) {
+ SIM_array_amp_clear_stat(amp);
+ amp->e_access = SIM_array_amp_energy();
+
+ return 0;
+ }
+ else
+ return -1;
+}
+
+
+int SIM_array_amp_record(power_amp *amp, unsigned cols )
+{
+ amp->n_access += cols;
+
+ return 0;
+}
+
+
+double SIM_array_amp_report(power_amp *amp )
+{
+ return ( amp->n_access * amp->e_access );
+}
+
+// ------- Sense amplifier end
+
+
+// ------- Tag comparator begin
+
+/* eval switches twice per cycle, so no 1/2 */
+/* WHS: assume eval = 1 when no cache operation */
+static double SIM_array_comp_base_cap( void )
+{
+ /* eval tx's: 4 inverters */
+ return ( SIM_power_draincap( Wevalinvp, PCH, 1 ) + SIM_power_draincap( Wevalinvn, NCH, 1 ) +
+ SIM_power_gatecap( Wevalinvp, 1 ) + SIM_power_gatecap( Wevalinvn, 1 ) +
+ SIM_power_draincap( Wcompinvp1, PCH, 1 ) + SIM_power_draincap( Wcompinvn1, NCH, 1 ) +
+ SIM_power_gatecap( Wcompinvp1, 1 ) + SIM_power_gatecap( Wcompinvn1, 1 ) +
+ SIM_power_draincap( Wcompinvp2, PCH, 1 ) + SIM_power_draincap( Wcompinvn2, NCH, 1 ) +
+ SIM_power_gatecap( Wcompinvp2, 1 ) + SIM_power_gatecap( Wcompinvn2, 1 ) +
+ SIM_power_draincap( Wcompinvp3, PCH, 1 ) + SIM_power_draincap( Wcompinvn3, NCH, 1 ) +
+ SIM_power_gatecap( Wcompinvp3, 1 ) + SIM_power_gatecap( Wcompinvn3, 1 ));
+}
+
+
+/* no 1/2 for the same reason with SIM_array_comp_base_cap */
+static double SIM_array_comp_match_cap( unsigned n_bits )
+{
+ return ( n_bits * ( SIM_power_draincap( Wcompn, NCH, 1 ) + SIM_power_draincap( Wcompn, NCH, 2 )));
+}
+
+
+/* upon mismatch, select signal 1->0, then 0->1 on next precharging, so no 1/2 */
+static double SIM_array_comp_mismatch_cap( unsigned n_pre )
+{
+ double Ctotal;
+
+ /* part 1: drain cap of precharge tx */
+ Ctotal = n_pre * SIM_power_draincap( Wcomppreequ, PCH, 1 );
+
+ /* part 2: nor gate of valid output */
+ Ctotal += SIM_power_gatecap( WdecNORn, 1 ) + SIM_power_gatecap( WdecNORp, 3 );
+
+ return Ctotal;
+}
+
+
+/* upon miss, valid output switches twice in one cycle, so no 1/2 */
+static double SIM_array_comp_miss_cap( unsigned assoc )
+{
+ /* drain cap of valid output */
+ return ( assoc * SIM_power_draincap( WdecNORn, NCH, 1 ) + SIM_power_draincap( WdecNORp, PCH, assoc ));
+}
+
+
+/* no 1/2 for the same reason as base_cap */
+static double SIM_array_comp_bit_match_cap( void )
+{
+ return ( 2 * ( SIM_power_draincap( Wcompn, NCH, 1 ) + SIM_power_draincap( Wcompn, NCH, 2 )));
+}
+
+
+/* no 1/2 for the same reason as base_cap */
+static double SIM_array_comp_bit_mismatch_cap( void )
+{
+ return ( 3 * SIM_power_draincap( Wcompn, NCH, 1 ) + SIM_power_draincap( Wcompn, NCH, 2 ));
+}
+
+
+/* each addr bit drives 2 nmos pass transistors, so no 1/2 */
+static double SIM_array_comp_chgaddr_cap( void )
+{
+ return ( SIM_power_gatecap( Wcompn, 1 ));
+}
+
+
+static int SIM_array_comp_clear_stat(power_comp *comp)
+{
+ comp->n_access = comp->n_miss = comp->n_chg_addr = comp->n_match = 0;
+ comp->n_mismatch = comp->n_bit_match = comp->n_bit_mismatch = 0;
+
+ return 0;
+}
+
+
+static int SIM_array_comp_init(power_comp *comp, int model, unsigned n_bits, unsigned assoc, unsigned n_pre, double matchline_len, double tagline_len )
+{
+ if ((comp->model = model) && model < COMP_MAX_MODEL) {
+ comp->n_bits = n_bits;
+ comp->assoc = assoc;
+ /* redundant field */
+ comp->comp_mask = HAMM_MASK(n_bits);
+
+ SIM_array_comp_clear_stat(comp);
+
+ switch ( model ) {
+ case CACHE_COMPONENT:
+ comp->e_access = SIM_array_comp_base_cap() * EnergyFactor;
+ comp->e_match = SIM_array_comp_match_cap( n_bits ) * EnergyFactor;
+ comp->e_mismatch = SIM_array_comp_mismatch_cap( n_pre ) * EnergyFactor;
+ comp->e_miss = SIM_array_comp_miss_cap( assoc ) * EnergyFactor;
+ comp->e_bit_match = SIM_array_comp_bit_match_cap() * EnergyFactor;
+ comp->e_bit_mismatch = SIM_array_comp_bit_mismatch_cap() * EnergyFactor;
+ comp->e_chg_addr = SIM_array_comp_chgaddr_cap() * EnergyFactor;
+ break;
+
+ case CAM_COMP:
+ comp->e_access = comp->e_match = comp->e_chg_addr = 0;
+ comp->e_bit_match = comp->e_bit_mismatch = 0;
+ /* energy consumption of tagline */
+ comp->e_chg_addr = SIM_cam_comp_tagline_cap( assoc, tagline_len ) * EnergyFactor;
+ comp->e_mismatch = SIM_cam_comp_mismatch_cap( n_bits, n_pre, matchline_len ) * EnergyFactor;
+ comp->e_miss = SIM_cam_comp_miss_cap( assoc ) * EnergyFactor;
+ break;
+
+ default: break;/* some error handler */
+ }
+
+ return 0;
+ }
+ else
+ return -1;
+}
+
+
+int SIM_array_comp_global_record(power_comp *comp, unsigned long int prev_value, unsigned long int curr_value, int miss )
+{
+ if ( miss ) comp->n_miss ++;
+
+ switch ( comp->model ) {
+ case CACHE_COMPONENT:
+ comp->n_access ++;
+ comp->n_chg_addr += SIM_power_Hamming( prev_value, curr_value, comp->comp_mask ) * comp->assoc;
+ break;
+
+ case CAM_COMP:
+ comp->n_chg_addr += SIM_power_Hamming( prev_value, curr_value, comp->comp_mask );
+ break;
+
+ default: break;/* some error handler */
+ }
+
+ return 0;
+}
+
+
+/* recover means prev_tag will recover on next cycle, e.g. driven by sense amplifier */
+/* return value: 1 if miss, 0 if hit */
+int SIM_array_comp_local_record(power_comp *comp, unsigned long int prev_tag, unsigned long int curr_tag, unsigned long int input, int recover )
+{
+ unsigned H_dist;
+ int mismatch;
+
+ if ( mismatch = ( curr_tag != input )) comp->n_mismatch ++;
+
+ /* for cam, input changes are reflected in memory cells */
+ if ( comp->model == CACHE_COMPONENT ) {
+ if ( recover )
+ comp->n_chg_addr += 2 * SIM_power_Hamming( prev_tag, curr_tag, comp->comp_mask );
+ else
+ comp->n_chg_addr += SIM_power_Hamming( prev_tag, curr_tag, comp->comp_mask );
+
+ if ( mismatch ) {
+ H_dist = SIM_power_Hamming( curr_tag, input, comp->comp_mask );
+ comp->n_bit_mismatch += H_dist;
+ comp->n_bit_match += comp->n_bits - H_dist;
+ }
+ else comp->n_match ++;
+ }
+
+ return mismatch;
+}
+
+
+double SIM_array_comp_report(power_comp *comp )
+{
+ return ( comp->n_access * comp->e_access + comp->n_match * comp->e_match +
+ comp->n_mismatch * comp->e_mismatch + comp->n_miss * comp->e_miss +
+ comp->n_bit_match * comp->e_bit_match + comp->n_chg_addr * comp->e_chg_addr +
+ comp->n_bit_mismatch * comp->e_bit_mismatch );
+}
+
+// ------- Tag comparator end
+
+
+
+// ------- Multiplexor begin
+
+/* upon mismatch, 1 output of nor gates 1->0, then 0->1 on next cycle, so no 1/2 */
+static double SIM_array_mux_mismatch_cap( unsigned n_nor_gates )
+{
+ double Cmul;
+
+ /* stage 1: inverter */
+ Cmul = SIM_power_draincap( Wmuxdrv12n, NCH, 1 ) + SIM_power_draincap( Wmuxdrv12p, PCH, 1 ) +
+ SIM_power_gatecap( Wmuxdrv12n, 1 ) + SIM_power_gatecap( Wmuxdrv12p, 1 );
+
+ /* stage 2: nor gates */
+ /* gate cap of nor gates */
+ Cmul += n_nor_gates * ( SIM_power_gatecap( WmuxdrvNORn, 1 ) + SIM_power_gatecap( WmuxdrvNORp, 1 ));
+ /* drain cap of nor gates, only count 1 */
+ Cmul += SIM_power_draincap( WmuxdrvNORp, PCH, 2 ) + 2 * SIM_power_draincap( WmuxdrvNORn, NCH, 1 );
+
+ /* stage 3: output inverter */
+ Cmul += SIM_power_gatecap( Wmuxdrv3n, 1 ) + SIM_power_gatecap( Wmuxdrv3p, 1 ) +
+ SIM_power_draincap( Wmuxdrv3n, NCH, 1 ) + SIM_power_draincap( Wmuxdrv3p, PCH, 1 );
+
+ return Cmul;
+}
+
+
+/* 2 nor gates switch gate signals, so no 1/2 */
+/* WHS: assume address changes won't propagate until matched or mismatched */
+static double SIM_array_mux_chgaddr_cap( void )
+{
+ return ( SIM_power_gatecap( WmuxdrvNORn, 1 ) + SIM_power_gatecap( WmuxdrvNORp, 1 ));
+}
+
+
+static int SIM_array_mux_clear_stat(power_mux *mux)
+{
+ mux->n_mismatch = mux->n_chg_addr = 0;
+
+ return 0;
+}
+
+
+static int SIM_array_mux_init(power_mux *mux, int model, unsigned n_gates, unsigned assoc )
+{
+ if ((mux->model = model) && model < MUX_MAX_MODEL) {
+ mux->assoc = assoc;
+
+ SIM_array_mux_clear_stat(mux);
+
+ mux->e_mismatch = SIM_array_mux_mismatch_cap( n_gates ) * EnergyFactor;
+ mux->e_chg_addr = SIM_array_mux_chgaddr_cap() * EnergyFactor;
+
+ return 0;
+ }
+ else
+ return -1;
+}
+
+
+int SIM_array_mux_record(power_mux *mux, unsigned long int prev_addr, unsigned long int curr_addr, int miss )
+{
+ if ( prev_addr != curr_addr )
+ mux->n_chg_addr += mux->assoc;
+
+ if ( miss )
+ mux->n_mismatch += mux->assoc;
+ else
+ mux->n_mismatch += mux->assoc - 1;
+
+ return 0;
+}
+
+
+double SIM_array_mux_report(power_mux *mux )
+{
+ return ( mux->n_mismatch * mux->e_mismatch + mux->n_chg_addr * mux->e_chg_addr );
+}
+
+// ------- Multiplexor end
+
+
+// ------- Output driver begin
+
+/* output driver should be disabled somehow when no access occurs, so no 1/2 */
+static double SIM_array_outdrv_select_cap( unsigned data_width )
+{
+ double Ctotal;
+
+ /* stage 1: inverter */
+ Ctotal = SIM_power_gatecap( Woutdrvseln, 1 ) + SIM_power_gatecap( Woutdrvselp, 1 ) +
+ SIM_power_draincap( Woutdrvseln, NCH, 1 ) + SIM_power_draincap( Woutdrvselp, PCH, 1 );
+
+ /* stage 2: gate cap of nand gate and nor gate */
+ /* only consider 1 gate cap because another and drain cap switch depends on data value */
+ Ctotal += data_width *( SIM_power_gatecap( Woutdrvnandn, 1 ) + SIM_power_gatecap( Woutdrvnandp, 1 ) +
+ SIM_power_gatecap( Woutdrvnorn, 1 ) + SIM_power_gatecap( Woutdrvnorp, 1 ));
+
+ return Ctotal;
+}
+
+
+/* WHS: assume data changes won't propagate until enabled */
+static double SIM_array_outdrv_chgdata_cap( void )
+{
+ return (( SIM_power_gatecap( Woutdrvnandn, 1 ) + SIM_power_gatecap( Woutdrvnandp, 1 ) +
+ SIM_power_gatecap( Woutdrvnorn, 1 ) + SIM_power_gatecap( Woutdrvnorp, 1 )) / 2 );
+}
+
+
+/* no 1/2 for the same reason as outdrv_select_cap */
+static double SIM_array_outdrv_outdata_cap( unsigned value )
+{
+ double Ctotal;
+
+ /* stage 1: drain cap of nand gate or nor gate */
+ if ( value )
+ /* drain cap of nand gate */
+ Ctotal = SIM_power_draincap( Woutdrvnandn, NCH, 2 ) + 2 * SIM_power_draincap( Woutdrvnandp, PCH, 1 );
+ else
+ /* drain cap of nor gate */
+ Ctotal = 2 * SIM_power_draincap( Woutdrvnorn, NCH, 1 ) + SIM_power_draincap( Woutdrvnorp, PCH, 2 );
+
+ /* stage 2: gate cap of output inverter */
+ if ( value )
+ Ctotal += SIM_power_gatecap( Woutdriverp, 1 );
+ else
+ Ctotal += SIM_power_gatecap( Woutdrivern, 1 );
+
+ /* drain cap of output inverter should be included into bus cap */
+ return Ctotal;
+}
+
+
+static int SIM_array_outdrv_clear_stat(power_out *outdrv)
+{
+ outdrv->n_select = outdrv->n_chg_data = 0;
+ outdrv->n_out_0 = outdrv->n_out_1 = 0;
+
+ return 0;
+}
+
+
+static int SIM_array_outdrv_init(power_out *outdrv, int model, unsigned item_width )
+{
+ if ((outdrv->model = model) && model < OUTDRV_MAX_MODEL) {
+ outdrv->item_width = item_width;
+ /* redundant field */
+ outdrv->out_mask = HAMM_MASK(item_width);
+
+ SIM_array_outdrv_clear_stat(outdrv);
+
+ outdrv->e_select = SIM_array_outdrv_select_cap( item_width ) * EnergyFactor;
+ outdrv->e_out_1 = SIM_array_outdrv_outdata_cap( 1 ) * EnergyFactor;
+ outdrv->e_out_0 = SIM_array_outdrv_outdata_cap( 0 ) * EnergyFactor;
+
+ switch ( model ) {
+ case CACHE_OUTDRV:
+ outdrv->e_chg_data = SIM_array_outdrv_chgdata_cap() * EnergyFactor;
+ break;
+
+ case CAM_OUTDRV:
+ /* input changes are reflected in memory cells */
+ case REG_OUTDRV:
+ /* input changes are reflected in bitlines */
+ outdrv->e_chg_data = 0;
+ break;
+
+ default: break;/* some error handler */
+ }
+
+ return 0;
+ }
+ else
+ return -1;
+}
+
+
+int SIM_array_outdrv_global_record(power_out *outdrv, unsigned long int data )
+{
+ unsigned n_1;
+
+ outdrv->n_select ++;
+
+ n_1 = SIM_power_Hamming( data, 0, outdrv->out_mask );
+
+ outdrv->n_out_1 += n_1;
+ outdrv->n_out_0 += outdrv->item_width - n_1;
+
+ return 0;
+}
+
+
+/* recover means prev_data will recover on next cycle, e.g. driven by sense amplifier */
+/* NOTE: this function SHOULD not be called by a fully-associative cache */
+int SIM_array_outdrv_local_record(power_out *outdrv, unsigned long int prev_data, unsigned long int curr_data, int recover )
+{
+ if ( recover )
+ outdrv->n_chg_data += 2 * SIM_power_Hamming( prev_data, curr_data, outdrv->out_mask );
+ else
+ outdrv->n_chg_data += SIM_power_Hamming( prev_data, curr_data, outdrv->out_mask );
+
+ return 0;
+}
+
+
+double SIM_array_outdrv_report(power_out *outdrv )
+{
+ return ( outdrv->n_select * outdrv->e_select + outdrv->n_chg_data * outdrv->e_chg_data +
+ outdrv->n_out_1 * outdrv->e_out_1 + outdrv->n_out_0 * outdrv->e_out_0 );
+}
+
+// ------- Output driver end
+
+
+
+// ------- Memcory cell begin
+
+/* WHS: use Wmemcella and Wmemcellbscale to compute tx width of memory cell */
+static double SIM_array_mem_cap( unsigned read_ports, unsigned write_ports, int share_rw, unsigned end )
+{
+ double Ctotal;
+
+ /* part 1: drain capacitance of pass transistors */
+ Ctotal = SIM_power_draincap( Wmemcellr, NCH, 1 ) * read_ports * end / 2;
+ if ( ! share_rw )
+ Ctotal += SIM_power_draincap( Wmemcellw, NCH, 1 ) * write_ports;
+
+ /* has coefficient ( 1/2 * 2 ) */
+ /* part 2: drain capacitance of memory cell */
+ Ctotal += SIM_power_draincap( Wmemcella, NCH, 1 ) + SIM_power_draincap( Wmemcella * Wmemcellbscale, PCH, 1 );
+
+ /* has coefficient ( 1/2 * 2 ) */
+ /* part 3: gate capacitance of memory cell */
+ Ctotal += SIM_power_gatecap( Wmemcella, 1 ) + SIM_power_gatecap( Wmemcella * Wmemcellbscale, 1 );
+
+ return Ctotal;
+}
+
+
+static int SIM_array_mem_clear_stat(power_mem *mem)
+{
+ mem->n_switch = 0;
+
+ return 0;
+}
+
+
+static int SIM_array_mem_init(power_mem *mem, int model, unsigned read_ports, unsigned write_ports, int share_rw, unsigned end )
+{
+ double i_leakage;
+
+ if ((mem->model = model) && model < MEM_MAX_MODEL) {
+ mem->end = end;
+ SIM_array_mem_clear_stat(mem);
+
+ switch ( model ) {
+ case CAM_TAG_RW_MEM:
+ mem->e_switch = SIM_cam_tag_mem_cap( read_ports, write_ports, share_rw, end, SIM_ARRAY_RW ) * EnergyFactor;
+ break;
+
+ /* FIXME: it's only an approximation using CAM_TAG_WO_MEM to emulate CAM_ATTACH_MEM */
+ case CAM_ATTACH_MEM:
+ case CAM_TAG_WO_MEM:
+ mem->e_switch = SIM_cam_tag_mem_cap( read_ports, write_ports, share_rw, end, SIM_ARRAY_WO ) * EnergyFactor;
+ break;
+
+ case CAM_DATA_MEM:
+ mem->e_switch = SIM_cam_data_mem_cap( read_ports, write_ports ) * EnergyFactor;
+ break;
+
+ default: /* NORMAL_MEM */
+ mem->e_switch = SIM_array_mem_cap( read_ports, write_ports, share_rw, end ) * EnergyFactor;
+
+ /* static power */
+ i_leakage = 0;
+ /* memory cell */
+ i_leakage += (Wmemcella * NMOS_TAB[0] + Wmemcella * Wmemcellbscale * PMOS_TAB[0]) * 2;
+ /* read port pass tx */
+ i_leakage += Wmemcellr * NMOS_TAB[0] * end * read_ports;
+ /* write port pass tx */
+ if (! share_rw)
+ i_leakage += Wmemcellw * NMOS_TAB[0] * 2 * write_ports;
+
+ mem->i_leakage = i_leakage / PARM_TECH_POINT * 100;
+ }
+
+ return 0;
+ }
+ else
+ return -1;
+}
+
+
+int SIM_array_mem_record(power_mem *mem, unsigned long int prev_value, unsigned long int curr_value, unsigned width )
+{
+ mem->n_switch += SIM_power_Hamming( prev_value, curr_value, HAMM_MASK(width));
+
+ return 0;
+}
+
+
+double SIM_array_mem_report(power_mem *mem )
+{
+ return ( mem->n_switch * mem->e_switch );
+}
+
+// ------- Memcory cell end
+
+
+
+// ------- Precharge begin
+
+/* consider charge then discharge, so no 1/2 */
+static double SIM_array_pre_cap( double width, double length )
+{
+ return SIM_power_gatecap( width, length );
+}
+
+
+/* return # of precharging gates per column */
+static unsigned n_pre_gate( int model )
+{
+ switch ( model ) {
+ case SINGLE_BITLINE: return 2;
+ case EQU_BITLINE: return 3;
+ case SINGLE_OTHER: return 1;
+ default: break;/* some error handler */
+ }
+
+ return 0;
+}
+
+
+/* return # of precharging drains per line */
+static unsigned n_pre_drain( int model )
+{
+ switch ( model ) {
+ case SINGLE_BITLINE: return 1;
+ case EQU_BITLINE: return 2;
+ case SINGLE_OTHER: return 1;
+ default: break;/* some error handler */
+ }
+
+ return 0;
+}
+
+
+static int SIM_array_pre_clear_stat(power_arr_pre *pre)
+{
+ pre->n_charge = 0;
+
+ return 0;
+}
+
+
+static int SIM_array_pre_init(power_arr_pre *pre, int model, double pre_size )
+{
+ unsigned n_gate;
+
+ n_gate = n_pre_gate(model);
+
+ if ((pre->model = model) && model < PRE_MAX_MODEL) {
+ SIM_array_pre_clear_stat(pre);
+
+ /* WHS: 10 should go to PARM */
+ pre->e_charge = SIM_array_pre_cap( pre_size, 10 ) * n_gate * EnergyFactor;
+
+ /* static power */
+ pre->i_leakage = n_gate * pre_size * PMOS_TAB[0] / PARM_TECH_POINT * 100;
+
+ return 0;
+ }
+ else
+ return -1;
+}
+
+
+int SIM_array_pre_record(power_arr_pre *pre, unsigned long int n_charge )
+{
+ pre->n_charge += n_charge;
+
+ return 0;
+}
+
+
+double SIM_array_pre_report(power_arr_pre *pre )
+{
+ return ( pre->n_charge * pre->e_charge );
+}
+
+// ------- Precharge end
+
+/* ---------- buffer model end ------------ */
+
+
+
+
+
+
+
+
+/***** from SIM_array_internal_m.c *********/
+
+
+/* for now we simply initialize all fields to 0, which should not
+ * add too much error if the program runtime is long enough :) */
+int SIM_array_port_state_init(power_array_info *info, SIM_array_port_state_t *port )
+{
+ //if ( IS_FULLY_ASSOC( info ) || !(info->share_rw))
+ //bzero( port->data_line, port->data_line_size );
+
+ port->tag_line = 0;
+ port->row_addr = 0;
+ port->col_addr = 0;
+ port->tag_addr = 0;
+
+ return 0;
+}
+
+
+int SIM_array_set_state_init( power_array_info *info, SIM_array_set_state_t *set )
+{
+ set->entry = NULL;
+ set->entry_set = NULL;
+
+ if ( IS_FULLY_ASSOC( info )) {
+ set->write_flag = 0;
+ set->write_back_flag = 0;
+ }
+
+ /* no default value for other fields */
+ return 0;
+}
+
+
+/* record row decoder and wordline activity */
+/* only used by non-fully-associative array, but we check it anyway */
+int SIM_power_array_dec( power_array_info *info, power_array *arr, SIM_array_port_state_t *port, unsigned long int row_addr, int rw )
+{
+ if ( ! IS_FULLY_ASSOC( info )) {
+ /* record row decoder stats */
+ if (info->row_dec_model) {
+ SIM_array_dec_record( &arr->row_dec, port->row_addr, row_addr );
+
+ /* update state */
+ port->row_addr = row_addr;
+ }
+
+ /* record wordline stats */
+ SIM_array_wordline_record( &arr->data_wordline, rw, info->data_ndwl );
+ if ( HAVE_TAG( info ))
+ SIM_array_wordline_record( &arr->tag_wordline, rw, info->tag_ndwl );
+
+ return 0;
+ }
+ else
+ return -1;
+}
+
+
+/* record read data activity (including bitline and sense amplifier) */
+/* only used by non-fully-associative array, but we check it anyway */
+/* data only used by RF array */
+int SIM_power_array_data_read( power_array_info *info, power_array *arr, unsigned long int data )
+{
+ if (info->data_end == 1) {
+ SIM_array_bitline_record( &arr->data_bitline, SIM_ARRAY_READ, info->eff_data_cols, 0, data );
+
+ return 0;
+ }
+ else if ( ! IS_FULLY_ASSOC( info )) {
+ SIM_array_bitline_record( &arr->data_bitline, SIM_ARRAY_READ, info->eff_data_cols, 0, 0 );
+ SIM_array_amp_record( &arr->data_amp, info->eff_data_cols );
+
+ return 0;
+ }
+ else
+ return -1;
+}
+
+
+/* record write data bitline and memory cell activity */
+/* assume no alignment restriction on write, so (char *) */
+/* set only used by fully-associative array */
+/* data_line only used by fully-associative or RF array */
+int SIM_power_array_data_write( power_array_info *info, power_array *arr, SIM_array_set_state_t *set, unsigned n_item, char *data_line, char *old_data, char *new_data )
+{
+ unsigned i;
+
+ /* record bitline stats */
+ if ( IS_FULLY_ASSOC( info )) {
+ /* wordline should be driven only once */
+ if ( ! set->write_flag ) {
+ SIM_array_wordline_record( &arr->data_wordline, SIM_ARRAY_WRITE, 1 );
+ set->write_flag = 1;
+ }
+
+ /* for fully-associative array, data bank has no read
+ * bitlines, so bitlines not written have no activity */
+ for ( i = 0; i < n_item; i ++ ) {
+ SIM_array_bitline_record( &arr->data_bitline, SIM_ARRAY_WRITE, 8, data_line[i], new_data[i] );
+ /* update state */
+ data_line[i] = new_data[i];
+ }
+ }
+ else if (info->share_rw) {
+ /* there is some subtlety here: write width may not be as wide as block size,
+ * bitlines not written are actually read, but column selector should be off,
+ * so read energy per bitline is the same as write energy per bitline */
+ SIM_array_bitline_record( &arr->data_bitline, SIM_ARRAY_WRITE, info->eff_data_cols, 0, 0 );
+
+ /* write in all sub-arrays if direct-mapped, which implies 1 cycle write latency,
+ * in those sub-arrays wordlines are not driven, so only n items columns switch */
+ if ( IS_DIRECT_MAP( info ) && info->data_ndbl > 1 )
+ SIM_array_bitline_record( &arr->data_bitline, SIM_ARRAY_WRITE, n_item * 8 * ( info->data_ndbl - 1 ), 0, 0 );
+ }
+ else { /* separate R/W bitlines */
+ /* same arguments as in the previous case apply here, except that when we say
+ * read_energy = write_energy, we omit the energy of write driver gate cap */
+ for ( i = 0; i < n_item; i ++ ) {
+ SIM_array_bitline_record( &arr->data_bitline, SIM_ARRAY_WRITE, 8, data_line[i], new_data[i] );
+ /* update state */
+ data_line[i] = new_data[i];
+ }
+ }
+
+ /* record memory cell stats */
+ for ( i = 0; i < n_item; i ++ )
+ SIM_array_mem_record( &arr->data_mem, old_data[i], new_data[i], 8 );
+
+ return 0;
+}
+
+
+/* record read tag activity (including bitline and sense amplifier) */
+/* only used by non-RF array */
+/* set only used by fully-associative array */
+int SIM_power_array_tag_read( power_array_info *info, power_array *arr, SIM_array_set_state_t *set )
+{
+ if ( IS_FULLY_ASSOC( info )) {
+ /* the only reason to read a fully-associative array tag is writing back */
+ SIM_array_wordline_record( &arr->tag_wordline, SIM_ARRAY_READ, 1 );
+ set->write_back_flag = 1;
+ }
+
+ SIM_array_bitline_record( &arr->tag_bitline, SIM_ARRAY_READ, info->eff_tag_cols, 0, 0 );
+ SIM_array_amp_record( &arr->tag_amp, info->eff_tag_cols );
+
+ return 0;
+}
+
+
+/* record write tag bitline and memory cell activity */
+/* WHS: assume update of use bit, valid bit, dirty bit and tag will be coalesced */
+/* only used by non-RF array */
+/* port only used by fully-associative array */
+//int SIM_power_array_tag_update( power_array_info *info, power_array *arr, SIM_array_port_state_t *port, SIM_array_set_state_t *set )
+//{
+ //unsigned i;
+ //unsigned long int curr_tag;
+ //power_mem *tag_attach_mem;
+
+ /* get current tag */
+ //if ( set->entry )
+ //curr_tag = (*info->get_entry_tag)( set->entry );
+
+ // if ( IS_FULLY_ASSOC( info ))
+ // tag_attach_mem = &arr->tag_attach_mem;
+ //else
+ //tag_attach_mem = &arr->tag_mem;
+
+ /* record tag bitline stats */
+ //if ( IS_FULLY_ASSOC( info )) {
+ // if ( set->entry && curr_tag != set->tag_bak ) {
+ // /* shared wordline should be driven only once */
+ // if ( ! set->write_back_flag )
+ // SIM_array_wordline_record( &arr->tag_wordline, SIM_ARRAY_WRITE, 1 );
+
+ /* WHS: value of tag_line doesn't matter if not write_through */
+ //SIM_array_bitline_record( &arr->tag_bitline, SIM_ARRAY_WRITE, info->eff_tag_cols, port->tag_line, curr_tag );
+ /* update state */
+ //if ( IS_WRITE_THROUGH( info ))
+ // port->tag_line = curr_tag;
+ //}
+ //}
+ //else {
+ /* tag update cannot occur at the 1st cycle, so no other sub-arrays */
+ // SIM_array_bitline_record( &arr->tag_bitline, SIM_ARRAY_WRITE, info->eff_tag_cols, 0, 0 );
+ //}
+
+ /* record tag memory cell stats */
+ //if ( HAVE_USE_BIT( info ))
+ // for ( i = 0; i < info->assoc; i ++ )
+ // SIM_array_mem_record( tag_attach_mem, set->use_bak[i], (*info->get_set_use_bit)( set->entry_set, i ), info->use_bit_width );
+
+ //if ( set->entry ) {
+ // SIM_array_mem_record( tag_attach_mem, set->valid_bak, (*info->get_entry_valid_bit)( set->entry ), info->valid_bit_width );
+ //SIM_array_mem_record( &arr->tag_mem, set->tag_bak, curr_tag, info->tag_addr_width );
+
+ //if ( IS_WRITE_BACK( info ))
+ // SIM_array_mem_record( tag_attach_mem, set->dirty_bak, (*info->get_entry_dirty_bit)( set->entry ), 1 );
+ //}
+
+ //return 0;
+//}
+
+
+/* record tag compare activity (including tag comparator, column decoder and multiplexor) */
+/* NOTE: this function may be called twice during ONE array operation, remember to update
+ * states at the end so that call to *_record won't add erroneous extra energy */
+/* only used by non-RF array */
+//int SIM_power_array_tag_compare( power_array_info *info, power_array *arr, SIM_array_port_state_t *port, unsigned long int tag_input, unsigned long int col_addr, SIM_array_set_state_t *set )
+//{
+ //int miss = 0;
+ //unsigned i;
+
+ /* record tag comparator stats */
+ //for ( i = 0; i < info->assoc; i ++ ) {
+ /* WHS: sense amplifiers output 0 when idle */
+ //if ( SIM_array_comp_local_record( &arr->comp, 0, (*info->get_set_tag)( set->entry_set, i ), tag_input, SIM_ARRAY_RECOVER ))
+ // miss = 1;
+ //}
+
+ //SIM_array_comp_global_record( &arr->comp, port->tag_addr, tag_input, miss );
+
+ /* record column decoder stats */
+ //if ( HAVE_COL_DEC( info ))
+ //SIM_array_dec_record( &arr->col_dec, port->col_addr, col_addr );
+
+ /* record multiplexor stats */
+ //if ( HAVE_COL_MUX( info ))
+ //SIM_array_mux_record( &arr->mux, port->col_addr, col_addr, miss );
+
+ /* update state */
+ //port->tag_addr = tag_input;
+ //if ( HAVE_COL_DEC( info ))
+ //port->col_addr = col_addr;
+
+ //return 0;
+//}
+
+
+/* record output driver activity */
+/* assume alignment restriction on read, so specify data_size */
+/* WHS: it's really a mess to use data_size to specify data type */
+/* data_all only used by non-RF and non-fully-associative array */
+/* WHS: don't support 128-bit or wider integer */
+//int SIM_power_array_output( power_array_info *info, power_array *arr, unsigned data_size, unsigned length, void *data_out, void *data_all )
+//{
+ // unsigned i, j;
+
+ /* record output driver stats */
+ //for ( i = 0; i < length; i ++ ) {
+ // switch ( data_size ) {
+ // case 1: SIM_array_outdrv_global_record( &arr->outdrv, ((unsigned8_t *)data_out)[i] );
+ // break;
+ //case 2: SIM_array_outdrv_global_record( &arr->outdrv, ((unsigned16_t *)data_out)[i] );
+ // break;
+ //case 4: SIM_array_outdrv_global_record( &arr->outdrv, ((unsigned32_t *)data_out)[i] );
+ // break;
+ //case 8: SIM_array_outdrv_global_record( &arr->outdrv, ((unsigned64_t *)data_out)[i] );
+ // break;
+ //default: /* some error handler */
+ //}
+ //}
+
+ //if ( ! IS_FULLY_ASSOC( info )) {
+ //for ( i = 0; i < info->assoc; i ++ )
+ //for ( j = 0; j < info->n_item; j ++ )
+ /* sense amplifiers output 0 when idle */
+ //switch ( data_size ) {
+ //case 1: SIM_array_outdrv_local_record( &arr->outdrv, 0, ((unsigned8_t **)data_all)[i][j], SIM_ARRAY_RECOVER );
+ //break;
+ //case 2: SIM_array_outdrv_local_record( &arr->outdrv, 0, ((unsigned16_t **)data_all)[i][j], SIM_ARRAY_RECOVER );
+ //break;
+ //case 4: SIM_array_outdrv_local_record( &arr->outdrv, 0, ((unsigned32_t **)data_all)[i][j], SIM_ARRAY_RECOVER );
+ //break;
+ //case 8: SIM_array_outdrv_local_record( &arr->outdrv, 0, ((unsigned64_t **)data_all)[i][j], SIM_ARRAY_RECOVER );
+ //break;
+ //default: /* some error handler */
+ //}
+ //}
+
+ //return 0;
+//}
+
+
+/********* end from SIM_array_internal_m.c **********/
+
+
+// ------- Array init
+
+
+int power_array_init(power_array_info *info, power_array *arr )
+{
+ unsigned rows, cols, ports, dec_width, n_bitline_pre, n_colsel_pre;
+ double wordline_len, bitline_len, tagline_len, matchline_len;
+ double wordline_cmetal, bitline_cmetal;
+ double Cline, pre_size, comp_pre_size;
+
+ arr->i_leakage = 0;
+
+ /* sanity check */
+ if ( info->read_ports == 0 ) info->share_rw = 0;
+ if ( info->share_rw ) { //AMIT are read and write ports shared?
+ info->data_end = 2;
+ info->tag_end = 2;
+ }
+
+ if ( info->share_rw ) ports = info->read_ports;
+ else ports = info->read_ports + info->write_ports;
+
+ /* data array unit length wire cap */
+ if (ports > 1) {
+ /* 3x minimal spacing */
+ wordline_cmetal = CC3M3metal;
+ bitline_cmetal = CC3M2metal;
+ }
+ else if (info->data_end == 2) {
+ /* wordline infinite spacing, bitline 3x minimal spacing */
+ wordline_cmetal = CM3metal;
+ bitline_cmetal = CC3M2metal;
+ }
+ else {
+ /* both infinite spacing */
+ wordline_cmetal = CM3metal;
+ bitline_cmetal = CM2metal;
+ }
+
+ info->data_arr_width = 0;
+ info->tag_arr_width = 0;
+ info->data_arr_height = 0;
+ info->tag_arr_height = 0;
+
+ /* BEGIN: data array power initialization */
+ if (dec_width = SIM_power_logtwo(info->n_set)) { //AMIT: not fully associative, n->sets!=1
+ /* row decoder power initialization */
+ SIM_array_dec_init( &arr->row_dec, info->row_dec_model, dec_width );
+
+ /* row decoder precharging power initialization */
+ //if ( is_dynamic_dec( info->row_dec_model ))
+ /* FIXME: need real pre_size */
+ //SIM_array_pre_init( &arr->row_dec_pre, info->row_dec_pre_model, 0 );
+
+ rows = info->n_set / info->data_ndbl / info->data_nspd; //AMIT: n_set is the number of sets(fully associative n_sets=1)
+ cols = info->blk_bits * info->assoc * info->data_nspd / info->data_ndwl; //AMIT: blk_bits is the line size
+
+ bitline_len = rows * ( RegCellHeight + ports * WordlineSpacing );
+ if ( info->data_end == 2 )
+ wordline_len = cols * ( RegCellWidth + 2 * ports * BitlineSpacing );
+ else /* info->data_end == 1 */
+ wordline_len = cols * ( RegCellWidth + ( 2 * ports - info->read_ports ) * BitlineSpacing );
+ info->data_arr_width = wordline_len;
+ info->data_arr_height = bitline_len;
+
+ /* compute precharging size */
+ /* FIXME: should consider n_pre and pre_size simultaneously */
+ Cline = rows * SIM_power_draincap( Wmemcellr, NCH, 1 ) + bitline_cmetal * bitline_len;
+ pre_size = SIM_power_driver_size( Cline, Period / 8 );
+ /* WHS: ?? compensate for not having an nmos pre-charging */
+ pre_size += pre_size * Wdecinvn / Wdecinvp;
+
+ /* bitline power initialization */
+ n_bitline_pre = n_pre_drain( info->data_bitline_pre_model );
+ n_colsel_pre = ( info->data_n_share_amp > 1 ) ? n_pre_drain( info->data_colsel_pre_model ) : 0;
+ SIM_array_bitline_init(&arr->data_bitline, info->data_bitline_model, info->share_rw, info->data_end, rows, bitline_len * bitline_cmetal, info->data_n_share_amp, n_bitline_pre, n_colsel_pre, pre_size, info->outdrv_model);
+ /* static power */
+ arr->i_leakage += arr->data_bitline.i_leakage * cols * info->write_ports;
+
+ /* bitline precharging power initialization */
+ SIM_array_pre_init( &arr->data_bitline_pre, info->data_bitline_pre_model, pre_size );
+ /* static power */
+ arr->i_leakage += arr->data_bitline_pre.i_leakage * cols * info->read_ports;
+ /* bitline column selector precharging power initialization */
+ if ( info->data_n_share_amp > 1 )
+ SIM_array_pre_init( &arr->data_colsel_pre, info->data_colsel_pre_model, pre_size );
+
+ /* sense amplifier power initialization */
+ SIM_array_amp_init( &arr->data_amp, info->data_amp_model );
+ }
+ else {
+ /* info->n_set == 1 means this array is fully-associative */
+ rows = info->assoc;
+ cols = info->blk_bits;
+
+ /* WHS: no read wordlines or bitlines */
+ bitline_len = rows * ( RegCellHeight + info->write_ports * WordlineSpacing );
+ wordline_len = cols * ( RegCellWidth + 2 * info->write_ports * BitlineSpacing );
+ info->data_arr_width = wordline_len;
+ info->data_arr_height = bitline_len;
+
+ /* bitline power initialization */
+ SIM_array_bitline_init(&arr->data_bitline, info->data_bitline_model, 0, info->data_end, rows, bitline_len * bitline_cmetal, 1, 0, 0, 0, info->outdrv_model);
+ }
+
+ /* wordline power initialization */
+ SIM_array_wordline_init( &arr->data_wordline, info->data_wordline_model, info->share_rw, cols, wordline_len * wordline_cmetal, info->data_end );
+ /* static power */
+ arr->i_leakage += arr->data_wordline.i_leakage * rows * ports;
+
+ if (dec_width = SIM_power_logtwo(info->n_item)) {
+ /* multiplexor power initialization */
+ SIM_array_mux_init( &arr->mux, info->mux_model, info->n_item, info->assoc );
+
+ /* column decoder power initialization */
+ SIM_array_dec_init( &arr->col_dec, info->col_dec_model, dec_width );
+
+ /* column decoder precharging power initialization */
+ //if ( is_dynamic_dec( info->col_dec_model ))
+ /* FIXME: need real pre_size */
+ //SIM_array_pre_init( &arr->col_dec_pre, info->col_dec_pre_model, 0 );
+ }
+
+ /* memory cell power initialization */
+ SIM_array_mem_init( &arr->data_mem, info->data_mem_model, info->read_ports, info->write_ports, info->share_rw, info->data_end );
+ /* static power */
+ arr->i_leakage += arr->data_mem.i_leakage * rows * cols;
+
+ /* output driver power initialization */
+ SIM_array_outdrv_init( &arr->outdrv, info->outdrv_model, info->data_width );
+ /* END: data array power initialization */
+
+
+ /* BEGIN: tag array power initialization */
+ /* assume a tag array must have memory cells */
+ if ( info->tag_mem_model ) {
+ if ( info->n_set > 1 ) {
+ /* tag array unit length wire cap */
+ if (ports > 1) {
+ /* 3x minimal spacing */
+ wordline_cmetal = CC3M3metal;
+ bitline_cmetal = CC3M2metal;
+ }
+ else if (info->data_end == 2) {
+ /* wordline infinite spacing, bitline 3x minimal spacing */
+ wordline_cmetal = CM3metal;
+ bitline_cmetal = CC3M2metal;
+ }
+ else {
+ /* both infinite spacing */
+ wordline_cmetal = CM3metal;
+ bitline_cmetal = CM2metal;
+ }
+
+ rows = info->n_set / info->tag_ndbl / info->tag_nspd;
+ cols = info->tag_line_width * info->assoc * info->tag_nspd / info->tag_ndwl;
+
+ bitline_len = rows * ( RegCellHeight + ports * WordlineSpacing );
+ if ( info->tag_end == 2 )
+ wordline_len = cols * ( RegCellWidth + 2 * ports * BitlineSpacing );
+ else /* info->tag_end == 1 */
+ wordline_len = cols * ( RegCellWidth + ( 2 * ports - info->read_ports ) * BitlineSpacing );
+ info->tag_arr_width = wordline_len;
+ info->tag_arr_height = bitline_len;
+
+ /* compute precharging size */
+ /* FIXME: should consider n_pre and pre_size simultaneously */
+ Cline = rows * SIM_power_draincap( Wmemcellr, NCH, 1 ) + bitline_cmetal * bitline_len;
+ pre_size = SIM_power_driver_size( Cline, Period / 8 );
+ /* WHS: ?? compensate for not having an nmos pre-charging */
+ pre_size += pre_size * Wdecinvn / Wdecinvp;
+
+ /* bitline power initialization */
+ n_bitline_pre = n_pre_drain( info->tag_bitline_pre_model );
+ n_colsel_pre = ( info->tag_n_share_amp > 1 ) ? n_pre_drain( info->tag_colsel_pre_model ) : 0;
+ SIM_array_bitline_init(&arr->tag_bitline, info->tag_bitline_model, info->share_rw, info->tag_end, rows, bitline_len * bitline_cmetal, info->tag_n_share_amp, n_bitline_pre, n_colsel_pre, pre_size, SIM_NO_MODEL);
+
+ /* bitline precharging power initialization */
+ SIM_array_pre_init( &arr->tag_bitline_pre, info->tag_bitline_pre_model, pre_size );
+ /* bitline column selector precharging power initialization */
+ if ( info->tag_n_share_amp > 1 )
+ SIM_array_pre_init( &arr->tag_colsel_pre, info->tag_colsel_pre_model, pre_size );
+
+ /* sense amplifier power initialization */
+ SIM_array_amp_init( &arr->tag_amp, info->tag_amp_model );
+
+ /* prepare for comparator initialization */
+ tagline_len = matchline_len = 0;
+ comp_pre_size = Wcomppreequ;
+ }
+ else { /* info->n_set == 1 */
+ /* cam cells are big enough, so infinite spacing */
+ wordline_cmetal = CM3metal;
+ bitline_cmetal = CM2metal;
+
+ rows = info->assoc;
+ /* FIXME: operations of valid bit, use bit and dirty bit are not modeled */
+ cols = info->tag_addr_width;
+
+ bitline_len = rows * ( CamCellHeight + ports * WordlineSpacing + info->read_ports * MatchlineSpacing );
+ if ( info->tag_end == 2 )
+ wordline_len = cols * ( CamCellWidth + 2 * ports * BitlineSpacing + 2 * info->read_ports * TaglineSpacing );
+ else /* info->tag_end == 1 */
+ wordline_len = cols * ( CamCellWidth + ( 2 * ports - info->read_ports ) * BitlineSpacing + 2 * info->read_ports * TaglineSpacing );
+ info->tag_arr_width = wordline_len;
+ info->tag_arr_height = bitline_len;
+
+ if ( is_rw_bitline ( info->tag_bitline_model )) {
+ /* compute precharging size */
+ /* FIXME: should consider n_pre and pre_size simultaneously */
+ Cline = rows * SIM_power_draincap( Wmemcellr, NCH, 1 ) + bitline_cmetal * bitline_len;
+ pre_size = SIM_power_driver_size( Cline, Period / 8 );
+ /* WHS: ?? compensate for not having an nmos pre-charging */
+ pre_size += pre_size * Wdecinvn / Wdecinvp;
+
+ /* bitline power initialization */
+ n_bitline_pre = n_pre_drain( info->tag_bitline_pre_model );
+ SIM_array_bitline_init(&arr->tag_bitline, info->tag_bitline_model, info->share_rw, info->tag_end, rows, bitline_len * bitline_cmetal, 1, n_bitline_pre, 0, pre_size, SIM_NO_MODEL);
+
+ /* bitline precharging power initialization */
+ SIM_array_pre_init( &arr->tag_bitline_pre, info->tag_bitline_pre_model, pre_size );
+
+ /* sense amplifier power initialization */
+ SIM_array_amp_init( &arr->tag_amp, info->tag_amp_model );
+ }
+ else {
+ /* bitline power initialization */
+ SIM_array_bitline_init(&arr->tag_bitline, info->tag_bitline_model, 0, info->tag_end, rows, bitline_len * bitline_cmetal, 1, 0, 0, 0, SIM_NO_MODEL);
+ }
+
+ /* memory cell power initialization */
+ SIM_array_mem_init( &arr->tag_attach_mem, info->tag_attach_mem_model, info->read_ports, info->write_ports, info->share_rw, info->tag_end );
+
+ /* prepare for comparator initialization */
+ tagline_len = bitline_len;
+ matchline_len = wordline_len;
+ comp_pre_size = Wmatchpchg;
+ }
+
+ /* wordline power initialization */
+ SIM_array_wordline_init( &arr->tag_wordline, info->tag_wordline_model, info->share_rw, cols, wordline_len * wordline_cmetal, info->tag_end );
+
+ /* comparator power initialization */
+ SIM_array_comp_init( &arr->comp, info->comp_model, info->tag_addr_width, info->assoc, n_pre_drain( info->comp_pre_model ), matchline_len, tagline_len );
+
+ /* comparator precharging power initialization */
+ SIM_array_pre_init( &arr->comp_pre, info->comp_pre_model, comp_pre_size );
+
+ /* memory cell power initialization */
+ SIM_array_mem_init( &arr->tag_mem, info->tag_mem_model, info->read_ports, info->write_ports, info->share_rw, info->tag_end );
+ }
+ /* END: tag array power initialization */
+
+ return 0;
+}
+
+double array_report(power_array_info *info, power_array *arr)
+{
+ double epart, etotal = 0;
+
+ if (info->row_dec_model) {
+ epart = SIM_array_dec_report(&arr->row_dec);
+ //fprintf(stderr, "row decoder: %g\n", epart);
+ etotal += epart;
+ }
+ if (info->col_dec_model) {
+ epart = SIM_array_dec_report(&arr->col_dec);
+ //fprintf(stderr, "col decoder: %g\n", epart);
+ etotal += epart;
+ }
+ if (info->data_wordline_model) {
+ epart = SIM_array_wordline_report(&arr->data_wordline);
+ //fprintf(stderr, "data wordline: %g\n", epart);
+ etotal += epart;
+ }
+ if (info->tag_wordline_model) {
+ epart = SIM_array_wordline_report(&arr->tag_wordline);
+ //fprintf(stderr, "tag wordline: %g\n", epart);
+ etotal += epart;
+ }
+ if (info->data_bitline_model) {
+ epart = SIM_array_bitline_report(&arr->data_bitline);
+ //fprintf(stderr, "data bitline: %g\n", epart);
+ etotal += epart;
+ }
+ if (info->data_bitline_pre_model) {
+ epart = SIM_array_pre_report(&arr->data_bitline_pre);
+ //fprintf(stderr, "data bitline precharge: %g\n", epart);
+ etotal += epart;
+ }
+ if (info->tag_bitline_model) {
+ epart = SIM_array_bitline_report(&arr->tag_bitline);
+ //fprintf(stderr, "tag bitline: %g\n", epart);
+ etotal += epart;
+ }
+ if (info->data_mem_model) {
+ epart = SIM_array_mem_report(&arr->data_mem);
+ //fprintf(stderr, "data memory: %g\n", epart);
+ etotal += epart;
+ }
+ if (info->tag_mem_model) {
+ epart = SIM_array_mem_report(&arr->tag_mem);
+ //fprintf(stderr, "tag memory: %g\n", epart);
+ etotal += epart;
+ }
+ if (info->data_amp_model) {
+ epart = SIM_array_amp_report(&arr->data_amp);
+ //fprintf(stderr, "data amp: %g\n", epart);
+ etotal += epart;
+ }
+ if (info->tag_amp_model) {
+ epart = SIM_array_amp_report(&arr->tag_amp);
+ //fprintf(stderr, "tag amp: %g\n", epart);
+ etotal += epart;
+ }
+ if (info->comp_model) {
+ epart = SIM_array_comp_report(&arr->comp);
+ //fprintf(stderr, "comparator: %g\n", epart);
+ etotal += epart;
+ }
+ if (info->mux_model) {
+ epart = SIM_array_mux_report(&arr->mux);
+ //fprintf(stderr, "multiplexor: %g\n", epart);
+ etotal += epart;
+ }
+ if (info->outdrv_model) {
+ epart = SIM_array_outdrv_report(&arr->outdrv);
+ //fprintf(stderr, "output driver: %g\n", epart);
+ etotal += epart;
+ }
+ /* ignore other precharging for now */
+
+ //fprintf(stderr, "total energy: %g\n", etotal);
+
+ return etotal;
+}
+
+/* ==================== buffer (wrapper/record functions) ==================== */
+
+/* record read data activity */
+int SIM_buf_power_data_read(power_array_info *info, power_array *arr, unsigned long int data)
+{
+ /* precharge */
+ SIM_array_pre_record(&arr->data_bitline_pre, info->blk_bits);
+ /* drive the wordline */
+ SIM_power_array_dec(info, arr, NULL, 0, SIM_ARRAY_READ);
+ /* read data */
+ SIM_power_array_data_read(info, arr, data);
+
+ return 0;
+}
+
+
+/* record write data bitline and memory cell activity */
+int SIM_buf_power_data_write(power_array_info *info, power_array *arr, char *data_line, char *old_data, char *new_data)
+{
+#define N_ITEM (PARM_flit_width / 8 + (PARM_flit_width % 8 ? 1:0))
+ /* drive the wordline */
+ SIM_power_array_dec(info, arr, NULL, 0, SIM_ARRAY_WRITE);
+ /* write data */
+ SIM_power_array_data_write(info, arr, NULL, N_ITEM, data_line, old_data, new_data);
+
+ return 0;
+}
+
+/* WHS: missing data output wrapper function */
+
+/* ==================== buffer (wrapper/record functions) end ==================== */
+
+
+
+
+
+int SIM_array_clear_stat(power_array *arr)
+{
+ SIM_array_dec_clear_stat(&arr->row_dec);
+ SIM_array_dec_clear_stat(&arr->col_dec);
+ SIM_array_wordline_clear_stat(&arr->data_wordline);
+ SIM_array_wordline_clear_stat(&arr->tag_wordline);
+ SIM_array_bitline_clear_stat(&arr->data_bitline);
+ SIM_array_bitline_clear_stat(&arr->tag_bitline);
+ SIM_array_mem_clear_stat(&arr->data_mem);
+ SIM_array_mem_clear_stat(&arr->tag_mem);
+ SIM_array_mem_clear_stat(&arr->tag_attach_mem);
+ SIM_array_amp_clear_stat(&arr->data_amp);
+ SIM_array_amp_clear_stat(&arr->tag_amp);
+ SIM_array_comp_clear_stat(&arr->comp);
+ SIM_array_mux_clear_stat(&arr->mux);
+ SIM_array_outdrv_clear_stat(&arr->outdrv);
+ SIM_array_pre_clear_stat(&arr->row_dec_pre);
+ SIM_array_pre_clear_stat(&arr->col_dec_pre);
+ SIM_array_pre_clear_stat(&arr->data_bitline_pre);
+ SIM_array_pre_clear_stat(&arr->tag_bitline_pre);
+ SIM_array_pre_clear_stat(&arr->data_colsel_pre);
+ SIM_array_pre_clear_stat(&arr->tag_colsel_pre);
+ SIM_array_pre_clear_stat(&arr->comp_pre);
+
+ return 0;
+}
+
+
+
+
+