diff options
Diffstat (limited to 'src/mem/ruby/network/orion/power_array.cc')
-rw-r--r-- | src/mem/ruby/network/orion/power_array.cc | 2158 |
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; +} + + + + + |