1/*****************************************************************************
2 *                                McPAT/CACTI
3 *                      SOFTWARE LICENSE AGREEMENT
4 *            Copyright 2012 Hewlett-Packard Development Company, L.P.
5 *            Copyright (c) 2010-2013 Advanced Micro Devices, Inc.
6 *                          All Rights Reserved
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met: redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer;
12 * redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution;
15 * neither the name of the copyright holders nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 ***************************************************************************/
32
33
34#include <pthread.h>
35
36#include <algorithm>
37#include <cmath>
38#include <ctime>
39#include <iostream>
40#include <list>
41
42#include "Ucache.h"
43#include "area.h"
44#include "bank.h"
45#include "basic_circuit.h"
46#include "component.h"
47#include "const.h"
48#include "decoder.h"
49#include "parameter.h"
50#include "subarray.h"
51#include "uca.h"
52
53using namespace std;
54
55const uint32_t nthreads = NTHREADS;
56
57
58void min_values_t::update_min_values(const min_values_t * val) {
59    min_delay   = (min_delay > val->min_delay) ? val->min_delay : min_delay;
60    min_dyn     = (min_dyn > val->min_dyn) ? val->min_dyn : min_dyn;
61    min_leakage = (min_leakage > val->min_leakage) ? val->min_leakage : min_leakage;
62    min_area    = (min_area > val->min_area) ? val->min_area : min_area;
63    min_cyc     = (min_cyc > val->min_cyc) ? val->min_cyc : min_cyc;
64}
65
66
67
68void min_values_t::update_min_values(const uca_org_t & res) {
69    min_delay   = (min_delay > res.access_time) ? res.access_time : min_delay;
70    min_dyn     = (min_dyn > res.power.readOp.dynamic) ? res.power.readOp.dynamic : min_dyn;
71    min_leakage = (min_leakage > res.power.readOp.leakage) ? res.power.readOp.leakage : min_leakage;
72    min_area    = (min_area > res.area) ? res.area : min_area;
73    min_cyc     = (min_cyc > res.cycle_time) ? res.cycle_time : min_cyc;
74}
75
76void min_values_t::update_min_values(const nuca_org_t * res) {
77    min_delay   = (min_delay > res->nuca_pda.delay) ? res->nuca_pda.delay : min_delay;
78    min_dyn     = (min_dyn > res->nuca_pda.power.readOp.dynamic) ? res->nuca_pda.power.readOp.dynamic : min_dyn;
79    min_leakage = (min_leakage > res->nuca_pda.power.readOp.leakage) ? res->nuca_pda.power.readOp.leakage : min_leakage;
80    min_area    = (min_area > res->nuca_pda.area.get_area()) ? res->nuca_pda.area.get_area() : min_area;
81    min_cyc     = (min_cyc > res->nuca_pda.cycle_time) ? res->nuca_pda.cycle_time : min_cyc;
82}
83
84void min_values_t::update_min_values(const mem_array * res) {
85    min_delay   = (min_delay > res->access_time) ? res->access_time : min_delay;
86    min_dyn     = (min_dyn > res->power.readOp.dynamic) ? res->power.readOp.dynamic : min_dyn;
87    min_leakage = (min_leakage > res->power.readOp.leakage) ? res->power.readOp.leakage : min_leakage;
88    min_area    = (min_area > res->area) ? res->area : min_area;
89    min_cyc     = (min_cyc > res->cycle_time) ? res->cycle_time : min_cyc;
90}
91
92
93
94void * calc_time_mt_wrapper(void * void_obj) {
95    calc_time_mt_wrapper_struct * calc_obj = (calc_time_mt_wrapper_struct *) void_obj;
96    uint32_t tid                   = calc_obj->tid;
97    list<mem_array *> & data_arr   = calc_obj->data_arr;
98    list<mem_array *> & tag_arr    = calc_obj->tag_arr;
99    bool is_tag                    = calc_obj->is_tag;
100    bool pure_ram                  = calc_obj->pure_ram;
101    bool pure_cam					 = calc_obj->pure_cam;
102    bool is_main_mem               = calc_obj->is_main_mem;
103    double Nspd_min                = calc_obj->Nspd_min;
104    min_values_t * data_res        = calc_obj->data_res;
105    min_values_t * tag_res         = calc_obj->tag_res;
106
107    data_arr.clear();
108    data_arr.push_back(new mem_array);
109    tag_arr.clear();
110    tag_arr.push_back(new mem_array);
111
112    uint32_t Ndwl_niter = _log2(MAXDATAN) + 1;
113    uint32_t Ndbl_niter = _log2(MAXDATAN) + 1;
114    uint32_t Ndcm_niter = _log2(MAX_COL_MUX) + 1;
115    uint32_t niter      = Ndwl_niter * Ndbl_niter * Ndcm_niter;
116
117
118    bool is_valid_partition;
119    int wt_min, wt_max;
120
121    if (g_ip->force_wiretype) {
122        if (g_ip->wt == 0) {
123            wt_min = Low_swing;
124            wt_max = Low_swing;
125        } else {
126            wt_min = Global;
127            wt_max = Low_swing - 1;
128        }
129    } else {
130        wt_min = Global;
131        wt_max = Low_swing;
132    }
133
134    for (double Nspd = Nspd_min; Nspd <= MAXDATASPD; Nspd *= 2) {
135        for (int wr = wt_min; wr <= wt_max; wr++) {
136            for (uint32_t iter = tid; iter < niter; iter += nthreads) {
137                // reconstruct Ndwl, Ndbl, Ndcm
138                unsigned int Ndwl = 1 << (iter / (Ndbl_niter * Ndcm_niter));
139                unsigned int Ndbl = 1 << ((iter / (Ndcm_niter)) % Ndbl_niter);
140                unsigned int Ndcm = 1 << (iter % Ndcm_niter);
141                for (unsigned int Ndsam_lev_1 = 1; Ndsam_lev_1 <= MAX_COL_MUX;
142                     Ndsam_lev_1 *= 2) {
143                    for (unsigned int Ndsam_lev_2 = 1;
144                         Ndsam_lev_2 <= MAX_COL_MUX; Ndsam_lev_2 *= 2) {
145                        //for debuging
146                        if (g_ip->force_cache_config && is_tag == false) {
147                            wr   = g_ip->wt;
148                            Ndwl = g_ip->ndwl;
149                            Ndbl = g_ip->ndbl;
150                            Ndcm = g_ip->ndcm;
151                            if (g_ip->nspd != 0) {
152                                Nspd = g_ip->nspd;
153                            }
154                            if (g_ip->ndsam1 != 0) {
155                                Ndsam_lev_1 = g_ip->ndsam1;
156                                Ndsam_lev_2 = g_ip->ndsam2;
157                            }
158                        }
159
160                        if (is_tag == true) {
161                            is_valid_partition = calculate_time(is_tag, pure_ram, pure_cam, Nspd, Ndwl,
162                                                                Ndbl, Ndcm, Ndsam_lev_1, Ndsam_lev_2,
163                                                                tag_arr.back(), 0, NULL, NULL,
164                                                                is_main_mem);
165                        }
166                        // If it's a fully-associative cache, the data array partition parameters are identical to that of
167                        // the tag array, so compute data array partition properties also here.
168                        if (is_tag == false || g_ip->fully_assoc) {
169                            is_valid_partition = calculate_time(is_tag/*false*/, pure_ram, pure_cam, Nspd, Ndwl,
170                                                                Ndbl, Ndcm, Ndsam_lev_1, Ndsam_lev_2,
171                                                                data_arr.back(), 0, NULL, NULL,
172                                                                is_main_mem);
173                        }
174
175                        if (is_valid_partition) {
176                            if (is_tag == true) {
177                                tag_arr.back()->wt = (enum Wire_type) wr;
178                                tag_res->update_min_values(tag_arr.back());
179                                tag_arr.push_back(new mem_array);
180                            }
181                            if (is_tag == false || g_ip->fully_assoc) {
182                                data_arr.back()->wt = (enum Wire_type) wr;
183                                data_res->update_min_values(data_arr.back());
184                                data_arr.push_back(new mem_array);
185                            }
186                        }
187
188                        if (g_ip->force_cache_config && is_tag == false) {
189                            wr   = wt_max;
190                            iter = niter;
191                            if (g_ip->nspd != 0) {
192                                Nspd = MAXDATASPD;
193                            }
194                            if (g_ip->ndsam1 != 0) {
195                                Ndsam_lev_1 = MAX_COL_MUX + 1;
196                                Ndsam_lev_2 = MAX_COL_MUX + 1;
197                            }
198                        }
199                    }
200                }
201            }
202        }
203    }
204
205    delete data_arr.back();
206    delete tag_arr.back();
207    data_arr.pop_back();
208    tag_arr.pop_back();
209
210#ifndef DEBUG
211    pthread_exit(NULL);
212#else
213    return NULL;
214#endif
215}
216
217
218
219bool calculate_time(
220    bool is_tag,
221    int pure_ram,
222    bool pure_cam,
223    double Nspd,
224    unsigned int Ndwl,
225    unsigned int Ndbl,
226    unsigned int Ndcm,
227    unsigned int Ndsam_lev_1,
228    unsigned int Ndsam_lev_2,
229    mem_array *ptr_array,
230    int flag_results_populate,
231    results_mem_array *ptr_results,
232    uca_org_t *ptr_fin_res,
233    bool is_main_mem) {
234    DynamicParameter dyn_p(is_tag, pure_ram, pure_cam, Nspd, Ndwl, Ndbl, Ndcm, Ndsam_lev_1, Ndsam_lev_2, is_main_mem);
235
236    if (dyn_p.is_valid == false) {
237        return false;
238    }
239
240    UCA * uca = new UCA(dyn_p);
241
242
243    //For the final solution, populate the ptr_results data structure
244    //-- TODO: copy only necessary variables
245    if (flag_results_populate) {
246    } else {
247        int num_act_mats_hor_dir = uca->bank.dp.num_act_mats_hor_dir;
248        int num_mats = uca->bank.dp.num_mats;
249        bool is_fa = uca->bank.dp.fully_assoc;
250        bool pure_cam = uca->bank.dp.pure_cam;
251        ptr_array->Ndwl = Ndwl;
252        ptr_array->Ndbl = Ndbl;
253        ptr_array->Nspd = Nspd;
254        ptr_array->deg_bl_muxing = dyn_p.deg_bl_muxing;
255        ptr_array->Ndsam_lev_1 = Ndsam_lev_1;
256        ptr_array->Ndsam_lev_2 = Ndsam_lev_2;
257        ptr_array->access_time = uca->access_time;
258        ptr_array->cycle_time = uca->cycle_time;
259        ptr_array->multisubbank_interleave_cycle_time =
260            uca->multisubbank_interleave_cycle_time;
261        ptr_array->area_ram_cells = uca->area_all_dataramcells;
262        ptr_array->area   = uca->area.get_area();
263        ptr_array->height = uca->area.h;
264        ptr_array->width  = uca->area.w;
265        ptr_array->mat_height = uca->bank.mat.area.h;
266        ptr_array->mat_length = uca->bank.mat.area.w;
267        ptr_array->subarray_height = uca->bank.mat.subarray.area.h;
268        ptr_array->subarray_length = uca->bank.mat.subarray.area.w;
269        ptr_array->power  = uca->power;
270        ptr_array->delay_senseamp_mux_decoder =
271            MAX(uca->delay_array_to_sa_mux_lev_1_decoder,
272                uca->delay_array_to_sa_mux_lev_2_decoder);
273        ptr_array->delay_before_subarray_output_driver =
274            uca->delay_before_subarray_output_driver;
275        ptr_array->delay_from_subarray_output_driver_to_output =
276            uca->delay_from_subarray_out_drv_to_out;
277
278        ptr_array->delay_route_to_bank = uca->htree_in_add->delay;
279        ptr_array->delay_input_htree = uca->bank.htree_in_add->delay;
280        ptr_array->delay_row_predecode_driver_and_block =
281            uca->bank.mat.r_predec->delay;
282        ptr_array->delay_row_decoder = uca->bank.mat.row_dec->delay;
283        ptr_array->delay_bitlines = uca->bank.mat.delay_bitline;
284        ptr_array->delay_matchlines = uca->bank.mat.delay_matchchline;
285        ptr_array->delay_sense_amp = uca->bank.mat.delay_sa;
286        ptr_array->delay_subarray_output_driver =
287            uca->bank.mat.delay_subarray_out_drv_htree;
288        ptr_array->delay_dout_htree = uca->bank.htree_out_data->delay;
289        ptr_array->delay_comparator = uca->bank.mat.delay_comparator;
290
291        ptr_array->all_banks_height = uca->area.h;
292        ptr_array->all_banks_width = uca->area.w;
293        ptr_array->area_efficiency = uca->area_all_dataramcells * 100 /
294            (uca->area.get_area());
295
296        ptr_array->power_routing_to_bank = uca->power_routing_to_bank;
297        ptr_array->power_addr_input_htree = uca->bank.htree_in_add->power;
298        ptr_array->power_data_input_htree = uca->bank.htree_in_data->power;
299        ptr_array->power_data_output_htree = uca->bank.htree_out_data->power;
300
301        ptr_array->power_row_predecoder_drivers =
302            uca->bank.mat.r_predec->driver_power;
303        ptr_array->power_row_predecoder_drivers.readOp.dynamic *=
304            num_act_mats_hor_dir;
305        ptr_array->power_row_predecoder_drivers.writeOp.dynamic *=
306            num_act_mats_hor_dir;
307        ptr_array->power_row_predecoder_drivers.searchOp.dynamic *=
308            num_act_mats_hor_dir;
309
310        ptr_array->power_row_predecoder_blocks =
311            uca->bank.mat.r_predec->block_power;
312        ptr_array->power_row_predecoder_blocks.readOp.dynamic *=
313            num_act_mats_hor_dir;
314        ptr_array->power_row_predecoder_blocks.writeOp.dynamic *=
315            num_act_mats_hor_dir;
316        ptr_array->power_row_predecoder_blocks.searchOp.dynamic *=
317            num_act_mats_hor_dir;
318
319        ptr_array->power_row_decoders = uca->bank.mat.power_row_decoders;
320        ptr_array->power_row_decoders.readOp.dynamic *= num_act_mats_hor_dir;
321        ptr_array->power_row_decoders.writeOp.dynamic *= num_act_mats_hor_dir;
322        ptr_array->power_row_decoders.searchOp.dynamic *= num_act_mats_hor_dir;
323
324        ptr_array->power_bit_mux_predecoder_drivers =
325            uca->bank.mat.b_mux_predec->driver_power;
326        ptr_array->power_bit_mux_predecoder_drivers.readOp.dynamic *=
327            num_act_mats_hor_dir;
328        ptr_array->power_bit_mux_predecoder_drivers.writeOp.dynamic *=
329            num_act_mats_hor_dir;
330        ptr_array->power_bit_mux_predecoder_drivers.searchOp.dynamic *=
331            num_act_mats_hor_dir;
332
333        ptr_array->power_bit_mux_predecoder_blocks =
334            uca->bank.mat.b_mux_predec->block_power;
335        ptr_array->power_bit_mux_predecoder_blocks.readOp.dynamic *=
336            num_act_mats_hor_dir;
337        ptr_array->power_bit_mux_predecoder_blocks.writeOp.dynamic *=
338            num_act_mats_hor_dir;
339        ptr_array->power_bit_mux_predecoder_blocks.searchOp.dynamic *=
340            num_act_mats_hor_dir;
341
342        ptr_array->power_bit_mux_decoders = uca->bank.mat.power_bit_mux_decoders;
343        ptr_array->power_bit_mux_decoders.readOp.dynamic *= num_act_mats_hor_dir;
344        ptr_array->power_bit_mux_decoders.writeOp.dynamic *=
345            num_act_mats_hor_dir;
346        ptr_array->power_bit_mux_decoders.searchOp.dynamic *=
347            num_act_mats_hor_dir;
348
349        ptr_array->power_senseamp_mux_lev_1_predecoder_drivers =
350            uca->bank.mat.sa_mux_lev_1_predec->driver_power;
351        ptr_array->power_senseamp_mux_lev_1_predecoder_drivers .readOp.dynamic *=
352            num_act_mats_hor_dir;
353        ptr_array->power_senseamp_mux_lev_1_predecoder_drivers .writeOp.dynamic *=
354            num_act_mats_hor_dir;
355        ptr_array->power_senseamp_mux_lev_1_predecoder_drivers .searchOp.dynamic *=
356            num_act_mats_hor_dir;
357
358        ptr_array->power_senseamp_mux_lev_1_predecoder_blocks =
359            uca->bank.mat.sa_mux_lev_1_predec->block_power;
360        ptr_array->power_senseamp_mux_lev_1_predecoder_blocks.readOp.dynamic *=
361            num_act_mats_hor_dir;
362        ptr_array->power_senseamp_mux_lev_1_predecoder_blocks.writeOp.dynamic *=
363            num_act_mats_hor_dir;
364        ptr_array->power_senseamp_mux_lev_1_predecoder_blocks.searchOp.dynamic *=
365            num_act_mats_hor_dir;
366
367        ptr_array->power_senseamp_mux_lev_1_decoders =
368            uca->bank.mat.power_sa_mux_lev_1_decoders;
369        ptr_array->power_senseamp_mux_lev_1_decoders.readOp.dynamic *=
370            num_act_mats_hor_dir;
371        ptr_array->power_senseamp_mux_lev_1_decoders.writeOp.dynamic *=
372            num_act_mats_hor_dir;
373        ptr_array->power_senseamp_mux_lev_1_decoders.searchOp.dynamic *=
374            num_act_mats_hor_dir;
375
376        ptr_array->power_senseamp_mux_lev_2_predecoder_drivers =
377            uca->bank.mat.sa_mux_lev_2_predec->driver_power;
378        ptr_array->power_senseamp_mux_lev_2_predecoder_drivers.readOp.dynamic *=
379            num_act_mats_hor_dir;
380        ptr_array->power_senseamp_mux_lev_2_predecoder_drivers.writeOp.dynamic *=
381            num_act_mats_hor_dir;
382        ptr_array->power_senseamp_mux_lev_2_predecoder_drivers.searchOp.dynamic *=
383            num_act_mats_hor_dir;
384
385        ptr_array->power_senseamp_mux_lev_2_predecoder_blocks =
386            uca->bank.mat.sa_mux_lev_2_predec->block_power;
387        ptr_array->power_senseamp_mux_lev_2_predecoder_blocks.readOp.dynamic *=
388            num_act_mats_hor_dir;
389        ptr_array->power_senseamp_mux_lev_2_predecoder_blocks.writeOp.dynamic *=
390            num_act_mats_hor_dir;
391        ptr_array->power_senseamp_mux_lev_2_predecoder_blocks.searchOp.dynamic *=
392            num_act_mats_hor_dir;
393
394        ptr_array->power_senseamp_mux_lev_2_decoders =
395            uca->bank.mat.power_sa_mux_lev_2_decoders;
396        ptr_array->power_senseamp_mux_lev_2_decoders .readOp.dynamic *=
397            num_act_mats_hor_dir;
398        ptr_array->power_senseamp_mux_lev_2_decoders .writeOp.dynamic *=
399            num_act_mats_hor_dir;
400        ptr_array->power_senseamp_mux_lev_2_decoders .searchOp.dynamic *=
401            num_act_mats_hor_dir;
402
403        ptr_array->power_bitlines = uca->bank.mat.power_bitline;
404        ptr_array->power_bitlines.readOp.dynamic *= num_act_mats_hor_dir;
405        ptr_array->power_bitlines.writeOp.dynamic *= num_act_mats_hor_dir;
406        ptr_array->power_bitlines.searchOp.dynamic *= num_act_mats_hor_dir;
407
408        ptr_array->power_sense_amps = uca->bank.mat.power_sa;
409        ptr_array->power_sense_amps.readOp.dynamic *= num_act_mats_hor_dir;
410        ptr_array->power_sense_amps.writeOp.dynamic *= num_act_mats_hor_dir;
411        ptr_array->power_sense_amps.searchOp.dynamic *= num_act_mats_hor_dir;
412
413        ptr_array->power_prechg_eq_drivers =
414            uca->bank.mat.power_bl_precharge_eq_drv;
415        ptr_array->power_prechg_eq_drivers.readOp.dynamic *=
416            num_act_mats_hor_dir;
417        ptr_array->power_prechg_eq_drivers.writeOp.dynamic *=
418            num_act_mats_hor_dir;
419        ptr_array->power_prechg_eq_drivers.searchOp.dynamic *=
420            num_act_mats_hor_dir;
421
422        ptr_array->power_output_drivers_at_subarray =
423            uca->bank.mat.power_subarray_out_drv;
424        ptr_array->power_output_drivers_at_subarray.readOp.dynamic *=
425            num_act_mats_hor_dir;
426        ptr_array->power_output_drivers_at_subarray.writeOp.dynamic *=
427            num_act_mats_hor_dir;
428        ptr_array->power_output_drivers_at_subarray.searchOp.dynamic *=
429            num_act_mats_hor_dir;
430
431        ptr_array->power_comparators = uca->bank.mat.power_comparator;
432        ptr_array->power_comparators.readOp.dynamic *= num_act_mats_hor_dir;
433        ptr_array->power_comparators.writeOp.dynamic *= num_act_mats_hor_dir;
434        ptr_array->power_comparators.searchOp.dynamic *= num_act_mats_hor_dir;
435
436        if (is_fa || pure_cam) {
437            ptr_array->power_htree_in_search =
438                uca->bank.htree_in_search->power;
439            ptr_array->power_htree_out_search =
440                uca->bank.htree_out_search->power;
441            ptr_array->power_searchline = uca->bank.mat.power_searchline;
442            ptr_array->power_searchline.searchOp.dynamic *= num_mats;
443            ptr_array->power_searchline_precharge =
444                uca->bank.mat.power_searchline_precharge;
445            ptr_array->power_searchline_precharge.searchOp.dynamic *= num_mats;
446            ptr_array->power_matchlines = uca->bank.mat.power_matchline;
447            ptr_array->power_matchlines.searchOp.dynamic *= num_mats;
448            ptr_array->power_matchline_precharge =
449                uca->bank.mat.power_matchline_precharge;
450            ptr_array->power_matchline_precharge.searchOp.dynamic *= num_mats;
451            ptr_array->power_matchline_to_wordline_drv =
452                uca->bank.mat.power_ml_to_ram_wl_drv;
453        }
454
455        ptr_array->activate_energy = uca->activate_energy;
456        ptr_array->read_energy = uca->read_energy;
457        ptr_array->write_energy = uca->write_energy;
458        ptr_array->precharge_energy = uca->precharge_energy;
459        ptr_array->refresh_power = uca->refresh_power;
460        ptr_array->leak_power_subbank_closed_page =
461            uca->leak_power_subbank_closed_page;
462        ptr_array->leak_power_subbank_open_page =
463            uca->leak_power_subbank_open_page;
464        ptr_array->leak_power_request_and_reply_networks =
465            uca->leak_power_request_and_reply_networks;
466
467        ptr_array->precharge_delay = uca->precharge_delay;
468    }
469
470
471    delete uca;
472    return true;
473}
474
475
476
477bool check_uca_org(uca_org_t & u, min_values_t *minval) {
478    if (((u.access_time - minval->min_delay) * 100 / minval->min_delay) >
479        g_ip->delay_dev) {
480        return false;
481    }
482    if (((u.power.readOp.dynamic - minval->min_dyn) / minval->min_dyn)*100 >
483        g_ip->dynamic_power_dev) {
484        return false;
485    }
486    if (((u.power.readOp.leakage - minval->min_leakage) /
487         minval->min_leakage) * 100 >
488        g_ip->leakage_power_dev) {
489        return false;
490    }
491    if (((u.cycle_time - minval->min_cyc) / minval->min_cyc)*100 >
492        g_ip->cycle_time_dev) {
493        return false;
494    }
495    if (((u.area - minval->min_area) / minval->min_area)*100 >
496        g_ip->area_dev) {
497        return false;
498    }
499    return true;
500}
501
502bool check_mem_org(mem_array & u, const min_values_t *minval) {
503    if (((u.access_time - minval->min_delay) * 100 / minval->min_delay) >
504        g_ip->delay_dev) {
505        return false;
506    }
507    if (((u.power.readOp.dynamic - minval->min_dyn) / minval->min_dyn)*100 >
508            g_ip->dynamic_power_dev) {
509        return false;
510    }
511    if (((u.power.readOp.leakage - minval->min_leakage) /
512         minval->min_leakage) * 100 >
513        g_ip->leakage_power_dev) {
514        return false;
515    }
516    if (((u.cycle_time - minval->min_cyc) / minval->min_cyc) * 100 >
517        g_ip->cycle_time_dev) {
518        return false;
519    }
520    if (((u.area - minval->min_area) / minval->min_area) * 100 >
521        g_ip->area_dev) {
522        return false;
523    }
524    return true;
525}
526
527
528
529
530void find_optimal_uca(uca_org_t *res, min_values_t * minval,
531                      list<uca_org_t> & ulist) {
532    double cost = 0;
533    double min_cost = BIGNUM;
534    float d, a, dp, lp, c;
535
536    dp = g_ip->dynamic_power_wt;
537    lp = g_ip->leakage_power_wt;
538    a  = g_ip->area_wt;
539    d  = g_ip->delay_wt;
540    c  = g_ip->cycle_time_wt;
541
542    if (ulist.empty() == true) {
543        cout << "ERROR: no valid cache organizations found" << endl;
544        exit(0);
545    }
546
547    for (list<uca_org_t>::iterator niter = ulist.begin(); niter != ulist.end();
548         niter++) {
549        if (g_ip->ed == 1) {
550            cost = ((niter)->access_time / minval->min_delay) *
551                ((niter)->power.readOp.dynamic / minval->min_dyn);
552            if (min_cost > cost) {
553                min_cost = cost;
554                *res = (*(niter));
555            }
556        } else if (g_ip->ed == 2) {
557            cost = ((niter)->access_time / minval->min_delay) *
558                   ((niter)->access_time / minval->min_delay) *
559                   ((niter)->power.readOp.dynamic / minval->min_dyn);
560            if (min_cost > cost) {
561                min_cost = cost;
562                *res = (*(niter));
563            }
564        } else {
565            /*
566             * check whether the current organization
567             * meets the input deviation constraints
568             */
569            bool v = check_uca_org(*niter, minval);
570
571            if (v) {
572                cost = (d  * ((niter)->access_time / minval->min_delay) +
573                        c  * ((niter)->cycle_time / minval->min_cyc) +
574                        dp * ((niter)->power.readOp.dynamic / minval->min_dyn) +
575                        lp *
576                        ((niter)->power.readOp.leakage / minval->min_leakage) +
577                        a  * ((niter)->area / minval->min_area));
578
579                if (min_cost > cost) {
580                    min_cost = cost;
581                    *res = (*(niter));
582                    niter = ulist.erase(niter);
583                    if (niter != ulist.begin())
584                        niter--;
585                }
586            } else {
587                niter = ulist.erase(niter);
588                if (niter != ulist.begin())
589                    niter--;
590            }
591        }
592    }
593
594    if (min_cost == BIGNUM) {
595        cout << "ERROR: no cache organizations met optimization criteria"
596             << endl;
597        exit(0);
598    }
599}
600
601
602
603void filter_tag_arr(const min_values_t * min, list<mem_array *> & list) {
604    double cost = BIGNUM;
605    double cur_cost;
606    double wt_delay = g_ip->delay_wt;
607    double wt_dyn = g_ip->dynamic_power_wt;
608    double wt_leakage = g_ip->leakage_power_wt;
609    double wt_cyc = g_ip->cycle_time_wt;
610    double wt_area = g_ip->area_wt;
611    mem_array * res = NULL;
612
613    if (list.empty() == true) {
614        cout << "ERROR: no valid tag organizations found" << endl;
615        exit(1);
616    }
617
618
619    while (list.empty() != true) {
620        bool v = check_mem_org(*list.back(), min);
621        if (v) {
622            cur_cost = wt_delay * (list.back()->access_time / min->min_delay) +
623                       wt_dyn * (list.back()->power.readOp.dynamic /
624                                 min->min_dyn) +
625                       wt_leakage * (list.back()->power.readOp.leakage /
626                                     min->min_leakage) +
627                       wt_area * (list.back()->area / min->min_area) +
628                       wt_cyc * (list.back()->cycle_time / min->min_cyc);
629        } else {
630            cur_cost = BIGNUM;
631        }
632        if (cur_cost < cost) {
633            if (res != NULL) {
634                delete res;
635            }
636            cost = cur_cost;
637            res  = list.back();
638        } else {
639            delete list.back();
640        }
641        list.pop_back();
642    }
643    if (!res) {
644        cout << "ERROR: no valid tag organizations found" << endl;
645        exit(0);
646    }
647
648    list.push_back(res);
649}
650
651
652
653void filter_data_arr(list<mem_array *> & curr_list) {
654    if (curr_list.empty() == true) {
655        cout << "ERROR: no valid data array organizations found" << endl;
656        exit(1);
657    }
658
659    list<mem_array *>::iterator iter;
660
661    for (iter = curr_list.begin(); iter != curr_list.end(); ++iter) {
662        mem_array * m = *iter;
663
664        if (m == NULL) exit(1);
665
666        if (((m->access_time - m->arr_min->min_delay) / m->arr_min->min_delay >
667             0.5) &&
668            ((m->power.readOp.dynamic - m->arr_min->min_dyn) /
669             m->arr_min->min_dyn > 0.5)) {
670            delete m;
671            iter = curr_list.erase(iter);
672            iter --;
673        }
674    }
675}
676
677
678
679/*
680 * Performs exhaustive search across different sub-array sizes,
681 * wire types and aspect ratios to find an optimal UCA organization
682 * 1. First different valid tag array organizations are calculated
683 *    and stored in tag_arr array
684 * 2. The exhaustive search is repeated to find valid data array
685 *    organizations and stored in data_arr array
686 * 3. Cache area, delay, power, and cycle time for different
687 *    cache organizations are calculated based on the
688 *    above results
689 * 4. Cache model with least cost is picked from sol_list
690 */
691void solve(uca_org_t *fin_res) {
692    bool   is_dram  = false;
693    int    pure_ram = g_ip->pure_ram;
694    bool   pure_cam = g_ip->pure_cam;
695
696    init_tech_params(g_ip->F_sz_um, false);
697
698
699    list<mem_array *> tag_arr (0);
700    list<mem_array *> data_arr(0);
701    list<mem_array *>::iterator miter;
702    list<uca_org_t> sol_list(1, uca_org_t());
703
704    fin_res->tag_array.access_time = 0;
705    fin_res->tag_array.Ndwl = 0;
706    fin_res->tag_array.Ndbl = 0;
707    fin_res->tag_array.Nspd = 0;
708    fin_res->tag_array.deg_bl_muxing = 0;
709    fin_res->tag_array.Ndsam_lev_1 = 0;
710    fin_res->tag_array.Ndsam_lev_2 = 0;
711
712
713    // distribute calculate_time() execution to multiple threads
714    calc_time_mt_wrapper_struct * calc_array =
715        new calc_time_mt_wrapper_struct[nthreads];
716    pthread_t threads[nthreads];
717
718    for (uint32_t t = 0; t < nthreads; t++) {
719        calc_array[t].tid         = t;
720        calc_array[t].pure_ram    = pure_ram;
721        calc_array[t].pure_cam    = pure_cam;
722        calc_array[t].data_res    = new min_values_t();
723        calc_array[t].tag_res     = new min_values_t();
724    }
725
726    bool     is_tag;
727    uint32_t ram_cell_tech_type;
728
729    // If it's a cache, first calculate the area, delay and power for all tag array partitions.
730    if (!(pure_ram || pure_cam || g_ip->fully_assoc)) { //cache
731        is_tag = true;
732        ram_cell_tech_type = g_ip->tag_arr_ram_cell_tech_type;
733        is_dram = ((ram_cell_tech_type == lp_dram) ||
734                   (ram_cell_tech_type == comm_dram));
735        init_tech_params(g_ip->F_sz_um, is_tag);
736
737        for (uint32_t t = 0; t < nthreads; t++) {
738            calc_array[t].is_tag      = is_tag;
739            calc_array[t].is_main_mem = false;
740            calc_array[t].Nspd_min    = 0.125;
741#ifndef DEBUG
742            pthread_create(&threads[t], NULL, calc_time_mt_wrapper,
743                           (void *)(&(calc_array[t])));
744#else
745            calc_time_mt_wrapper((void *)(&(calc_array[t])));
746#endif
747        }
748
749#ifndef DEBUG
750        for (uint32_t t = 0; t < nthreads; t++) {
751            pthread_join(threads[t], NULL);
752        }
753#endif
754
755        for (uint32_t t = 0; t < nthreads; t++) {
756            calc_array[t].data_arr.sort(mem_array::lt);
757            data_arr.merge(calc_array[t].data_arr, mem_array::lt);
758            calc_array[t].tag_arr.sort(mem_array::lt);
759            tag_arr.merge(calc_array[t].tag_arr, mem_array::lt);
760        }
761    }
762
763
764    // calculate the area, delay and power for all data array partitions (for cache or plain RAM).
765    // in the new cacti, cam, fully_associative cache are processed as single array in the data portion
766    is_tag              = false;
767    ram_cell_tech_type  = g_ip->data_arr_ram_cell_tech_type;
768    is_dram             = ((ram_cell_tech_type == lp_dram) || (ram_cell_tech_type == comm_dram));
769    init_tech_params(g_ip->F_sz_um, is_tag);
770
771    for (uint32_t t = 0; t < nthreads; t++) {
772        calc_array[t].is_tag      = is_tag;
773        calc_array[t].is_main_mem = g_ip->is_main_mem;
774        if (!(pure_cam || g_ip->fully_assoc)) {
775            calc_array[t].Nspd_min = (double)(g_ip->out_w) /
776                (double)(g_ip->block_sz * 8);
777        } else {
778            calc_array[t].Nspd_min = 1;
779        }
780
781#ifndef DEBUG
782        pthread_create(&threads[t], NULL, calc_time_mt_wrapper,
783                       (void *)(&(calc_array[t])));
784#else
785        calc_time_mt_wrapper((void *)(&(calc_array[t])));
786#endif
787    }
788
789#ifndef DEBUG
790    for (uint32_t t = 0; t < nthreads; t++) {
791        pthread_join(threads[t], NULL);
792    }
793#endif
794
795    data_arr.clear();
796    for (uint32_t t = 0; t < nthreads; t++) {
797        calc_array[t].data_arr.sort(mem_array::lt);
798        data_arr.merge(calc_array[t].data_arr, mem_array::lt);
799
800
801    }
802
803
804
805    min_values_t * d_min = new min_values_t();
806    min_values_t * t_min = new min_values_t();
807    min_values_t * cache_min = new min_values_t();
808
809    for (uint32_t t = 0; t < nthreads; t++) {
810        d_min->update_min_values(calc_array[t].data_res);
811        t_min->update_min_values(calc_array[t].tag_res);
812    }
813
814    for (miter = data_arr.begin(); miter != data_arr.end(); miter++) {
815        (*miter)->arr_min = d_min;
816    }
817
818    filter_data_arr(data_arr);
819    if (!(pure_ram || pure_cam || g_ip->fully_assoc)) {
820        filter_tag_arr(t_min, tag_arr);
821    }
822
823    if (pure_ram || pure_cam || g_ip->fully_assoc) {
824        for (miter = data_arr.begin(); miter != data_arr.end(); miter++) {
825            uca_org_t & curr_org  = sol_list.back();
826            curr_org.tag_array2  = NULL;
827            curr_org.data_array2 = (*miter);
828
829            curr_org.find_delay();
830            curr_org.find_energy();
831            curr_org.find_area();
832            curr_org.find_cyc();
833
834            //update min values for the entire cache
835            cache_min->update_min_values(curr_org);
836
837            sol_list.push_back(uca_org_t());
838        }
839    } else {
840        while (tag_arr.empty() != true) {
841            mem_array * arr_temp = (tag_arr.back());
842            tag_arr.pop_back();
843
844            for (miter = data_arr.begin(); miter != data_arr.end(); miter++) {
845                uca_org_t & curr_org  = sol_list.back();
846                curr_org.tag_array2  = arr_temp;
847                curr_org.data_array2 = (*miter);
848
849                curr_org.find_delay();
850                curr_org.find_energy();
851                curr_org.find_area();
852                curr_org.find_cyc();
853
854                //update min values for the entire cache
855                cache_min->update_min_values(curr_org);
856
857                sol_list.push_back(uca_org_t());
858            }
859        }
860    }
861
862    sol_list.pop_back();
863
864    find_optimal_uca(fin_res, cache_min, sol_list);
865
866    sol_list.clear();
867
868    for (miter = data_arr.begin(); miter != data_arr.end(); ++miter) {
869        if (*miter != fin_res->data_array2) {
870            delete *miter;
871        }
872    }
873    data_arr.clear();
874
875    for (uint32_t t = 0; t < nthreads; t++) {
876        delete calc_array[t].data_res;
877        delete calc_array[t].tag_res;
878    }
879
880    delete [] calc_array;
881    delete cache_min;
882    delete d_min;
883    delete t_min;
884}
885
886void update(uca_org_t *fin_res)
887{
888  if(fin_res->tag_array2)
889  {
890    init_tech_params(g_ip->F_sz_um,true);
891    DynamicParameter tag_arr_dyn_p(true, g_ip->pure_ram, g_ip->pure_cam,
892                                   fin_res->tag_array2->Nspd,
893                                   fin_res->tag_array2->Ndwl,
894                                   fin_res->tag_array2->Ndbl,
895                                   fin_res->tag_array2->Ndcm,
896                                   fin_res->tag_array2->Ndsam_lev_1,
897                                   fin_res->tag_array2->Ndsam_lev_2,
898                                   g_ip->is_main_mem);
899    if(tag_arr_dyn_p.is_valid)
900    {
901      UCA * tag_arr = new UCA(tag_arr_dyn_p);
902      fin_res->tag_array2->power = tag_arr->power;
903    }
904    else
905    {
906      cout << "ERROR: Cannot retrieve array structure for leakage feedback"
907           << endl;
908      exit(1);
909    }
910  }
911  init_tech_params(g_ip->F_sz_um,false);
912  DynamicParameter data_arr_dyn_p(false, g_ip->pure_ram, g_ip->pure_cam,
913                                  fin_res->data_array2->Nspd,
914                                  fin_res->data_array2->Ndwl,
915                                  fin_res->data_array2->Ndbl,
916                                  fin_res->data_array2->Ndcm,
917                                  fin_res->data_array2->Ndsam_lev_1,
918                                  fin_res->data_array2->Ndsam_lev_2,
919                                  g_ip->is_main_mem);
920  if(data_arr_dyn_p.is_valid)
921  {
922    UCA * data_arr = new UCA(data_arr_dyn_p);
923    fin_res->data_array2->power = data_arr->power;
924  }
925  else
926  {
927    cout << "ERROR: Cannot retrieve array structure for leakage feedback"
928         << endl;
929    exit(1);
930  }
931
932  fin_res->find_energy();
933}
934
935