summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTor Aamodt <[email protected]>2010-10-16 17:30:52 -0800
committerTor Aamodt <[email protected]>2010-10-16 17:30:52 -0800
commitb577cbcdf229a2c02d1bf8584c6e82be7a14cb33 (patch)
tree373ea8ec8ea8d7d9a7a1df0eaa17f15652df1306 /src
parent2072e7ff2037c19a0c346e60469949c9437569bf (diff)
1. creating cache_config object to encapsulate cache configuration information
(and parse it before creating the simulator objects). 2. creating core_config to hold only features of a shader_core that are high level enough either (a) the functional simulator needs to know about them, or (b) they affect memory *access* generation. 3. in config files only (so far) separate out notion of write-{through,back}, from notion of when a line is allocated... will use this to distinguish different types of caches. passing CUDA 3.1 regression [git-p4: depot-paths = "//depot/gpgpu_sim_research/fermi/distribution/": change = 7870]
Diffstat (limited to 'src')
-rw-r--r--src/abstract_hardware_model.cc178
-rw-r--r--src/abstract_hardware_model.h89
-rw-r--r--src/cuda-sim/ptx_ir.cc2
-rw-r--r--src/cuda-sim/ptx_ir.h2
-rw-r--r--src/cuda-sim/ptx_parser.cc4
-rw-r--r--src/gpgpu-sim/gpu-cache.cc39
-rw-r--r--src/gpgpu-sim/gpu-cache.h78
-rw-r--r--src/gpgpu-sim/gpu-sim.cc55
-rw-r--r--src/gpgpu-sim/gpu-sim.h10
-rw-r--r--src/gpgpu-sim/l2cache.cc23
-rw-r--r--src/gpgpu-sim/shader.cc236
-rw-r--r--src/gpgpu-sim/shader.h95
-rw-r--r--src/gpgpu-sim/stats.h2
-rw-r--r--src/intersim/interconnect_interface.cpp5
14 files changed, 447 insertions, 371 deletions
diff --git a/src/abstract_hardware_model.cc b/src/abstract_hardware_model.cc
index 7b67df9..2134cfc 100644
--- a/src/abstract_hardware_model.cc
+++ b/src/abstract_hardware_model.cc
@@ -24,3 +24,181 @@ gpgpu_t::gpgpu_t()
m_dev_malloc=GLOBAL_HEAP_START;
}
+unsigned core_config::shmem_bank_func(address_type addr, unsigned) const
+{
+ return ((addr/WORD_SIZE) % gpgpu_n_shmem_bank);
+}
+
+unsigned core_config::dcache_bank_func(address_type add, unsigned line_size) const
+{
+ if (gpgpu_no_dl1) return 1; //no banks
+ else return (add / line_size) & (gpgpu_n_cache_bank - 1);
+}
+
+address_type null_tag_func(address_type address, unsigned line_size)
+{
+ return address; //no modification: each address is its own tag.
+}
+
+address_type line_size_based_tag_func(address_type address, unsigned line_size)
+{
+ //gives the tag for an address based on a given line size
+ return ((address) & (~((address_type)line_size - 1)));
+}
+
+void warp_inst_t::get_memory_access_list()
+{
+ // Calculates memory accesses generated by this warp
+ // Returns acesses which are "coalesced"
+ // Does not coalesce nor overlap bank accesses across warp "parts".
+
+ // This is called once per warp_inst_t when the warp_inst_t enters the memory stage.
+ // It produces the set of distinct memory accesses that need to be peformed.
+ // These accessess are then performed over multiple cycles (stalling the pipeline)
+ // if the accessses cannot be performed all at once.
+
+ // In hardware, these accesses would be created at the specific unit handling the type
+ // of memory access. We centralize the logic simply to reduce code duplication.
+
+ // Below, accesses are assigned an "order" based on when that access may be issued.
+ // Accesses with the same order number may occur at the same time: they are to different banks.
+ // Later, when the queue is processed it will evaluate accesses of as many orders as
+ // ports on that cache/shmem.
+ //
+ // Accesses are placed in accessq sorted so that accesses of the same order are adjacent.
+
+ typedef unsigned (core_config::*bank_func_t)(address_type add, unsigned line_size) const;
+ typedef address_type (*tag_func_t)(address_type add, unsigned line_size);
+ bank_func_t bank_func = NULL;
+ tag_func_t tag_func = NULL;
+ unsigned warp_parts = 0;
+ unsigned line_size = 0;
+ bool limit_broadcast = 0;
+ bool global_mem_access = false;
+
+ switch( space.get_type() ) {
+ case shared_space:
+ bank_func = &core_config::shmem_bank_func;
+ tag_func = null_tag_func;
+ warp_parts = m_config->gpgpu_shmem_pipe_speedup;
+ line_size = 1; //shared memory doesn't care about line_size, needs to be at least 1;
+ limit_broadcast = true; // limit broadcasts to single cycle.
+ break;
+ case tex_space:
+ bank_func = &core_config::null_bank_func;
+ tag_func = line_size_based_tag_func;
+ warp_parts = 1;
+ line_size = m_config->gpgpu_cache_texl1_linesize;
+ limit_broadcast = false;
+ break;
+ case const_space: case param_space_kernel:
+ bank_func = &core_config::null_bank_func;
+ tag_func = line_size_based_tag_func;
+ warp_parts = 1;
+ line_size = m_config->gpgpu_cache_constl1_linesize;
+ limit_broadcast = false;
+ break;
+ case global_space: case local_space: case param_space_local:
+ global_mem_access=true;
+ warp_parts = 1;
+ line_size = m_config->gpgpu_cache_dl1_linesize;
+ if( m_config->gpgpu_coalesce_arch == 13 ){
+ warp_parts = 2;
+ if( m_config->gpgpu_no_dl1 ) {
+ // line size is dependant on instruction;
+ switch (data_size) {
+ case 1: line_size = 32; break;
+ case 2: line_size = 64; break;
+ case 4: case 8: case 16: line_size = 128; break;
+ default: assert(0);
+ }
+ }
+ }
+ bank_func = &core_config::dcache_bank_func;
+ tag_func = line_size_based_tag_func;
+ limit_broadcast = false;
+ break;
+ default:
+ abort();
+ }
+
+ // bank_accs tracks bank accesses for sorting into generations;
+ // each entry is (bank #, number of accesses)
+ // the idea is that you can only access a bank a number of times each cycle equal to
+ // its number of ports in one cycle.
+ std::map<unsigned,unsigned> bank_accs;
+
+ // keep track of broadcasts with unique orders if limit_broadcast
+ // the normally calculated orders will never be greater than warp_size
+ unsigned broadcast_order = warp_size();
+ unsigned qbegin = get_accessq_size();
+ unsigned qpartbegin = qbegin;
+ unsigned mem_pipe_size = warp_size() / warp_parts;
+ for (unsigned part = 0; part < warp_size(); part += mem_pipe_size) {
+ for (unsigned i = part; i < part + mem_pipe_size; i++) {
+ if ( !active(i) )
+ continue;
+ new_addr_type addr = get_addr(i);
+ address_type lane_segment_address = tag_func(addr, line_size);
+ unsigned quarter = 0;
+ if( line_size>=4 )
+ quarter = (addr / (line_size/4)) & 3;
+ bool match = false;
+ if( !isatomic() ) { //atomics must have own request
+ for( unsigned j = qpartbegin; j <get_accessq_size(); j++ ) {
+ if (lane_segment_address == accessq(j).addr) {
+ accessq(j).quarter_count[quarter]++;
+ accessq(j).warp_indices.push_back(i);
+ if (limit_broadcast) // two threads access this address, so its a broadcast.
+ accessq(j).order = ++broadcast_order; //do broadcast in its own cycle.
+ match = true;
+ break;
+ }
+ }
+ }
+ if (!match) { // does not match a previous request by another thread, so need a new request
+ assert( space != undefined_space );
+ m_accessq.push_back( mem_access_t( lane_segment_address, line_size, quarter, i) );
+ // Determine Bank Conflicts:
+ unsigned bank = (m_config->*bank_func)(get_addr(i), line_size);
+ // ensure no concurrent bank access accross warp parts.
+ // ie. order will be less than part for all previous loads in previous parts, so:
+ if (bank_accs[bank] < part)
+ bank_accs[bank]=part;
+ accessq_back().order = bank_accs[bank];
+ bank_accs[bank]++;
+ }
+ }
+ qpartbegin = get_accessq_size(); //don't coalesce accross warp parts
+ }
+ //sort requests by order they will be processed in
+ std::stable_sort( m_accessq.begin()+qbegin,m_accessq.end());
+
+ if( global_mem_access ) {
+ // Now that we have the accesses, if we don't have a cache we can adjust request sizes to
+ // include only the data referenced by the threads
+ for (unsigned i = 0; i < get_accessq_size(); i++) {
+ if (m_config->gpgpu_coalesce_arch == 13 && m_config->gpgpu_no_dl1) {
+ // do coalescing here.
+ char* quarter_counts = accessq(i).quarter_count;
+ bool low = quarter_counts[0] or quarter_counts[1];
+ bool high = quarter_counts[2] or quarter_counts[3];
+ if (accessq(i).req_size == 128) {
+ if (low xor high) { //can reduce size
+ accessq(i).req_size = 64;
+ if (high) accessq(i).addr += 64;
+ low = quarter_counts[0] or quarter_counts[2]; //set low and high for next pass
+ high = quarter_counts[1] or quarter_counts[3];
+ }
+ }
+ if (accessq(i).req_size == 64) {
+ if (low xor high) { //can reduce size
+ accessq(i).req_size = 32;
+ if (high) accessq(i).addr += 32;
+ }
+ }
+ }
+ }
+ }
+}
+
diff --git a/src/abstract_hardware_model.h b/src/abstract_hardware_model.h
index b94aa48..ed832b6 100644
--- a/src/abstract_hardware_model.h
+++ b/src/abstract_hardware_model.h
@@ -130,6 +130,29 @@ private:
dim3 m_next_tid;
};
+struct core_config {
+ core_config() { m_valid = false; }
+ virtual void init() = 0;
+
+ bool m_valid;
+ unsigned warp_size;
+
+ // memory request architecture parameters
+ int gpgpu_coalesce_arch;
+ bool gpgpu_no_dl1;
+ int gpgpu_shmem_pipe_speedup;
+ unsigned gpgpu_cache_texl1_linesize;
+ unsigned gpgpu_cache_constl1_linesize;
+ unsigned gpgpu_cache_dl1_linesize;
+
+ static const address_type WORD_SIZE=4;
+ unsigned null_bank_func(address_type, unsigned) const { return 1; }
+ int gpgpu_n_shmem_bank;
+ unsigned shmem_bank_func(address_type addr, unsigned) const;
+ int gpgpu_n_cache_bank;
+ unsigned dcache_bank_func(address_type add, unsigned line_size) const;
+};
+
class core_t {
public:
virtual ~core_t() {}
@@ -430,68 +453,6 @@ enum divergence_support_t {
NUM_SIMD_MODEL
};
-struct shader_core_config
-{
- unsigned warp_size;
- bool gpgpu_perfect_mem;
- enum divergence_support_t model;
- unsigned n_thread_per_shader;
- unsigned max_warps_per_shader;
- unsigned max_cta_per_core; //Limit on number of concurrent CTAs in shader core
- unsigned pdom_sched_type;
- bool gpgpu_no_dl1;
- char *gpgpu_cache_texl1_opt;
- char *gpgpu_cache_constl1_opt;
- char *gpgpu_cache_dl1_opt;
- char *gpgpu_cache_il1_opt;
- unsigned n_mshr_per_shader;
- bool gpgpu_dwf_reg_bankconflict;
- int gpgpu_operand_collector_num_units_sp;
- int gpgpu_operand_collector_num_units_sfu;
- int gpgpu_operand_collector_num_units_mem;
- bool gpgpu_stall_on_use;
- bool gpgpu_cache_wt_through;
- //Shader core resources
- unsigned gpgpu_shmem_size;
- unsigned gpgpu_shader_registers;
- int gpgpu_warpdistro_shader;
- int gpgpu_interwarp_mshr_merge;
- int gpgpu_n_shmem_bank;
- int gpgpu_n_cache_bank;
- int gpgpu_shmem_port_per_bank;
- int gpgpu_cache_port_per_bank;
- int gpgpu_const_port_per_bank;
- int gpgpu_shmem_pipe_speedup;
- unsigned gpgpu_num_reg_banks;
- unsigned gpu_max_cta_per_shader; // TODO: modify this for fermi... computed based upon kernel
- // resource usage; used in shader_core_ctx::translate_local_memaddr
- bool gpgpu_reg_bank_use_warp_id;
- int gpgpu_coalesce_arch;
- bool gpgpu_local_mem_map;
- int gpu_padded_cta_size;
-
- unsigned max_sp_latency;
- unsigned max_sfu_latency;
- unsigned gpgpu_cache_texl1_linesize;
- unsigned gpgpu_cache_constl1_linesize;
- unsigned gpgpu_cache_dl1_linesize;
-
- static const address_type WORD_SIZE=4;
- unsigned null_bank_func(address_type, unsigned) const { return 1; }
- unsigned shmem_bank_func(address_type addr, unsigned) const;
- unsigned dcache_bank_func(address_type add, unsigned line_size) const;
-
- unsigned n_simt_cores_per_cluster;
- unsigned n_simt_clusters;
- unsigned n_simt_ejection_buffer_size;
- unsigned ldst_unit_response_queue_size;
-
- unsigned mem2device(unsigned memid) const { return memid + n_simt_clusters; }
-};
-
-typedef unsigned (shader_core_config::*bank_func_t)(address_type add, unsigned line_size) const;
-typedef address_type (*tag_func_t)(address_type add, unsigned line_size);
-
class warp_inst_t: public inst_t {
public:
// constructors
@@ -501,7 +462,7 @@ public:
m_empty=true;
m_config=NULL;
}
- warp_inst_t( const struct shader_core_config *config )
+ warp_inst_t( const core_config *config )
{
m_uid=0;
assert(config->warp_size<=MAX_WARP_SIZE);
@@ -650,7 +611,7 @@ protected:
unsigned cycles; // used for implementing initiation interval delay
bool m_isatomic;
unsigned m_warp_id;
- const struct shader_core_config *m_config;
+ const core_config *m_config;
std::bitset<MAX_WARP_SIZE> warp_active_mask;
struct per_thread_info {
diff --git a/src/cuda-sim/ptx_ir.cc b/src/cuda-sim/ptx_ir.cc
index 8d7fa11..5def6db 100644
--- a/src/cuda-sim/ptx_ir.cc
+++ b/src/cuda-sim/ptx_ir.cc
@@ -983,7 +983,7 @@ ptx_instruction::ptx_instruction( int opcode,
const char *file,
unsigned line,
const char *source,
- const shader_core_config *config ) : warp_inst_t(config)
+ const core_config *config ) : warp_inst_t(config)
{
m_uid = ++g_num_ptx_inst_uid;
m_PC = 0;
diff --git a/src/cuda-sim/ptx_ir.h b/src/cuda-sim/ptx_ir.h
index 84ded76..cea2e2b 100644
--- a/src/cuda-sim/ptx_ir.h
+++ b/src/cuda-sim/ptx_ir.h
@@ -801,7 +801,7 @@ public:
const char *file,
unsigned line,
const char *source,
- const shader_core_config *config );
+ const core_config *config );
void print_insn() const;
virtual void print_insn( FILE *fp ) const;
diff --git a/src/cuda-sim/ptx_parser.cc b/src/cuda-sim/ptx_parser.cc
index c4486a2..1081c3c 100644
--- a/src/cuda-sim/ptx_parser.cc
+++ b/src/cuda-sim/ptx_parser.cc
@@ -68,8 +68,8 @@
extern "C" int ptx_error( const char *s );
extern int ptx_lineno;
-static const struct shader_core_config *g_shader_core_config;
-void set_ptx_warp_size(const struct shader_core_config * warp_size)
+static const struct core_config *g_shader_core_config;
+void set_ptx_warp_size(const struct core_config * warp_size)
{
g_shader_core_config=warp_size;
}
diff --git a/src/gpgpu-sim/gpu-cache.cc b/src/gpgpu-sim/gpu-cache.cc
index c1acc83..98909ce 100644
--- a/src/gpgpu-sim/gpu-cache.cc
+++ b/src/gpgpu-sim/gpu-cache.cc
@@ -77,39 +77,20 @@ cache_t::~cache_t()
delete m_lines;
}
-cache_t::cache_t( const char *name,
- const char *opt,
- enum cache_write_policy wp,
- int core_id,
- int type_id )
+cache_t::cache_t( const char *name, const cache_config &config, int core_id, int type_id )
+ : m_config(config)
{
- unsigned int nset;
- unsigned int line_sz;
- unsigned int assoc;
- unsigned char policy;
- int ntok = sscanf(opt,"%d:%d:%d:%c", &nset, &line_sz, &assoc, &policy);
- if( ntok != 4 ) {
- printf("GPGPU-Sim uArch: cache configuration string parsing error for cache %s\n", name);
- abort();
- }
- assert(nset && assoc);
-
- unsigned int nlines;
- nlines = nset * assoc;
m_name = name;
- m_nset = nset;
- m_nset_log2 = LOGB2(nset);
- m_assoc = assoc;
- m_line_sz = line_sz;
- m_line_sz_log2 = LOGB2(line_sz);
- m_replacement_policy = policy;
- m_write_policy = wp;
+ m_nset = config.nset;
+ m_nset_log2 = LOGB2(config.nset);
+ m_assoc = config.assoc;
+ m_line_sz = config.line_sz;
+ m_line_sz_log2 = LOGB2(config.line_sz);
+ m_replacement_policy = config.replacement_policy;
+ m_write_policy = config.get_write_policy();
+ unsigned nlines = config.get_num_lines();
m_lines = new cache_block_t[nlines];
- // don't hook up with any logger
- m_core_id = -1;
- m_type_id = -1;
-
// initialize snapshot counters for visualizer
m_prev_snapshot_access = 0;
m_prev_snapshot_miss = 0;
diff --git a/src/gpgpu-sim/gpu-cache.h b/src/gpgpu-sim/gpu-cache.h
index 21cdbbc..89a2ed0 100644
--- a/src/gpgpu-sim/gpu-cache.h
+++ b/src/gpgpu-sim/gpu-cache.h
@@ -101,23 +101,79 @@ struct cache_block_t {
unsigned char status; /* valid, dirty... etc */
};
-#define LRU 'L'
-#define FIFO 'F'
-#define RANDOM 'R'
+enum replacement_policy {
+ LRU,
+ FIFO
+};
-enum cache_write_policy {
+enum write_policy {
no_writes, // line replacement when new line arrives
write_back, // line replacement when new line arrives
write_through // reservation based, use much handle reservation full error.
};
+enum allocation_policy {
+ on_miss,
+ on_fill
+};
+
+class cache_config {
+public:
+ cache_config()
+ {
+ m_valid = false;
+ m_config_string = NULL; // set by option parser
+ }
+ void init()
+ {
+ assert( m_config_string );
+ int ntok = sscanf(m_config_string,"%d:%d:%d:%c:%c:%c", &nset, &line_sz, &assoc, &replacement_policy, &write_policy, &alloc_policy);
+ if( ntok != 6 ) {
+ printf("GPGPU-Sim uArch: cache configuration parsing error (%s)\n", m_config_string );
+ abort();
+ }
+ m_valid = true;
+ }
+ unsigned get_line_sz() const
+ {
+ assert( m_valid );
+ return line_sz;
+ }
+ unsigned get_num_lines() const
+ {
+ assert( m_valid );
+ return nset * assoc;
+ }
+
+ enum write_policy get_write_policy() const
+ {
+ if( write_policy == 'R' )
+ return no_writes;
+ else if( write_policy == 'B' )
+ return write_back;
+ else if( write_policy == 'T' )
+ return write_through;
+ else
+ abort();
+ }
+
+ char *m_config_string;
+
+private:
+ bool m_valid;
+ unsigned int nset;
+ unsigned int line_sz;
+ unsigned int assoc;
+ unsigned char replacement_policy; // 'L' = LRU, 'F' = FIFO, 'R' = RANDOM
+ unsigned char write_policy; // 'T' = write through, 'B' = write back, 'R' = read only
+ unsigned char alloc_policy; // 'm' = allocate on miss, 'f' = allocate on fill
+
+ friend class cache_t;
+};
+
class cache_t {
public:
- cache_t( const char *name,
- const char *opt,
- enum cache_write_policy wp,
- int core_id,
- int type_id);
+ cache_t( const char *name, const cache_config &config, int core_id, int type_id );
~cache_t();
enum cache_request_status access( new_addr_type addr,
@@ -132,10 +188,10 @@ public:
void print( FILE *stream, unsigned &total_access, unsigned &total_misses );
float windowed_cache_miss_rate(int);
void new_window();
- unsigned get_line_sz() const { return m_line_sz; }
private:
std::string m_name;
+ const cache_config &m_config;
cache_block_t *m_lines; /* nbanks x nset x assoc lines in total */
unsigned m_n_banks;
@@ -145,7 +201,7 @@ private:
unsigned m_line_sz; // bytes
unsigned m_line_sz_log2;
- enum cache_write_policy m_write_policy;
+ enum write_policy m_write_policy;
unsigned char m_replacement_policy;
unsigned m_access;
diff --git a/src/gpgpu-sim/gpu-sim.cc b/src/gpgpu-sim/gpu-sim.cc
index dc4241b..b3bc56a 100644
--- a/src/gpgpu-sim/gpu-sim.cc
+++ b/src/gpgpu-sim/gpu-sim.cc
@@ -169,27 +169,27 @@ void gpgpu_sim::reg_options(option_parser_t opp)
"terminates gpu simulation early (0 = no limit)",
"0");
- option_parser_register(opp, "-gpgpu_tex_cache:l1", OPT_CSTR, &m_shader_config->gpgpu_cache_texl1_opt,
+ option_parser_register(opp, "-gpgpu_tex_cache:l1", OPT_CSTR, &m_shader_config->m_L1T_config.m_config_string,
"per-shader L1 texture cache (READ-ONLY) config, i.e., {<nsets>:<linesize>:<assoc>:<repl>|none}",
- "512:64:2:L");
+ "512:64:2:L:R:m");
- option_parser_register(opp, "-gpgpu_const_cache:l1", OPT_CSTR, &m_shader_config->gpgpu_cache_constl1_opt,
+ option_parser_register(opp, "-gpgpu_const_cache:l1", OPT_CSTR, &m_shader_config->m_L1C_config.m_config_string,
"per-shader L1 constant memory cache (READ-ONLY) config, i.e., {<nsets>:<linesize>:<assoc>:<repl>|none}",
- "64:64:2:L");
+ "64:64:2:L:R:f");
option_parser_register(opp, "-gpgpu_no_dl1", OPT_BOOL, &m_shader_config->gpgpu_no_dl1,
"no dl1 cache (voids -gpgpu_cache:dl1 option)",
"0");
- option_parser_register(opp, "-gpgpu_cache:dl1", OPT_CSTR, &m_shader_config->gpgpu_cache_dl1_opt,
+ option_parser_register(opp, "-gpgpu_cache:dl1", OPT_CSTR, &m_shader_config->m_L1D_config.m_config_string,
"shader L1 data cache config, i.e., {<nsets>:<bsize>:<assoc>:<repl>|none}",
"256:128:1:L");
- option_parser_register(opp, "-gpgpu_cache:il1", OPT_CSTR, &m_shader_config->gpgpu_cache_il1_opt,
+ option_parser_register(opp, "-gpgpu_cache:il1", OPT_CSTR, &m_shader_config->m_L1I_config.m_config_string,
"shader L1 instruction cache config, i.e., {<nsets>:<bsize>:<assoc>:<repl>|none}",
- "4:256:4:L");
+ "4:256:4:L:R:f");
- option_parser_register(opp, "-gpgpu_cache:dl2", OPT_CSTR, &m_memory_config->gpgpu_cache_dl2_opt,
+ option_parser_register(opp, "-gpgpu_cache:dl2", OPT_CSTR, &m_memory_config->m_L2_config.m_config_string,
"unified banked L2 data cache config, i.e., {<nsets>:<bsize>:<assoc>:<repl>|none}; disabled by default",
NULL);
@@ -275,10 +275,6 @@ void gpgpu_sim::reg_options(option_parser_t opp)
"Number of groups each warp is divided for shared memory bank conflict check",
"2");
- option_parser_register(opp, "-gpgpu_cache_wt_through", OPT_BOOL, &m_shader_config->gpgpu_cache_wt_through,
- "L1 cache become write through (1=on, 0=off)",
- "0");
-
option_parser_register(opp, "-gpgpu_deadlock_detect", OPT_BOOL, &gpu_deadlock_detect,
"Stop the simulation at deadlock (1=on (default), 0=off)",
"1");
@@ -416,9 +412,9 @@ void gpgpu_sim::next_grid()
gpgpu_sim::gpgpu_sim()
{
m_options_set=false;
- m_shader_config = (shader_core_config*)calloc(1,sizeof(shader_core_config));
- m_shader_stats = (shader_core_stats*)calloc(1,sizeof(shader_core_stats));
- m_memory_config = (memory_config*)calloc(1,sizeof(memory_config));
+ m_shader_config = new shader_core_config();
+ m_memory_config = new memory_config();
+ m_shader_stats = (shader_core_stats*) calloc(1,sizeof(shader_core_stats));
m_memory_stats = NULL;
gpu_sim_insn = 0;
gpu_tot_sim_insn = 0;
@@ -427,7 +423,7 @@ gpgpu_sim::gpgpu_sim()
gpu_deadlock = false;
}
-void set_ptx_warp_size(const struct shader_core_config * warp_size);
+void set_ptx_warp_size(const struct core_config * warp_size);
void gpgpu_sim::init_gpu()
{
@@ -440,9 +436,8 @@ void gpgpu_sim::init_gpu()
&m_shader_config->n_thread_per_shader,
&m_shader_config->warp_size);
set_ptx_warp_size(m_shader_config);
-
- m_shader_config->max_warps_per_shader = m_shader_config->n_thread_per_shader/m_shader_config->warp_size;
- assert( !(m_shader_config->n_thread_per_shader % m_shader_config->warp_size) );
+
+ m_shader_config->init();
m_shader_stats->num_warps_issuable = (int*) calloc(m_shader_config->max_warps_per_shader+1, sizeof(int));
m_shader_stats->num_warps_issuable_pershader = (int*) calloc(m_shader_config->n_simt_clusters*m_shader_config->n_simt_cores_per_cluster, sizeof(int));
@@ -645,7 +640,7 @@ unsigned int gpgpu_sim::run_gpu_sim()
if (m_memory_config->gpgpu_memlatency_stat & GPU_MEMLATSTAT_QUEUELOGS ) {
for (unsigned i=0;i<m_memory_config->m_n_mem;i++)
m_memory_partition_unit[i]->queue_latency_log_dump(stdout);
- if (m_memory_config->gpgpu_cache_dl2_opt) {
+ if (m_memory_config->m_L2_config.get_num_lines() > 0 ) {
for(unsigned i=0; i<m_memory_config->m_n_mem; i++)
m_memory_partition_unit[i]->L2c_log(DUMPLOG);
L2c_latency_log_dump();
@@ -732,9 +727,9 @@ void gpgpu_sim::gpu_print_stat() const
//for (unsigned i=0; i< m_n_shader; i++) printf("%d ", m_sc[i]->get_max_mshr_used() );
//printf("\n");
- if (m_memory_config->gpgpu_cache_dl2_opt) {
+ if (m_memory_config->m_L2_config.get_num_lines())
m_memory_stats->L2c_print_stat( m_memory_config->m_n_mem );
- }
+
for (unsigned i=0;i<m_memory_config->m_n_mem;i++)
m_memory_partition_unit[i]->print(stdout);
/*
@@ -749,7 +744,7 @@ void gpgpu_sim::gpu_print_stat() const
m_sc[i]->L1constcache_print(stdout,a,m);
printf("L1 Const Cache Total Miss Rate = %0.3f\n", (float)m/a);
*/
- if (m_memory_config->gpgpu_cache_dl2_opt)
+ if (m_memory_config->m_L2_config.get_num_lines())
L2c_print_cache_stat();
if (m_shader_config->model == POST_DOMINATOR) {
@@ -956,7 +951,7 @@ void memory_partition_unit::push( mem_fetch* req, unsigned long long cycle )
mem_fetch* mf = m_rop.front().req;
m_rop.pop();
m_stats->memlatstat_icnt2mem_pop(mf);
- if (m_config->gpgpu_cache_dl2_opt) {
+ if (m_config->m_L2_config.get_num_lines()) {
if (m_config->gpgpu_l2_readoverwrite && mf->get_is_write())
m_icnt2cache_write_queue->push(mf,gpu_sim_cycle);
else
@@ -973,7 +968,7 @@ void memory_partition_unit::push( mem_fetch* req, unsigned long long cycle )
mem_fetch* memory_partition_unit::pop()
{
mem_fetch* mf;
- if( m_config->gpgpu_cache_dl2_opt ) {
+ if( m_config->m_L2_config.get_num_lines()) {
mf = L2tocbqueue->pop(gpu_sim_cycle);
if( mf && mf->isatomic() )
mf->do_atomic();
@@ -991,7 +986,7 @@ mem_fetch* memory_partition_unit::pop()
mem_fetch* memory_partition_unit::top()
{
- if (m_config->gpgpu_cache_dl2_opt) {
+ if (m_config->m_L2_config.get_num_lines()) {
return L2tocbqueue->top();
} else {
mem_fetch* mf = m_dram->returnq_top();
@@ -1002,7 +997,7 @@ mem_fetch* memory_partition_unit::top()
void memory_partition_unit::issueCMD()
{
- if (m_config->gpgpu_cache_dl2_opt) {
+ if (m_config->m_L2_config.get_num_lines()) {
// pop completed memory request from dram and push it to dram-to-L2 queue
if ( !(dramtoL2queue->full() || dramtoL2writequeue->full()) ) {
mem_fetch* mf = m_dram->pop();
@@ -1046,8 +1041,8 @@ int gpgpu_sim::next_clock_domain(void)
{
double smallest = min3(core_time,icnt_time,dram_time);
int mask = 0x00;
- if (m_memory_config->gpgpu_cache_dl2_opt //when no-L2 it will never be L2's turn
- && ( l2_time <= smallest) ) {
+ if ( m_memory_config->m_L2_config.get_num_lines() //when no-L2 it will never be L2's turn
+ && (l2_time <= smallest) ) {
smallest = l2_time;
mask |= L2 ;
l2_time += l2_period;
@@ -1157,7 +1152,7 @@ void gpgpu_sim::cycle()
}
if (all_threads_complete) {
printf("Flushed L2 caches...\n");
- if (m_memory_config->gpgpu_cache_dl2_opt) {
+ if (m_memory_config->m_L2_config.get_num_lines()) {
int dlc = 0;
for (unsigned i=0;i<m_memory_config->m_n_mem;i++) {
dlc = m_memory_partition_unit[i]->flushL2();
diff --git a/src/gpgpu-sim/gpu-sim.h b/src/gpgpu-sim/gpu-sim.h
index 762cea2..b881806 100644
--- a/src/gpgpu-sim/gpu-sim.h
+++ b/src/gpgpu-sim/gpu-sim.h
@@ -71,6 +71,8 @@
#include "../abstract_hardware_model.h"
#include "addrdec.h"
+#include "gpu-cache.h"
+#include "shader.h"
#include <list>
#include <stdio.h>
@@ -106,7 +108,7 @@ enum dram_ctrl_t {
struct memory_config {
memory_config()
{
- gpgpu_cache_dl2_opt=NULL;
+ m_valid = false;
gpgpu_dram_timing_opt=NULL;
gpgpu_L2_queue_config=NULL;
}
@@ -117,9 +119,13 @@ struct memory_config {
tRCDWR = tRCD-(WL+1);
tRTW = (CL+(BL/2)+2-WL);
m_address_mapping.init(m_n_mem);
+ m_L2_config.init();
+ m_valid = true;
}
- char *gpgpu_cache_dl2_opt;
+ bool m_valid;
+ cache_config m_L2_config;
+
char *gpgpu_dram_timing_opt;
char *gpgpu_L2_queue_config;
bool gpgpu_l2_readoverwrite;
diff --git a/src/gpgpu-sim/l2cache.cc b/src/gpgpu-sim/l2cache.cc
index 4c77da4..d2b61d7 100644
--- a/src/gpgpu-sim/l2cache.cc
+++ b/src/gpgpu-sim/l2cache.cc
@@ -286,7 +286,7 @@ void memory_partition_unit::cache_cycle()
process_dram_output(); // pop from dram
L2c_push_miss_to_dram(); // push to dram
L2c_service_mem_req(); // pop(push) from(to) icnt2l2(l2toicnt) queues; service l2 requests
- if (m_config->gpgpu_cache_dl2_opt) { // L2 cache enabled
+ if (m_config->m_L2_config.get_num_lines()) { // L2 cache enabled
L2c_update_stat();
L2c_log(SAMPLELOG);
}
@@ -294,12 +294,12 @@ void memory_partition_unit::cache_cycle()
unsigned memory_partition_unit::L2c_get_linesize()
{
- return m_L2cache->get_line_sz();
+ return m_config->m_L2_config.get_line_sz();
}
bool memory_partition_unit::full() const
{
- if (m_config->gpgpu_cache_dl2_opt) {
+ if (m_config->m_L2_config.get_num_lines()) {
return m_icnt2cache_queue->full() || m_icnt2cache_write_queue->full();
} else {
return( m_config->gpgpu_dram_sched_queue_size && m_dram->full() );
@@ -319,13 +319,14 @@ memory_partition_unit::memory_partition_unit( unsigned partition_id,
m_stats=stats;
m_dram = new dram_t(m_id,m_config,m_stats);
- if( m_config->gpgpu_cache_dl2_opt ) {
+ if( m_config->m_L2_config.get_num_lines() ) {
char L2c_name[32];
- snprintf(L2c_name, 32, "L2_%03d", m_id);
- m_L2cache = new cache_t(L2c_name,m_config->gpgpu_cache_dl2_opt, write_through,-1,-1);
- m_mshr = new L2c_mshr(m_L2cache->get_line_sz());
- m_missTracker = new L2c_miss_tracker(m_L2cache->get_line_sz());
- m_accessLocality = new L2c_access_locality(m_L2cache->get_line_sz());
+ snprintf(L2c_name, 32, "L2_bank_%03d", m_id);
+ m_L2cache = new cache_t(L2c_name,m_config->m_L2_config,-1,-1);
+ unsigned l2_line_sz = m_config->m_L2_config.get_line_sz();
+ m_mshr = new L2c_mshr( l2_line_sz );
+ m_missTracker = new L2c_miss_tracker( l2_line_sz );
+ m_accessLocality = new L2c_access_locality( l2_line_sz );
} else {
m_L2cache=NULL;
m_mshr=NULL;
@@ -356,7 +357,7 @@ memory_partition_unit::memory_partition_unit( unsigned partition_id,
L2todram_wbqueue = new fifo_pipeline<mem_fetch>("L2todram_wbqueue", L2c_L2_dm_minlength, L2c_L2_dm_minlength + m_config->gpgpu_dram_sched_queue_size + L2c_dm_L2_length, gpu_sim_cycle);
L2dramout = NULL;
wb_addr=-1;
- if (m_config->gpgpu_cache_dl2_opt && 1) {
+ if (m_config->m_L2_config.get_num_lines() && 1) {
cbtol2_Dist = StatCreate("cbtoL2",1, m_icnt2cache_queue->get_max_len());
cbtoL2wr_Dist = StatCreate("cbtoL2write",1, m_icnt2cache_write_queue->get_max_len());
L2tocb_Dist = StatCreate("L2tocb",1, L2tocbqueue->get_max_len());
@@ -478,7 +479,7 @@ void memory_partition_unit::process_dram_output()
// it is the 1st or nth time trial to writeback
if (wb_addr != (unsigned long long int)-1) {
// performing L2 writeback (no false sharing for memory-side cache)
- int wb_succeed = L2c_write_back(wb_addr, m_L2cache->get_line_sz());
+ int wb_succeed = L2c_write_back(wb_addr, m_config->m_L2_config.get_line_sz());
if (!wb_succeed) {
assert (L2dramout || wb_addr == (unsigned long long int)-1);
return;
diff --git a/src/gpgpu-sim/shader.cc b/src/gpgpu-sim/shader.cc
index a316fbb..2c5de09 100644
--- a/src/gpgpu-sim/shader.cc
+++ b/src/gpgpu-sim/shader.cc
@@ -293,7 +293,7 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu,
class simt_core_cluster *cluster,
unsigned shader_id,
unsigned tpc_id,
- struct shader_core_config *config,
+ const struct shader_core_config *config,
const struct memory_config *mem_config,
struct shader_core_stats *stats )
: m_barriers( config->max_warps_per_shader, config->max_cta_per_core )
@@ -304,8 +304,6 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu,
m_memory_config = mem_config;
m_stats = stats;
unsigned warp_size=config->warp_size;
- config->max_sfu_latency = 32;
- config->max_sp_latency = 32;
m_sid = shader_id;
m_tpc = tpc_id;
@@ -332,7 +330,7 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu,
#define STRSIZE 1024
char L1I_name[STRSIZE];
snprintf(L1I_name, STRSIZE, "L1I_%03d", m_sid);
- m_L1I = new cache_t(L1I_name,m_config->gpgpu_cache_il1_opt,no_writes,m_sid,get_shader_instruction_cache_id());
+ m_L1I = new cache_t(L1I_name,m_config->m_L1I_config,m_sid,get_shader_instruction_cache_id());
m_warp.resize(m_config->max_warps_per_shader, shd_warp_t(this, warp_size));
m_pdom_warp = new pdom_warp_ctx_t*[config->max_warps_per_shader];
@@ -611,9 +609,9 @@ void shader_core_ctx::fetch()
address_type ppc = pc + PROGRAM_MEM_START;
address_type wb=0;
unsigned nbytes=16;
- unsigned offset_in_block = pc & (m_L1I->get_line_sz()-1);
- if( (offset_in_block+nbytes) > m_L1I->get_line_sz() )
- nbytes = (m_L1I->get_line_sz()-offset_in_block);
+ unsigned offset_in_block = pc & (m_config->m_L1I_config.get_line_sz()-1);
+ if( (offset_in_block+nbytes) > m_config->m_L1I_config.get_line_sz() )
+ nbytes = (m_config->m_L1I_config.get_line_sz()-offset_in_block);
enum cache_request_status status = m_L1I->access( (unsigned long long)pc, 0, gpu_sim_cycle, &wb );
if( status != HIT ) {
unsigned req_size = READ_PACKET_SIZE;
@@ -813,182 +811,6 @@ mshr_entry* mshr_shader_unit::add_mshr(mem_access_t &access, warp_inst_t* pinst)
return mshr;
}
-address_type line_size_based_tag_func(address_type address, unsigned line_size)
-{
- //gives the tag for an address based on a given line size
- return ((address) & (~((address_type)line_size - 1)));
-}
-
-address_type null_tag_func(address_type address, unsigned line_size)
-{
- return address; //no modification: each address is its own tag.
-}
-
-unsigned shader_core_config::shmem_bank_func(address_type addr, unsigned) const
-{
- return ((addr/WORD_SIZE) % gpgpu_n_shmem_bank);
-}
-
-unsigned shader_core_config::dcache_bank_func(address_type add, unsigned line_size) const
-{
- if (gpgpu_no_dl1) return 1; //no banks
- else return (add / line_size) & (gpgpu_n_cache_bank - 1);
-}
-
-void warp_inst_t::get_memory_access_list()
-{
- // Calculates memory accesses generated by this warp
- // Returns acesses which are "coalesced"
- // Does not coalesce nor overlap bank accesses across warp "parts".
-
- // This is called once per warp_inst_t when the warp_inst_t enters the memory stage.
- // It produces the set of distinct memory accesses that need to be peformed.
- // These accessess are then performed over multiple cycles (stalling the pipeline)
- // if the accessses cannot be performed all at once.
-
- // In hardware, these accesses would be created at the specific unit handling the type
- // of memory access. We centralize the logic simply to reduce code duplication.
-
- // Below, accesses are assigned an "order" based on when that access may be issued.
- // Accesses with the same order number may occur at the same time: they are to different banks.
- // Later, when the queue is processed it will evaluate accesses of as many orders as
- // ports on that cache/shmem.
- //
- // Accesses are placed in accessq sorted so that accesses of the same order are adjacent.
-
- bank_func_t bank_func = NULL;
- tag_func_t tag_func = NULL;
- unsigned warp_parts = 0;
- unsigned line_size = 0;
- bool limit_broadcast = 0;
- bool global_mem_access = false;
-
- switch( space.get_type() ) {
- case shared_space:
- bank_func = &shader_core_config::shmem_bank_func;
- tag_func = null_tag_func;
- warp_parts = m_config->gpgpu_shmem_pipe_speedup;
- line_size = 1; //shared memory doesn't care about line_size, needs to be at least 1;
- limit_broadcast = true; // limit broadcasts to single cycle.
- break;
- case tex_space:
- bank_func = &shader_core_config::null_bank_func;
- tag_func = line_size_based_tag_func;
- warp_parts = 1;
- line_size = m_config->gpgpu_cache_texl1_linesize;
- limit_broadcast = false;
- break;
- case const_space: case param_space_kernel:
- bank_func = &shader_core_config::null_bank_func;
- tag_func = line_size_based_tag_func;
- warp_parts = 1;
- line_size = m_config->gpgpu_cache_constl1_linesize;
- limit_broadcast = false;
- break;
- case global_space: case local_space: case param_space_local:
- global_mem_access=true;
- warp_parts = 1;
- line_size = m_config->gpgpu_cache_dl1_linesize;
- if( m_config->gpgpu_coalesce_arch == 13 ){
- warp_parts = 2;
- if( m_config->gpgpu_no_dl1 ) {
- // line size is dependant on instruction;
- switch (data_size) {
- case 1: line_size = 32; break;
- case 2: line_size = 64; break;
- case 4: case 8: case 16: line_size = 128; break;
- default: assert(0);
- }
- }
- }
- bank_func = &shader_core_config::dcache_bank_func;
- tag_func = line_size_based_tag_func;
- limit_broadcast = false;
- break;
- default:
- abort();
- }
-
- // bank_accs tracks bank accesses for sorting into generations;
- // each entry is (bank #, number of accesses)
- // the idea is that you can only access a bank a number of times each cycle equal to
- // its number of ports in one cycle.
- std::map<unsigned,unsigned> bank_accs;
-
- // keep track of broadcasts with unique orders if limit_broadcast
- // the normally calculated orders will never be greater than warp_size
- unsigned broadcast_order = warp_size();
- unsigned qbegin = get_accessq_size();
- unsigned qpartbegin = qbegin;
- unsigned mem_pipe_size = warp_size() / warp_parts;
- for (unsigned part = 0; part < warp_size(); part += mem_pipe_size) {
- for (unsigned i = part; i < part + mem_pipe_size; i++) {
- if ( !active(i) )
- continue;
- new_addr_type addr = get_addr(i);
- address_type lane_segment_address = tag_func(addr, line_size);
- unsigned quarter = 0;
- if( line_size>=4 )
- quarter = (addr / (line_size/4)) & 3;
- bool match = false;
- if( !isatomic() ) { //atomics must have own request
- for( unsigned j = qpartbegin; j <get_accessq_size(); j++ ) {
- if (lane_segment_address == accessq(j).addr) {
- accessq(j).quarter_count[quarter]++;
- accessq(j).warp_indices.push_back(i);
- if (limit_broadcast) // two threads access this address, so its a broadcast.
- accessq(j).order = ++broadcast_order; //do broadcast in its own cycle.
- match = true;
- break;
- }
- }
- }
- if (!match) { // does not match a previous request by another thread, so need a new request
- assert( space != undefined_space );
- m_accessq.push_back( mem_access_t( lane_segment_address, line_size, quarter, i) );
- // Determine Bank Conflicts:
- unsigned bank = (m_config->*bank_func)(get_addr(i), line_size);
- // ensure no concurrent bank access accross warp parts.
- // ie. order will be less than part for all previous loads in previous parts, so:
- if (bank_accs[bank] < part)
- bank_accs[bank]=part;
- accessq_back().order = bank_accs[bank];
- bank_accs[bank]++;
- }
- }
- qpartbegin = get_accessq_size(); //don't coalesce accross warp parts
- }
- //sort requests by order they will be processed in
- std::stable_sort( m_accessq.begin()+qbegin,m_accessq.end());
-
- if( global_mem_access ) {
- // Now that we have the accesses, if we don't have a cache we can adjust request sizes to
- // include only the data referenced by the threads
- for (unsigned i = 0; i < get_accessq_size(); i++) {
- if (m_config->gpgpu_coalesce_arch == 13 && m_config->gpgpu_no_dl1) {
- // do coalescing here.
- char* quarter_counts = accessq(i).quarter_count;
- bool low = quarter_counts[0] or quarter_counts[1];
- bool high = quarter_counts[2] or quarter_counts[3];
- if (accessq(i).req_size == 128) {
- if (low xor high) { //can reduce size
- accessq(i).req_size = 64;
- if (high) accessq(i).addr += 64;
- low = quarter_counts[0] or quarter_counts[2]; //set low and high for next pass
- high = quarter_counts[1] or quarter_counts[3];
- }
- }
- if (accessq(i).req_size == 64) {
- if (low xor high) { //can reduce size
- accessq(i).req_size = 32;
- if (high) accessq(i).addr += 32;
- }
- }
- }
- }
- }
-}
-
void ldst_unit::const_cache_access(warp_inst_t &inst)
{
// do cache checks here for each request (non-physical), could be
@@ -1400,11 +1222,41 @@ void ldst_unit::generate_mem_accesses(warp_inst_t &inst)
inst.set_mem_accesses_created();
}
+
+simd_function_unit::simd_function_unit( const shader_core_config *config )
+{
+ m_config=config;
+ m_dispatch_reg = new warp_inst_t(config);
+}
+
+sfu::sfu( warp_inst_t **result_port, const shader_core_config *config )
+ : pipelined_simd_unit(result_port,config,config->max_sfu_latency)
+{
+ m_name = "SFU";
+}
+
+sp_unit::sp_unit( warp_inst_t **result_port, const shader_core_config *config )
+ : pipelined_simd_unit(result_port,config,config->max_sp_latency)
+{
+ m_name = "SP ";
+}
+
+
+pipelined_simd_unit::pipelined_simd_unit( warp_inst_t **result_port, const shader_core_config *config, unsigned max_latency )
+ : simd_function_unit(config)
+{
+ m_result_port = result_port;
+ m_pipeline_depth = max_latency;
+ m_pipeline_reg = new warp_inst_t*[m_pipeline_depth];
+ for( unsigned i=0; i < m_pipeline_depth; i++ )
+ m_pipeline_reg[i] = new warp_inst_t( config );
+}
+
ldst_unit::ldst_unit( simt_core_cluster *cluster,
shader_core_ctx *core,
opndcoll_rfu_t *operand_collector,
Scoreboard *scoreboard,
- shader_core_config *config,
+ const shader_core_config *config,
const memory_config *mem_config,
shader_core_stats *stats,
unsigned sid,
@@ -1425,14 +1277,10 @@ ldst_unit::ldst_unit( simt_core_cluster *cluster,
snprintf(L1D_name, STRSIZE, "L1D_%03d", m_sid);
snprintf(L1T_name, STRSIZE, "L1T_%03d", m_sid);
snprintf(L1C_name, STRSIZE, "L1C_%03d", m_sid);
- enum cache_write_policy L1D_policy = m_config->gpgpu_cache_wt_through?write_through:write_back;
- m_L1D = new cache_t(L1D_name,m_config->gpgpu_cache_dl1_opt,L1D_policy,m_sid,get_shader_normal_cache_id());
- m_L1T = new cache_t(L1T_name,m_config->gpgpu_cache_texl1_opt,no_writes, m_sid,get_shader_texture_cache_id());
- m_L1C = new cache_t(L1C_name,m_config->gpgpu_cache_constl1_opt,no_writes, m_sid,get_shader_constant_cache_id());
- config->gpgpu_cache_dl1_linesize = m_L1D->get_line_sz();
- config->gpgpu_cache_texl1_linesize = m_L1T->get_line_sz();
- config->gpgpu_cache_constl1_linesize = m_L1C->get_line_sz();
- m_cluster->get_gpu()->ptx_set_tex_cache_linesize(m_L1T->get_line_sz());
+ m_L1D = new cache_t(L1D_name,m_config->m_L1D_config,m_sid,get_shader_normal_cache_id());
+ m_L1T = new cache_t(L1T_name,m_config->m_L1T_config,m_sid,get_shader_texture_cache_id());
+ m_L1C = new cache_t(L1C_name,m_config->m_L1C_config,m_sid,get_shader_constant_cache_id());
+ m_cluster->get_gpu()->ptx_set_tex_cache_linesize(m_config->m_L1T_config.get_line_sz());
m_mshr_unit = new mshr_shader_unit(m_config);
m_mem_rc = NO_RC_FAIL;
}
@@ -2401,7 +2249,7 @@ void opndcoll_rfu_t::collector_unit_t::init( unsigned n,
warp_inst_t **port,
unsigned num_banks,
unsigned log2_warp_size,
- const shader_core_config *config,
+ const core_config *config,
opndcoll_rfu_t *rfu )
{
m_rfu=rfu;
@@ -2456,7 +2304,7 @@ class ptx_thread_info *shader_core_ctx::get_thread_state( unsigned hw_thread_id
simt_core_cluster::simt_core_cluster( class gpgpu_sim *gpu,
unsigned cluster_id,
- struct shader_core_config *config,
+ const struct shader_core_config *config,
const struct memory_config *mem_config,
struct shader_core_stats *stats )
{
diff --git a/src/gpgpu-sim/shader.h b/src/gpgpu-sim/shader.h
index 85d5ac1..786913a 100644
--- a/src/gpgpu-sim/shader.h
+++ b/src/gpgpu-sim/shader.h
@@ -662,7 +662,7 @@ private:
warp_inst_t **port,
unsigned num_banks,
unsigned log2_warp_size,
- const shader_core_config *config,
+ const core_config *config,
opndcoll_rfu_t *rfu );
void allocate( warp_inst_t *&pipeline_reg );
@@ -867,11 +867,7 @@ struct ifetch_buffer_t {
class simd_function_unit {
public:
- simd_function_unit( const shader_core_config *config )
- {
- m_config=config;
- m_dispatch_reg = new warp_inst_t(config);
- }
+ simd_function_unit( const shader_core_config *config );
~simd_function_unit() { delete m_dispatch_reg; }
// modifiers
@@ -894,15 +890,7 @@ protected:
class pipelined_simd_unit : public simd_function_unit {
public:
- pipelined_simd_unit( warp_inst_t **result_port, const shader_core_config *config, unsigned max_latency )
- : simd_function_unit(config)
- {
- m_result_port = result_port;
- m_pipeline_depth = max_latency;
- m_pipeline_reg = new warp_inst_t*[m_pipeline_depth];
- for( unsigned i=0; i < m_pipeline_depth; i++ )
- m_pipeline_reg[i] = new warp_inst_t( config );
- }
+ pipelined_simd_unit( warp_inst_t **result_port, const shader_core_config *config, unsigned max_latency );
//modifiers
virtual void cycle()
@@ -948,8 +936,7 @@ protected:
class sfu : public pipelined_simd_unit
{
public:
- sfu( warp_inst_t **result_port, const shader_core_config *config )
- : pipelined_simd_unit(result_port,config,config->max_sfu_latency) { m_name = "SFU"; }
+ sfu( warp_inst_t **result_port, const shader_core_config *config );
virtual bool can_issue( const warp_inst_t &inst ) const
{
switch(inst.op) {
@@ -964,8 +951,7 @@ public:
class sp_unit : public pipelined_simd_unit
{
public:
- sp_unit( warp_inst_t **result_port, const shader_core_config *config )
- : pipelined_simd_unit(result_port,config,config->max_sp_latency) { m_name = "SP "; }
+ sp_unit( warp_inst_t **result_port, const shader_core_config *config );
virtual bool can_issue( const warp_inst_t &inst ) const
{
switch(inst.op) {
@@ -987,7 +973,7 @@ public:
shader_core_ctx *core,
opndcoll_rfu_t *operand_collector,
Scoreboard *scoreboard,
- shader_core_config *config,
+ const shader_core_config *config,
const memory_config *mem_config,
shader_core_stats *stats,
unsigned sid, unsigned tpc );
@@ -1066,6 +1052,71 @@ enum pipeline_stage_name_t {
N_PIPELINE_STAGES
};
+struct shader_core_config : public core_config
+{
+ void init()
+ {
+ max_warps_per_shader = n_thread_per_shader/warp_size;
+ assert( !(n_thread_per_shader % warp_size) );
+
+ max_sfu_latency = 32;
+ max_sp_latency = 32;
+
+ m_L1I_config.init();
+ m_L1T_config.init();
+ m_L1C_config.init();
+ m_L1D_config.init();
+ gpgpu_cache_dl1_linesize = m_L1D_config.get_line_sz();
+ gpgpu_cache_texl1_linesize = m_L1T_config.get_line_sz();
+ gpgpu_cache_constl1_linesize = m_L1C_config.get_line_sz();
+
+ m_valid = true;
+ }
+
+ bool gpgpu_perfect_mem;
+ enum divergence_support_t model;
+ unsigned n_thread_per_shader;
+ unsigned max_warps_per_shader;
+ unsigned max_cta_per_core; //Limit on number of concurrent CTAs in shader core
+ unsigned pdom_sched_type;
+
+ cache_config m_L1I_config;
+ cache_config m_L1T_config;
+ cache_config m_L1C_config;
+ cache_config m_L1D_config;
+
+ unsigned n_mshr_per_shader;
+ bool gpgpu_dwf_reg_bankconflict;
+ int gpgpu_operand_collector_num_units_sp;
+ int gpgpu_operand_collector_num_units_sfu;
+ int gpgpu_operand_collector_num_units_mem;
+ bool gpgpu_stall_on_use;
+ //Shader core resources
+ unsigned gpgpu_shmem_size;
+ unsigned gpgpu_shader_registers;
+ int gpgpu_warpdistro_shader;
+ int gpgpu_interwarp_mshr_merge;
+ int gpgpu_shmem_port_per_bank;
+ int gpgpu_cache_port_per_bank;
+ int gpgpu_const_port_per_bank;
+ unsigned gpgpu_num_reg_banks;
+ unsigned gpu_max_cta_per_shader; // TODO: modify this for fermi... computed based upon kernel
+ // resource usage; used in shader_core_ctx::translate_local_memaddr
+ bool gpgpu_reg_bank_use_warp_id;
+ bool gpgpu_local_mem_map;
+ int gpu_padded_cta_size;
+
+ unsigned max_sp_latency;
+ unsigned max_sfu_latency;
+
+ unsigned n_simt_cores_per_cluster;
+ unsigned n_simt_clusters;
+ unsigned n_simt_ejection_buffer_size;
+ unsigned ldst_unit_response_queue_size;
+
+ unsigned mem2device(unsigned memid) const { return memid + n_simt_clusters; }
+};
+
class shader_core_ctx : public core_t
{
public:
@@ -1073,7 +1124,7 @@ public:
class simt_core_cluster *cluster,
unsigned shader_id,
unsigned tpc_id,
- struct shader_core_config *config,
+ const struct shader_core_config *config,
const struct memory_config *mem_config,
struct shader_core_stats *stats );
@@ -1190,7 +1241,7 @@ class simt_core_cluster {
public:
simt_core_cluster( class gpgpu_sim *gpu,
unsigned cluster_id,
- struct shader_core_config *config,
+ const struct shader_core_config *config,
const struct memory_config *mem_config,
struct shader_core_stats *stats );
diff --git a/src/gpgpu-sim/stats.h b/src/gpgpu-sim/stats.h
index 20acfa1..8115eae 100644
--- a/src/gpgpu-sim/stats.h
+++ b/src/gpgpu-sim/stats.h
@@ -90,7 +90,7 @@ enum mem_stage_stall_type {
N_MEM_STAGE_STALL_TYPE
};
-struct shader_core_stats
+struct shader_core_stats
{
unsigned int gpgpu_n_load_insn;
unsigned int gpgpu_n_store_insn;
diff --git a/src/intersim/interconnect_interface.cpp b/src/intersim/interconnect_interface.cpp
index 5d3d55c..1b4ffea 100644
--- a/src/intersim/interconnect_interface.cpp
+++ b/src/intersim/interconnect_interface.cpp
@@ -465,9 +465,8 @@ void init_interconnect (char* config_file,
if (icnt_config.GetInt("input_buf_size")) {
input_buffer_capacity = icnt_config.GetInt("input_buf_size");
} else {
- if (shader_config->gpgpu_cache_dl1_opt && !shader_config->gpgpu_no_dl1) {
- int l1cache_linesize = 32;
- sscanf(shader_config->gpgpu_cache_dl1_opt,"%*d:%d:%*d:%*c", &l1cache_linesize);
+ if (shader_config->m_L1D_config.get_num_lines() && !shader_config->gpgpu_no_dl1) {
+ int l1cache_linesize = shader_config->m_L1D_config.get_line_sz();
input_buffer_capacity = shader_config->n_thread_per_shader*(l1cache_linesize/_flit_size+(int)ceil(8.0f/_flit_size));
} else {
input_buffer_capacity = shader_config->n_thread_per_shader*((int)ceil(8.0f/_flit_size));