648 lines
28 KiB
C++
648 lines
28 KiB
C++
|
/*****************************************************************************
|
||
|
* McPAT
|
||
|
* SOFTWARE LICENSE AGREEMENT
|
||
|
* Copyright (c) 2010-2013 Advanced Micro Devices, Inc.
|
||
|
* 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.
|
||
|
*
|
||
|
* Authors: Joel Hestness
|
||
|
* Yasuko Eckert
|
||
|
*
|
||
|
***************************************************************************/
|
||
|
|
||
|
#include <algorithm>
|
||
|
#include <cmath>
|
||
|
#include <cstring>
|
||
|
#include <iostream>
|
||
|
|
||
|
#include "arbiter.h"
|
||
|
#include "array.h"
|
||
|
#include "basic_circuit.h"
|
||
|
#include "cachearray.h"
|
||
|
#include "cacheunit.h"
|
||
|
#include "common.h"
|
||
|
#include "const.h"
|
||
|
#include "io.h"
|
||
|
#include "logic.h"
|
||
|
#include "parameter.h"
|
||
|
|
||
|
bool CacheUnit::is_cache = true;
|
||
|
bool CacheUnit::pure_cam = false;
|
||
|
bool CacheUnit::opt_local = true;
|
||
|
bool CacheUnit::force_cache_config = false;
|
||
|
|
||
|
CacheUnit::CacheUnit(XMLNode* _xml_data, InputParameter* _interface_ip)
|
||
|
: dir_overhead(0), McPATComponent(_xml_data, _interface_ip) {
|
||
|
|
||
|
int tag;
|
||
|
int data;
|
||
|
|
||
|
name = "Cache Unit";
|
||
|
CacheArray* arrayPtr = NULL;
|
||
|
|
||
|
set_cache_param_from_xml_data();
|
||
|
|
||
|
//All lower level cache are physically indexed and tagged.
|
||
|
double size;
|
||
|
double line;
|
||
|
double assoc;
|
||
|
double banks;
|
||
|
size = cache_params.capacity;
|
||
|
line = cache_params.blockW;
|
||
|
assoc = cache_params.assoc;
|
||
|
banks = cache_params.nbanks;
|
||
|
if ((cache_params.dir_ty == ST &&
|
||
|
cache_params.cache_level == L1Directory) ||
|
||
|
(cache_params.dir_ty == ST &&
|
||
|
cache_params.cache_level == L2Directory)) {
|
||
|
tag = physical_address_width + EXTRA_TAG_BITS;
|
||
|
} else {
|
||
|
tag = physical_address_width - int(ceil(log2(size / line / assoc))) -
|
||
|
int(ceil(log2(line))) + EXTRA_TAG_BITS;
|
||
|
|
||
|
if (cache_params.dir_ty == SBT) {
|
||
|
dir_overhead = ceil(cache_params.num_cores / BITS_PER_BYTE) *
|
||
|
BITS_PER_BYTE / (line * BITS_PER_BYTE);
|
||
|
line *= (1 + dir_overhead);
|
||
|
size *= (1 + dir_overhead);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
interface_ip.cache_sz = (int)size;
|
||
|
interface_ip.line_sz = (int)line;
|
||
|
interface_ip.assoc = (int)assoc;
|
||
|
interface_ip.nbanks = (int)banks;
|
||
|
interface_ip.specific_tag = tag > 0;
|
||
|
interface_ip.tag_w = tag;
|
||
|
|
||
|
if (cache_params.cache_level == L1) {
|
||
|
interface_ip.out_w = interface_ip.line_sz * BITS_PER_BYTE;
|
||
|
} else {
|
||
|
interface_ip.out_w = interface_ip.line_sz * BITS_PER_BYTE / 2;
|
||
|
}
|
||
|
|
||
|
interface_ip.access_mode = cache_params.cache_access_mode;
|
||
|
interface_ip.throughput= cache_params.throughput;
|
||
|
interface_ip.latency = cache_params.latency;
|
||
|
interface_ip.obj_func_dyn_energy = 0;
|
||
|
interface_ip.obj_func_dyn_power = 0;
|
||
|
interface_ip.obj_func_leak_power = 0;
|
||
|
interface_ip.obj_func_cycle_t = 1;
|
||
|
interface_ip.is_cache = is_cache;
|
||
|
interface_ip.pure_ram = cache_params.pure_ram;
|
||
|
interface_ip.pure_cam = pure_cam;
|
||
|
interface_ip.num_rw_ports = cache_params.cache_rw_ports;
|
||
|
interface_ip.num_rd_ports = cache_params.cache_rd_ports;
|
||
|
interface_ip.num_wr_ports = cache_params.cache_wr_ports;
|
||
|
interface_ip.num_se_rd_ports = cache_params.cache_se_rd_ports;
|
||
|
interface_ip.num_search_ports = cache_params.cache_search_ports;
|
||
|
|
||
|
arrayPtr = new CacheArray(xml_data, &interface_ip, "Data and Tag Arrays",
|
||
|
cache_params.device_ty, clockRate, opt_local,
|
||
|
cache_params.core_ty);
|
||
|
children.push_back(arrayPtr);
|
||
|
|
||
|
// This is for calculating TDP, which depends on the number of
|
||
|
// available ports
|
||
|
int num_tdp_ports = arrayPtr->l_ip.num_rw_ports +
|
||
|
arrayPtr->l_ip.num_rd_ports + arrayPtr->l_ip.num_wr_ports;
|
||
|
|
||
|
// Set new array stats for calculating TDP and runtime power
|
||
|
arrayPtr->tdp_stats.reset();
|
||
|
arrayPtr->tdp_stats.readAc.access = cache_stats.tdp_read_access_scalar *
|
||
|
num_tdp_ports * cache_stats.duty_cycle *
|
||
|
cache_stats.homenode_access_scalar;
|
||
|
arrayPtr->tdp_stats.readAc.miss = 0;
|
||
|
arrayPtr->tdp_stats.readAc.hit = arrayPtr->tdp_stats.readAc.access -
|
||
|
arrayPtr->tdp_stats.readAc.miss;
|
||
|
arrayPtr->tdp_stats.writeAc.access = cache_stats.tdp_write_access_scalar *
|
||
|
num_tdp_ports * cache_stats.duty_cycle *
|
||
|
cache_stats.homenode_access_scalar;
|
||
|
arrayPtr->tdp_stats.writeAc.miss = 0;
|
||
|
arrayPtr->tdp_stats.writeAc.hit = arrayPtr->tdp_stats.writeAc.access -
|
||
|
arrayPtr->tdp_stats.writeAc.miss;
|
||
|
arrayPtr->tdp_stats.searchAc.access = 0;
|
||
|
arrayPtr->tdp_stats.searchAc.miss = 0;
|
||
|
arrayPtr->tdp_stats.searchAc.hit = 0;
|
||
|
|
||
|
arrayPtr->rtp_stats.reset();
|
||
|
if (cache_stats.use_detailed_stats) {
|
||
|
arrayPtr->rtp_stats.dataReadAc.access =
|
||
|
cache_stats.num_data_array_reads;
|
||
|
arrayPtr->rtp_stats.dataWriteAc.access =
|
||
|
cache_stats.num_data_array_writes;
|
||
|
arrayPtr->rtp_stats.tagReadAc.access =
|
||
|
cache_stats.num_tag_array_reads;
|
||
|
arrayPtr->rtp_stats.tagWriteAc.access =
|
||
|
cache_stats.num_tag_array_writes;
|
||
|
} else {
|
||
|
// This code makes assumptions. For instance, it assumes that
|
||
|
// tag and data arrays are accessed in parallel on a read request and
|
||
|
// this is a write-allocate cache. It also ignores any coherence
|
||
|
// requests. Using detailed stats as above can avoid the ambiguity
|
||
|
// that is introduced here
|
||
|
arrayPtr->rtp_stats.dataReadAc.access =
|
||
|
cache_stats.read_accesses + cache_stats.write_misses;
|
||
|
arrayPtr->rtp_stats.dataWriteAc.access =
|
||
|
cache_stats.write_accesses + cache_stats.read_misses;
|
||
|
arrayPtr->rtp_stats.tagReadAc.access =
|
||
|
cache_stats.read_accesses + cache_stats.write_accesses;
|
||
|
arrayPtr->rtp_stats.tagWriteAc.access =
|
||
|
cache_stats.read_misses + cache_stats.write_misses;
|
||
|
}
|
||
|
|
||
|
// Set SBT stats if this is an SBT directory type
|
||
|
if (dir_overhead > 0) {
|
||
|
arrayPtr->setSBTDirOverhead(dir_overhead);
|
||
|
|
||
|
// TDP stats
|
||
|
arrayPtr->sbt_tdp_stats.readAc.access =
|
||
|
cache_stats.tdp_read_access_scalar *
|
||
|
num_tdp_ports * cache_stats.dir_duty_cycle *
|
||
|
(1 - cache_stats.homenode_access_scalar);
|
||
|
arrayPtr->sbt_tdp_stats.readAc.miss = 0;
|
||
|
arrayPtr->sbt_tdp_stats.readAc.hit =
|
||
|
arrayPtr->sbt_tdp_stats.readAc.access -
|
||
|
arrayPtr->sbt_tdp_stats.readAc.miss;
|
||
|
arrayPtr->sbt_tdp_stats.writeAc.access =
|
||
|
cache_stats.tdp_sbt_write_access_scalar *
|
||
|
num_tdp_ports * cache_stats.dir_duty_cycle *
|
||
|
(1 - cache_stats.homenode_access_scalar);
|
||
|
arrayPtr->sbt_tdp_stats.writeAc.miss = 0;
|
||
|
arrayPtr->sbt_tdp_stats.writeAc.hit =
|
||
|
arrayPtr->sbt_tdp_stats.writeAc.access -
|
||
|
arrayPtr->sbt_tdp_stats.writeAc.miss;
|
||
|
|
||
|
// Runtime power stats
|
||
|
arrayPtr->sbt_rtp_stats.readAc.access =
|
||
|
cache_stats.homenode_read_accesses;
|
||
|
arrayPtr->sbt_rtp_stats.readAc.miss =
|
||
|
cache_stats.homenode_read_misses;
|
||
|
arrayPtr->sbt_rtp_stats.readAc.access =
|
||
|
cache_stats.homenode_read_accesses -
|
||
|
cache_stats.homenode_read_misses;
|
||
|
arrayPtr->sbt_rtp_stats.writeAc.access =
|
||
|
cache_stats.homenode_write_accesses;
|
||
|
arrayPtr->sbt_rtp_stats.writeAc.miss =
|
||
|
cache_stats.homenode_write_misses;
|
||
|
arrayPtr->sbt_rtp_stats.writeAc.hit =
|
||
|
cache_stats.homenode_write_accesses -
|
||
|
cache_stats.homenode_write_misses;
|
||
|
}
|
||
|
|
||
|
interface_ip.force_cache_config = force_cache_config;
|
||
|
if (!((cache_params.dir_ty == ST &&
|
||
|
cache_params.cache_level == L1Directory) ||
|
||
|
(cache_params.dir_ty == ST &&
|
||
|
cache_params.cache_level== L2Directory))) {
|
||
|
// Miss Buffer
|
||
|
tag = physical_address_width + EXTRA_TAG_BITS;
|
||
|
data = (physical_address_width) +
|
||
|
int(ceil(log2(size / cache_params.blockW))) +
|
||
|
(cache_params.blockW * BITS_PER_BYTE);
|
||
|
line = int(ceil(data / BITS_PER_BYTE));
|
||
|
size = cache_params.missb_size * line;
|
||
|
|
||
|
interface_ip.cache_sz = size;
|
||
|
interface_ip.line_sz = line;
|
||
|
interface_ip.assoc = cache_params.missb_assoc;
|
||
|
interface_ip.nbanks = cache_params.missb_banks;
|
||
|
interface_ip.specific_tag = tag > 0;
|
||
|
interface_ip.tag_w = tag;
|
||
|
|
||
|
if (cache_params.cache_level == L1) {
|
||
|
interface_ip.out_w = line * BITS_PER_BYTE;
|
||
|
} else {
|
||
|
interface_ip.out_w = line * BITS_PER_BYTE / 2;
|
||
|
}
|
||
|
|
||
|
interface_ip.access_mode = cache_params.miss_buff_access_mode;
|
||
|
interface_ip.obj_func_dyn_energy = 0;
|
||
|
interface_ip.obj_func_dyn_power = 0;
|
||
|
interface_ip.obj_func_leak_power = 0;
|
||
|
interface_ip.obj_func_cycle_t = 1;
|
||
|
interface_ip.is_cache = is_cache;
|
||
|
interface_ip.pure_ram = cache_params.pure_ram;
|
||
|
interface_ip.pure_cam = pure_cam;
|
||
|
interface_ip.throughput = cache_params.throughput;
|
||
|
interface_ip.latency = cache_params.latency;
|
||
|
interface_ip.num_rw_ports = cache_params.miss_buff_rw_ports;
|
||
|
interface_ip.num_rd_ports = cache_params.miss_buff_rd_ports;
|
||
|
interface_ip.num_wr_ports = cache_params.miss_buff_wr_ports;
|
||
|
interface_ip.num_se_rd_ports = cache_params.miss_buff_se_rd_ports;
|
||
|
interface_ip.num_search_ports = cache_params.miss_buff_search_ports;
|
||
|
|
||
|
arrayPtr = new CacheArray(xml_data, &interface_ip, "Miss Buffer",
|
||
|
cache_params.device_ty, clockRate, opt_local,
|
||
|
cache_params.core_ty);
|
||
|
children.push_back(arrayPtr);
|
||
|
|
||
|
arrayPtr->tdp_stats.reset();
|
||
|
arrayPtr->tdp_stats.readAc.access = 0;
|
||
|
arrayPtr->tdp_stats.writeAc.access = arrayPtr->l_ip.num_search_ports;
|
||
|
arrayPtr->tdp_stats.searchAc.access = arrayPtr->l_ip.num_search_ports;
|
||
|
|
||
|
arrayPtr->rtp_stats.reset();
|
||
|
arrayPtr->rtp_stats.readAc.access =
|
||
|
cache_stats.read_misses + cache_stats.write_misses;
|
||
|
arrayPtr->rtp_stats.writeAc.access =
|
||
|
cache_stats.read_misses + cache_stats.write_misses;
|
||
|
arrayPtr->rtp_stats.searchAc.access = 0;
|
||
|
|
||
|
if (cache_params.dir_ty == SBT) {
|
||
|
arrayPtr->rtp_stats.readAc.access +=
|
||
|
cache_stats.homenode_write_misses;
|
||
|
arrayPtr->rtp_stats.writeAc.access +=
|
||
|
cache_stats.homenode_write_misses;
|
||
|
}
|
||
|
|
||
|
// Fill Buffer
|
||
|
tag = physical_address_width + EXTRA_TAG_BITS;
|
||
|
data = cache_params.blockW;
|
||
|
|
||
|
interface_ip.cache_sz = data * cache_params.fu_size;
|
||
|
interface_ip.line_sz = data;
|
||
|
interface_ip.assoc = cache_params.fu_assoc;
|
||
|
interface_ip.nbanks = cache_params.fu_banks;
|
||
|
interface_ip.specific_tag = tag > 0;
|
||
|
interface_ip.tag_w = tag;
|
||
|
|
||
|
if (cache_params.cache_level == L1) {
|
||
|
interface_ip.out_w = interface_ip.line_sz * BITS_PER_BYTE;
|
||
|
} else {
|
||
|
interface_ip.out_w = interface_ip.line_sz * BITS_PER_BYTE / 2;
|
||
|
}
|
||
|
|
||
|
interface_ip.access_mode = cache_params.fetch_buff_access_mode;
|
||
|
interface_ip.obj_func_dyn_energy = 0;
|
||
|
interface_ip.obj_func_dyn_power = 0;
|
||
|
interface_ip.obj_func_leak_power = 0;
|
||
|
interface_ip.obj_func_cycle_t = 1;
|
||
|
interface_ip.is_cache = is_cache;
|
||
|
interface_ip.pure_cam = pure_cam;
|
||
|
interface_ip.throughput = cache_params.throughput;
|
||
|
interface_ip.latency = cache_params.latency;
|
||
|
interface_ip.num_rw_ports = cache_params.fetch_buff_rw_ports;
|
||
|
interface_ip.num_rd_ports = cache_params.fetch_buff_rd_ports;
|
||
|
interface_ip.num_wr_ports = cache_params.fetch_buff_wr_ports;
|
||
|
interface_ip.num_se_rd_ports = cache_params.fetch_buff_se_rd_ports;
|
||
|
interface_ip.num_search_ports = cache_params.fetch_buff_search_ports;
|
||
|
arrayPtr = new CacheArray(xml_data, &interface_ip, "Fill Buffer",
|
||
|
cache_params.device_ty, clockRate, opt_local,
|
||
|
cache_params.core_ty);
|
||
|
children.push_back(arrayPtr);
|
||
|
|
||
|
arrayPtr->tdp_stats.reset();
|
||
|
arrayPtr->tdp_stats.readAc.access = 0;
|
||
|
arrayPtr->tdp_stats.writeAc.access = arrayPtr->l_ip.num_search_ports;
|
||
|
arrayPtr->tdp_stats.searchAc.access = arrayPtr->l_ip.num_search_ports;
|
||
|
|
||
|
arrayPtr->rtp_stats.reset();
|
||
|
arrayPtr->rtp_stats.readAc.access =
|
||
|
cache_stats.read_misses + cache_stats.write_misses;
|
||
|
arrayPtr->rtp_stats.writeAc.access =
|
||
|
cache_stats.read_misses + cache_stats.write_misses;
|
||
|
arrayPtr->rtp_stats.searchAc.access = 0;
|
||
|
|
||
|
if (cache_params.dir_ty == SBT) {
|
||
|
arrayPtr->rtp_stats.readAc.access +=
|
||
|
cache_stats.homenode_write_misses;
|
||
|
arrayPtr->rtp_stats.writeAc.access +=
|
||
|
cache_stats.homenode_write_misses;
|
||
|
}
|
||
|
|
||
|
// Prefetch Buffer
|
||
|
tag = physical_address_width + EXTRA_TAG_BITS;
|
||
|
line = cache_params.blockW;
|
||
|
|
||
|
interface_ip.cache_sz = cache_params.prefetchb_size * line;
|
||
|
interface_ip.line_sz = line;
|
||
|
interface_ip.assoc = cache_params.prefetchb_assoc;
|
||
|
interface_ip.nbanks = cache_params.prefetchb_banks;
|
||
|
interface_ip.specific_tag = tag > 0;
|
||
|
interface_ip.tag_w = tag;
|
||
|
|
||
|
if (cache_params.cache_level == L1) {
|
||
|
interface_ip.out_w = interface_ip.line_sz * BITS_PER_BYTE;
|
||
|
} else {
|
||
|
interface_ip.out_w = interface_ip.line_sz * BITS_PER_BYTE / 2;
|
||
|
}
|
||
|
|
||
|
interface_ip.access_mode = cache_params.prefetch_buff_access_mode;
|
||
|
interface_ip.obj_func_dyn_energy = 0;
|
||
|
interface_ip.obj_func_dyn_power = 0;
|
||
|
interface_ip.obj_func_leak_power = 0;
|
||
|
interface_ip.obj_func_cycle_t = 1;
|
||
|
interface_ip.is_cache = is_cache;
|
||
|
interface_ip.pure_ram = cache_params.pure_ram;
|
||
|
interface_ip.pure_cam = pure_cam;
|
||
|
interface_ip.throughput = cache_params.throughput;
|
||
|
interface_ip.latency = cache_params.latency;
|
||
|
interface_ip.num_rw_ports = cache_params.pf_buff_rw_ports;
|
||
|
interface_ip.num_rd_ports = cache_params.pf_buff_rd_ports;
|
||
|
interface_ip.num_wr_ports = cache_params.pf_buff_wr_ports;
|
||
|
interface_ip.num_se_rd_ports = cache_params.pf_buff_se_rd_ports;
|
||
|
interface_ip.num_search_ports = cache_params.pf_buff_search_ports;
|
||
|
arrayPtr = new CacheArray(xml_data, &interface_ip, "Prefetch Buffer",
|
||
|
cache_params.device_ty, clockRate, opt_local,
|
||
|
cache_params.core_ty);
|
||
|
children.push_back(arrayPtr);
|
||
|
|
||
|
arrayPtr->tdp_stats.reset();
|
||
|
arrayPtr->tdp_stats.readAc.access = 0;
|
||
|
arrayPtr->tdp_stats.writeAc.access = arrayPtr->l_ip.num_search_ports;
|
||
|
arrayPtr->tdp_stats.searchAc.access = arrayPtr->l_ip.num_search_ports;
|
||
|
|
||
|
arrayPtr->rtp_stats.reset();
|
||
|
arrayPtr->rtp_stats.readAc.access = cache_stats.read_misses;
|
||
|
arrayPtr->rtp_stats.writeAc.access = cache_stats.read_misses;
|
||
|
arrayPtr->rtp_stats.searchAc.access = 0;
|
||
|
|
||
|
if (cache_params.dir_ty == SBT) {
|
||
|
arrayPtr->rtp_stats.readAc.access +=
|
||
|
cache_stats.homenode_write_misses;
|
||
|
arrayPtr->rtp_stats.writeAc.access +=
|
||
|
cache_stats.homenode_write_misses;
|
||
|
}
|
||
|
|
||
|
// Writeback Buffer
|
||
|
if (cache_params.wbb_size > 0) {
|
||
|
tag = physical_address_width + EXTRA_TAG_BITS;
|
||
|
line = cache_params.blockW;
|
||
|
|
||
|
interface_ip.cache_sz = cache_params.wbb_size * line;
|
||
|
interface_ip.line_sz = line;
|
||
|
interface_ip.assoc = cache_params.wbb_assoc;
|
||
|
interface_ip.nbanks = cache_params.wbb_banks;
|
||
|
interface_ip.specific_tag = tag > 0;
|
||
|
interface_ip.tag_w = tag;
|
||
|
|
||
|
if (cache_params.cache_level == L1) {
|
||
|
interface_ip.out_w = interface_ip.line_sz * BITS_PER_BYTE;
|
||
|
} else {
|
||
|
interface_ip.out_w = interface_ip.line_sz * BITS_PER_BYTE / 2;
|
||
|
}
|
||
|
|
||
|
interface_ip.access_mode = cache_params.writeback_buff_access_mode;
|
||
|
interface_ip.obj_func_dyn_energy = 0;
|
||
|
interface_ip.obj_func_dyn_power = 0;
|
||
|
interface_ip.obj_func_leak_power = 0;
|
||
|
interface_ip.obj_func_cycle_t = 1;
|
||
|
interface_ip.is_cache = is_cache;
|
||
|
interface_ip.pure_ram = cache_params.pure_ram;
|
||
|
interface_ip.pure_cam = pure_cam;
|
||
|
interface_ip.throughput = cache_params.throughput;
|
||
|
interface_ip.latency = cache_params.latency;
|
||
|
interface_ip.num_rw_ports = cache_params.wb_buff_rw_ports;
|
||
|
interface_ip.num_rd_ports = cache_params.wb_buff_rd_ports;
|
||
|
interface_ip.num_wr_ports = cache_params.wb_buff_wr_ports;
|
||
|
interface_ip.num_se_rd_ports = cache_params.wb_buff_se_rd_ports;
|
||
|
interface_ip.num_search_ports = cache_params.wb_buff_search_ports;
|
||
|
arrayPtr = new CacheArray(xml_data, &interface_ip,
|
||
|
"Writeback Buffer",
|
||
|
cache_params.device_ty, clockRate,
|
||
|
opt_local, cache_params.core_ty);
|
||
|
children.push_back(arrayPtr);
|
||
|
|
||
|
arrayPtr->tdp_stats.reset();
|
||
|
arrayPtr->tdp_stats.readAc.access = 0;
|
||
|
arrayPtr->tdp_stats.writeAc.access =
|
||
|
arrayPtr->l_ip.num_search_ports;
|
||
|
arrayPtr->tdp_stats.searchAc.access =
|
||
|
arrayPtr->l_ip.num_search_ports;
|
||
|
|
||
|
arrayPtr->rtp_stats.reset();
|
||
|
arrayPtr->rtp_stats.readAc.access = cache_stats.write_misses;
|
||
|
arrayPtr->rtp_stats.writeAc.access = cache_stats.write_misses;
|
||
|
arrayPtr->rtp_stats.searchAc.access = 0;
|
||
|
|
||
|
if (cache_params.dir_ty == SBT) {
|
||
|
arrayPtr->rtp_stats.readAc.access +=
|
||
|
cache_stats.homenode_write_misses;
|
||
|
arrayPtr->rtp_stats.writeAc.access +=
|
||
|
cache_stats.homenode_write_misses;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CacheUnit::computeEnergy() {
|
||
|
McPATComponent::computeEnergy();
|
||
|
}
|
||
|
|
||
|
void CacheUnit::set_cache_param_from_xml_data() {
|
||
|
int level, type;
|
||
|
|
||
|
// Initialization... move this?
|
||
|
memset(&cache_params, 0, sizeof(CacheParameters));
|
||
|
memset(&cache_stats, 0, sizeof(CacheStatistics));
|
||
|
|
||
|
// By default, use the core clock frequency. This can be changed by
|
||
|
// setting the clockrate param in the XML definition of the CacheUnit
|
||
|
clockRate = target_core_clockrate;
|
||
|
XMLCSTR comp_name = xml_data->getAttribute("name");
|
||
|
if (comp_name) {
|
||
|
name = comp_name;
|
||
|
}
|
||
|
|
||
|
int num_children = xml_data->nChildNode("param");
|
||
|
int i;
|
||
|
int tech_type;
|
||
|
int mat_type;
|
||
|
for (i = 0; i < num_children; i++) {
|
||
|
XMLNode* paramNode = xml_data->getChildNodePtr("param", &i);
|
||
|
XMLCSTR node_name = paramNode->getAttribute("name");
|
||
|
XMLCSTR value = paramNode->getAttribute("value");
|
||
|
|
||
|
if (!node_name)
|
||
|
warnMissingParamName(paramNode->getAttribute("id"));
|
||
|
|
||
|
ASSIGN_INT_IF("level", level);
|
||
|
ASSIGN_FP_IF("size", cache_params.capacity);
|
||
|
ASSIGN_FP_IF("block_size", cache_params.blockW);
|
||
|
ASSIGN_FP_IF("assoc", cache_params.assoc);
|
||
|
ASSIGN_FP_IF("num_banks", cache_params.nbanks);
|
||
|
ASSIGN_FP_IF("latency", cache_params.latency);
|
||
|
ASSIGN_FP_IF("throughput", cache_params.throughput);
|
||
|
ASSIGN_INT_IF("miss_buffer_size", cache_params.missb_size);
|
||
|
ASSIGN_INT_IF("fetch_buffer_size", cache_params.fu_size);
|
||
|
ASSIGN_INT_IF("prefetch_buffer_size", cache_params.prefetchb_size);
|
||
|
ASSIGN_INT_IF("writeback_buffer_size", cache_params.wbb_size);
|
||
|
ASSIGN_INT_IF("miss_buffer_assoc", cache_params.missb_assoc);
|
||
|
ASSIGN_INT_IF("fetch_buffer_assoc", cache_params.fu_assoc);
|
||
|
ASSIGN_INT_IF("prefetch_buffer_assoc", cache_params.prefetchb_assoc);
|
||
|
ASSIGN_INT_IF("writeback_buffer_assoc", cache_params.wbb_assoc);
|
||
|
ASSIGN_INT_IF("miss_buffer_banks", cache_params.missb_banks);
|
||
|
ASSIGN_INT_IF("fetch_buffer_banks", cache_params.fu_banks);
|
||
|
ASSIGN_INT_IF("prefetch_buffer_banks", cache_params.prefetchb_banks);
|
||
|
ASSIGN_INT_IF("writeback_buffer_banks", cache_params.wbb_banks);
|
||
|
ASSIGN_ENUM_IF("cache_access_mode",
|
||
|
cache_params.cache_access_mode, Access_mode);
|
||
|
ASSIGN_ENUM_IF("miss_buff_access_mode",
|
||
|
cache_params.miss_buff_access_mode, Access_mode);
|
||
|
ASSIGN_ENUM_IF("fetch_buff_access_mode",
|
||
|
cache_params.fetch_buff_access_mode, Access_mode);
|
||
|
ASSIGN_ENUM_IF("prefetch_buff_access_mode",
|
||
|
cache_params.prefetch_buff_access_mode, Access_mode);
|
||
|
ASSIGN_ENUM_IF("writeback_buff_access_mode",
|
||
|
cache_params.writeback_buff_access_mode, Access_mode);
|
||
|
ASSIGN_INT_IF("cache_rw_ports", cache_params.cache_rw_ports);
|
||
|
ASSIGN_INT_IF("cache_rd_ports", cache_params.cache_rd_ports);
|
||
|
ASSIGN_INT_IF("cache_wr_ports", cache_params.cache_wr_ports);
|
||
|
ASSIGN_INT_IF("cache_se_rd_ports", cache_params.cache_se_rd_ports);
|
||
|
ASSIGN_INT_IF("cache_search_ports", cache_params.cache_search_ports);
|
||
|
ASSIGN_INT_IF("miss_buff_rw_ports", cache_params.miss_buff_rw_ports);
|
||
|
ASSIGN_INT_IF("miss_buff_rd_ports", cache_params.miss_buff_rd_ports);
|
||
|
ASSIGN_INT_IF("miss_buff_wr_ports", cache_params.miss_buff_wr_ports);
|
||
|
ASSIGN_INT_IF("miss_buff_se_rd_ports" ,
|
||
|
cache_params.miss_buff_se_rd_ports);
|
||
|
ASSIGN_INT_IF("miss_buff_search_ports",
|
||
|
cache_params.miss_buff_search_ports);
|
||
|
ASSIGN_INT_IF("fetch_buff_rw_ports", cache_params.fetch_buff_rw_ports);
|
||
|
ASSIGN_INT_IF("fetch_buff_rd_ports", cache_params.fetch_buff_rd_ports);
|
||
|
ASSIGN_INT_IF("fetch_buff_wr_ports", cache_params.fetch_buff_wr_ports);
|
||
|
ASSIGN_INT_IF("fetch_buff_se_rd_ports",
|
||
|
cache_params.fetch_buff_se_rd_ports);
|
||
|
ASSIGN_INT_IF("fetch_buff_search_ports",
|
||
|
cache_params.fetch_buff_search_ports);
|
||
|
ASSIGN_INT_IF("pf_buff_rw_ports", cache_params.pf_buff_rw_ports);
|
||
|
ASSIGN_INT_IF("pf_buff_rd_ports", cache_params.pf_buff_rd_ports);
|
||
|
ASSIGN_INT_IF("pf_buff_wr_ports", cache_params.pf_buff_wr_ports);
|
||
|
ASSIGN_INT_IF("pf_buff_se_rd_ports", cache_params.pf_buff_se_rd_ports);
|
||
|
ASSIGN_INT_IF("pf_buff_search_ports",
|
||
|
cache_params.pf_buff_search_ports);
|
||
|
ASSIGN_INT_IF("wb_buff_rw_ports", cache_params.wb_buff_rw_ports);
|
||
|
ASSIGN_INT_IF("wb_buff_rd_ports", cache_params.wb_buff_rd_ports);
|
||
|
ASSIGN_INT_IF("wb_buff_wr_ports", cache_params.wb_buff_wr_ports);
|
||
|
ASSIGN_INT_IF("wb_buff_se_rd_ports", cache_params.wb_buff_se_rd_ports);
|
||
|
ASSIGN_INT_IF("wb_buff_search_ports",
|
||
|
cache_params.wb_buff_search_ports);
|
||
|
ASSIGN_FP_IF("clockrate", cache_params.clockRate);
|
||
|
ASSIGN_INT_IF("pure_ram", cache_params.pure_ram);
|
||
|
ASSIGN_INT_IF("tech_type", tech_type);
|
||
|
ASSIGN_ENUM_IF("Directory_type", cache_params.dir_ty, Dir_type);
|
||
|
ASSIGN_ENUM_IF("device_type", cache_params.device_ty, Device_ty);
|
||
|
ASSIGN_ENUM_IF("core_type", cache_params.core_ty, Core_type);
|
||
|
ASSIGN_INT_IF("num_cores", cache_params.num_cores);
|
||
|
ASSIGN_INT_IF("wire_mat_type", mat_type);
|
||
|
ASSIGN_ENUM_IF("wire_type", interface_ip.wt, Wire_type);
|
||
|
|
||
|
else {
|
||
|
warnUnrecognizedParam(node_name);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Change from MHz to Hz
|
||
|
cache_params.clockRate *= 1e6;
|
||
|
if (cache_params.clockRate > 0) {
|
||
|
clockRate = cache_params.clockRate;
|
||
|
}
|
||
|
|
||
|
interface_ip.data_arr_ram_cell_tech_type = tech_type;
|
||
|
interface_ip.data_arr_peri_global_tech_type = tech_type;
|
||
|
interface_ip.tag_arr_ram_cell_tech_type = tech_type;
|
||
|
interface_ip.tag_arr_peri_global_tech_type = tech_type;
|
||
|
|
||
|
interface_ip.wire_is_mat_type = mat_type;
|
||
|
interface_ip.wire_os_mat_type = mat_type;
|
||
|
|
||
|
switch(level) {
|
||
|
case 1:
|
||
|
cache_params.cache_level = L1;
|
||
|
break;
|
||
|
case 2:
|
||
|
cache_params.cache_level = L2;
|
||
|
break;
|
||
|
case 3:
|
||
|
cache_params.cache_level = L3;
|
||
|
break;
|
||
|
case 4:
|
||
|
cache_params.cache_level = L1Directory;
|
||
|
break;
|
||
|
case 5:
|
||
|
cache_params.cache_level = L2Directory;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
fprintf(stderr, "ERROR: Unrecognized cache level in %s: %d\n",
|
||
|
name.c_str(), level);
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
cache_stats.use_detailed_stats = false;
|
||
|
|
||
|
num_children = xml_data->nChildNode("stat");
|
||
|
for (i = 0; i < num_children; i++) {
|
||
|
XMLNode* statNode = xml_data->getChildNodePtr("stat", &i);
|
||
|
XMLCSTR node_name = statNode->getAttribute("name");
|
||
|
XMLCSTR value = statNode->getAttribute("value");
|
||
|
|
||
|
if (!node_name)
|
||
|
warnMissingStatName(statNode->getAttribute("id"));
|
||
|
|
||
|
ASSIGN_FP_IF("num_data_array_reads", cache_stats.num_data_array_reads);
|
||
|
ASSIGN_FP_IF("num_data_array_writes",
|
||
|
cache_stats.num_data_array_writes);
|
||
|
ASSIGN_FP_IF("num_tag_array_reads", cache_stats.num_tag_array_reads);
|
||
|
ASSIGN_FP_IF("num_tag_array_writes", cache_stats.num_tag_array_writes);
|
||
|
ASSIGN_FP_IF("duty_cycle", cache_stats.duty_cycle);
|
||
|
ASSIGN_FP_IF("read_accesses", cache_stats.read_accesses);
|
||
|
ASSIGN_FP_IF("write_accesses", cache_stats.write_accesses);
|
||
|
ASSIGN_FP_IF("read_misses", cache_stats.read_misses);
|
||
|
ASSIGN_FP_IF("write_misses", cache_stats.write_misses);
|
||
|
ASSIGN_FP_IF("conflicts", cache_stats.conflicts);
|
||
|
ASSIGN_INT_IF("homenode_read_accesses",
|
||
|
cache_stats.homenode_read_accesses);
|
||
|
ASSIGN_INT_IF("homenode_write_accesses",
|
||
|
cache_stats.homenode_write_accesses);
|
||
|
ASSIGN_INT_IF("homenode_read_misses",
|
||
|
cache_stats.homenode_read_misses);
|
||
|
ASSIGN_INT_IF("homenode_write_misses",
|
||
|
cache_stats.homenode_write_misses);
|
||
|
ASSIGN_FP_IF("homenode_access_scalar",
|
||
|
cache_stats.homenode_access_scalar);
|
||
|
ASSIGN_FP_IF("tdp_read_access_scalar",
|
||
|
cache_stats.tdp_read_access_scalar);
|
||
|
ASSIGN_FP_IF("tdp_write_access_scalar",
|
||
|
cache_stats.tdp_write_access_scalar);
|
||
|
ASSIGN_FP_IF("tdp_sbt_write_access_scalar",
|
||
|
cache_stats.tdp_sbt_write_access_scalar);
|
||
|
ASSIGN_FP_IF("dir_duty_cycle",
|
||
|
cache_stats.dir_duty_cycle);
|
||
|
|
||
|
else {
|
||
|
warnUnrecognizedStat(node_name);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (cache_stats.num_data_array_reads > 0 ||
|
||
|
cache_stats.num_data_array_writes > 0 ||
|
||
|
cache_stats.num_tag_array_reads > 0 ||
|
||
|
cache_stats.num_tag_array_writes > 0) {
|
||
|
cache_stats.use_detailed_stats = true;
|
||
|
calculate_runtime_data_and_tag = true;
|
||
|
}
|
||
|
}
|