summaryrefslogtreecommitdiff
path: root/src/mem/ruby/network/orion/power_array.cc
diff options
context:
space:
mode:
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;
+}
+
+
+
+
+