summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTor Aamodt <[email protected]>2010-10-10 21:19:52 -0800
committerTor Aamodt <[email protected]>2010-10-10 21:19:52 -0800
commitb3ce70a797756285ea9b15b3e5cf515d8b6a2b63 (patch)
tree5b84d880e646f80611cc5b01931fdde622c5e06c /src
parent0151c5c566dcbcbb962acf35c86a8e0f4a4a6eb6 (diff)
1. create function unit classes for SP, SFU, LD/ST.
2. refactor memory stage into a ld/st function unit 3. refactor memory access generation (moved into warp_inst_t class) the above should make supporting fermi uarch much easier passing CUDA 3.1 regression still need to... (a) update scoreboard to keep count of outstanding memory requests and use operand collector for writebacks into register file (b) add back shared memory pipeline delay (c) remove use of MSHR's for non-cached global/local accesses (d) replace texture cache with a split tag/data array pipe (e) re-implement memory_partition stuff so it makes more sense [git-p4: depot-paths = "//depot/gpgpu_sim_research/fermi/distribution/": change = 7844]
Diffstat (limited to 'src')
-rw-r--r--src/abstract_hardware_model.cc4
-rw-r--r--src/abstract_hardware_model.h107
-rw-r--r--src/cuda-sim/cuda-sim.cc102
-rw-r--r--src/cuda-sim/ptx_ir.cc3
-rw-r--r--src/cuda-sim/ptx_ir.h11
-rw-r--r--src/cuda-sim/ptx_parser.cc10
-rw-r--r--src/gpgpu-sim/gpu-sim.cc52
-rw-r--r--src/gpgpu-sim/gpu-sim.h47
-rw-r--r--src/gpgpu-sim/mem_fetch.cc2
-rw-r--r--src/gpgpu-sim/shader.cc893
-rw-r--r--src/gpgpu-sim/shader.h345
-rw-r--r--src/gpgpu-sim/stats.h3
-rw-r--r--src/gpgpu-sim/visualizer.cc3
13 files changed, 893 insertions, 689 deletions
diff --git a/src/abstract_hardware_model.cc b/src/abstract_hardware_model.cc
index b943a76..619b9b7 100644
--- a/src/abstract_hardware_model.cc
+++ b/src/abstract_hardware_model.cc
@@ -23,7 +23,3 @@ gpgpu_t::gpgpu_t()
m_dev_malloc=GLOBAL_HEAP_START;
}
-void warp_inst_t::sort_accessq( unsigned qbegin )
-{
- std::stable_sort( m_accessq.begin()+qbegin,m_accessq.end());
-}
diff --git a/src/abstract_hardware_model.h b/src/abstract_hardware_model.h
index 5ccdaf3..41fe025 100644
--- a/src/abstract_hardware_model.h
+++ b/src/abstract_hardware_model.h
@@ -386,7 +386,8 @@ public:
is_vectorin=0;
is_vectorout=0;
space = memory_space_t();
- cycles = 0;
+ latency = 1;
+ initiation_interval = 1;
for( unsigned i=0; i < MAX_REG_OPERANDS; i++ )
arch_reg[i]=-1;
isize=0;
@@ -411,7 +412,8 @@ public:
int pred; // predicate register number
int ar1, ar2;
int arch_reg[MAX_REG_OPERANDS]; // register number for bank conflict evaluation
- unsigned cycles; // 1/throughput for instruction
+ unsigned latency; // operation latency
+ unsigned initiation_interval;
unsigned data_size; // what is the size of the word being operated on?
memory_space_t space;
@@ -423,16 +425,77 @@ protected:
#define MAX_WARP_SIZE 32
+enum divergence_support_t {
+ POST_DOMINATOR = 1,
+ 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;
+};
+
+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
- warp_inst_t( unsigned warp_size )
+ warp_inst_t( const struct shader_core_config *config )
{
- assert(warp_size<=MAX_WARP_SIZE);
- m_warp_size=warp_size;
+ assert(config->warp_size<=MAX_WARP_SIZE);
+ m_config=config;
m_empty=true;
m_isatomic=false;
m_per_scalar_thread_valid=false;
+ m_mem_accesses_created=false;
}
// modifiers
@@ -452,18 +515,19 @@ public:
}
void issue( unsigned mask, unsigned warp_id, unsigned long long cycle )
{
- for (int i=(int)m_warp_size-1; i>=0; i--) {
+ for (int i=(int)m_config->warp_size-1; i>=0; i--) {
if( mask & (1<<i) )
warp_active_mask.set(i);
}
m_warp_id = warp_id;
issue_cycle = cycle;
+ cycles = initiation_interval;
m_empty=false;
}
void set_addr( unsigned n, new_addr_type addr )
{
if( !m_per_scalar_thread_valid ) {
- m_per_scalar_thread.resize(m_warp_size);
+ m_per_scalar_thread.resize(m_config->warp_size);
m_per_scalar_thread_valid=true;
}
m_per_scalar_thread[n].memreqaddr = addr;
@@ -474,7 +538,7 @@ public:
class ptx_thread_info *thread )
{
if( !m_per_scalar_thread_valid ) {
- m_per_scalar_thread.resize(m_warp_size);
+ m_per_scalar_thread.resize(m_config->warp_size);
m_per_scalar_thread_valid=true;
m_isatomic=true;
}
@@ -487,11 +551,11 @@ public:
warp_active_mask.reset();
for( std::vector<unsigned>::iterator i=active.begin(); i!=active.end(); ++i ) {
unsigned t = *i;
- assert( t < m_warp_size );
+ assert( t < m_config->warp_size );
warp_active_mask.set(t);
}
if( m_isatomic ) {
- for( unsigned i=0; i < m_warp_size; i++ ) {
+ for( unsigned i=0; i < m_config->warp_size; i++ ) {
if( !warp_active_mask.test(i) ) {
m_per_scalar_thread[i].callback.function = NULL;
m_per_scalar_thread[i].callback.instruction = NULL;
@@ -504,12 +568,13 @@ public:
{
warp_active_mask.reset(lane_id);
}
+ void get_memory_access_list();
// accessors
virtual void print_insn(FILE *fp) const
{
fprintf(fp," [inst @ pc=0x%04x] ", pc );
- for (int i=(int)m_warp_size-1; i>=0; i--)
+ for (int i=(int)m_config->warp_size-1; i>=0; i--)
fprintf(fp, "%c", ((warp_active_mask[i])?'1':'0') );
}
bool active( unsigned thread ) const { return warp_active_mask.test(thread); }
@@ -533,22 +598,32 @@ public:
bool isatomic() const { return m_isatomic; }
- bool mem_accesses_computed() const { return m_mem_accesses_created; }
- void set_mem_accesses_computed() { m_mem_accesses_created=true; }
+ unsigned warp_size() const { return m_config->warp_size; }
+
+ bool mem_accesses_created() const { return m_mem_accesses_created; }
+ void set_mem_accesses_created() { m_mem_accesses_created=true; }
bool accessq_empty() const { return m_accessq.empty(); }
unsigned get_accessq_size() const { return m_accessq.size(); }
mem_access_t &accessq( unsigned n ) { return m_accessq[n]; }
mem_access_t &accessq_back() { return m_accessq.back(); }
- void accessq_push_back( const mem_access_t &req ) { m_accessq.push_back(req); }
void accessq_pop_back() { m_accessq.pop_back(); }
- void sort_accessq( unsigned qbegin );
+
+ bool dispatch_delay()
+ {
+ if( cycles > 0 )
+ cycles--;
+ return cycles > 0;
+ }
+
+ void print( FILE *fout ) const;
protected:
bool m_empty;
unsigned long long issue_cycle;
+ unsigned cycles; // used for implementing initiation interval delay
bool m_isatomic;
unsigned m_warp_id;
- unsigned m_warp_size;
+ const struct shader_core_config *m_config;
std::bitset<MAX_WARP_SIZE> warp_active_mask;
struct per_thread_info {
diff --git a/src/cuda-sim/cuda-sim.cc b/src/cuda-sim/cuda-sim.cc
index 89e89e8..e61659c 100644
--- a/src/cuda-sim/cuda-sim.cc
+++ b/src/cuda-sim/cuda-sim.cc
@@ -438,61 +438,64 @@ void ptx_print_insn( address_type pc, FILE *fp )
finfo->print_insn(pc,fp);
}
-static void get_opcode_info( const ptx_instruction *pI, unsigned opcode, unsigned *cycles, op_type *op )
+void ptx_instruction::get_opcode_info()
{
- *op = ALU_OP;
- *cycles = 1;
- if ( opcode == LD_OP ) {
- *op = LOAD_OP;
- } else if ( opcode == ST_OP ) {
- *op = STORE_OP;
- } else if ( opcode == BRA_OP ) {
- *op = BRANCH_OP;
- } else if ( opcode == BREAKADDR_OP ) {
- *op = BRANCH_OP;
- } else if ( opcode == TEX_OP ) {
- *op = LOAD_OP;
- } else if ( opcode == ATOM_OP ) {
- *op = LOAD_OP; // timing model treats this like load for now
- } else if ( opcode == BAR_OP ) {
- *op = BARRIER_OP;
- } else if ( opcode == MEMBAR_OP )
- *op = MEMORY_BARRIER_OP;
-
- // Floating point instructions
- if( opcode == RCP_OP ) {
- *cycles = 2;
- *op = SFU_OP;
- } else if ( opcode == LG2_OP || opcode == RSQRT_OP ) {
- *cycles = 4;
- *op = SFU_OP;
- } else if( opcode == SQRT_OP || opcode == SIN_OP || opcode == COS_OP || opcode == EX2_OP ) {
- *cycles = 4;
- *op = SFU_OP;
- } else if( opcode == DIV_OP ) {
+ op = ALU_OP;
+ initiation_interval = latency = 1;
+ switch( m_opcode ) {
+ case LD_OP: op = LOAD_OP; break;
+ case ST_OP: op = STORE_OP; break;
+ case BRA_OP: op = BRANCH_OP; break;
+ case BREAKADDR_OP: op = BRANCH_OP; break;
+ case TEX_OP: op = LOAD_OP; break;
+ case ATOM_OP: op = LOAD_OP; break;
+ case BAR_OP: op = BARRIER_OP; break;
+ case MEMBAR_OP: op = MEMORY_BARRIER_OP; break;
+ case RCP_OP:
+ latency = 2;
+ initiation_interval = 2;
+ op = SFU_OP;
+ break;
+ case LG2_OP: case RSQRT_OP:
+ latency = 4;
+ initiation_interval = 4;
+ op = SFU_OP;
+ break;
+ case SQRT_OP: case SIN_OP: case COS_OP: case EX2_OP:
+ latency = 10;
+ initiation_interval = 4;
+ op = SFU_OP;
+ break;
+ case DIV_OP:
// Floating point only
- if( pI->get_type() == F32_TYPE || pI->get_type() == F64_TYPE ) {
- *cycles = 4;
- *op = SFU_OP;
+ if( get_type() == F32_TYPE || get_type() == F64_TYPE ) {
+ latency = 10;
+ initiation_interval = 4;
+ op = SFU_OP;
}
- }
- // Integer instructions
- if( opcode == MUL_OP ) {
- if( pI->get_type() == B32_TYPE || pI->get_type() == U32_TYPE || pI->get_type() == S32_TYPE ) {
+ break;
+ case MUL_OP:
+ if( get_type() == B32_TYPE || get_type() == U32_TYPE || get_type() == S32_TYPE ) {
// 32-bit integer instruction
- *cycles = 5;
- *op = SFU_OP;
+ latency = 24;
+ initiation_interval = 5;
+ op = SFU_OP;
}
- if( pI->get_type() == F32_TYPE || pI->get_type() == F64_TYPE )
- *op = ALU_SFU_OP;
- }
- if( opcode == MAD_OP ) {
- if( pI->get_type() == B32_TYPE || pI->get_type() == U32_TYPE || pI->get_type() == S32_TYPE ) {
+ if( get_type() == F32_TYPE || get_type() == F64_TYPE ) {
+ op = ALU_SFU_OP;
+ }
+ break;
+ case MAD_OP:
+ if( get_type() == B32_TYPE || get_type() == U32_TYPE || get_type() == S32_TYPE ) {
// 32-bit integer instruction
- *cycles = 6;
- *op = SFU_OP;
+ latency = 30;
+ initiation_interval = 6;
+ op = SFU_OP;
}
- }
+ break;
+ default:
+ break;
+ }
}
void ptx_thread_info::ptx_fetch_inst( inst_t &inst ) const
@@ -519,7 +522,6 @@ void ptx_instruction::pre_decode()
ar2 = 0;
bool has_dst = false ;
- int opcode = get_opcode(); //determine the opcode
switch ( get_opcode() ) {
#define OP_DEF(OP,FUNC,STR,DST,CLASSIFICATION) case OP: has_dst = (DST!=0); break;
@@ -530,7 +532,7 @@ void ptx_instruction::pre_decode()
break;
}
- get_opcode_info(this,opcode,&cycles,&op);
+ get_opcode_info();
// Get register operands
int n=0,m=0;
diff --git a/src/cuda-sim/ptx_ir.cc b/src/cuda-sim/ptx_ir.cc
index 8172f80..8d7fa11 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,
- unsigned warp_size ) : warp_inst_t(warp_size)
+ const shader_core_config *config ) : warp_inst_t(config)
{
m_uid = ++g_num_ptx_inst_uid;
m_PC = 0;
@@ -1011,7 +1011,6 @@ ptx_instruction::ptx_instruction( int opcode,
m_geom_spec = 0;
m_vector_spec = 0;
m_atomic_spec = 0;
- m_warp_size = warp_size;
m_membar_level = 0;
m_inst_size = 8; // bytes
diff --git a/src/cuda-sim/ptx_ir.h b/src/cuda-sim/ptx_ir.h
index 07f2e36..84ded76 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,
- unsigned warp_size );
+ const shader_core_config *config );
void print_insn() const;
virtual void print_insn( FILE *fp ) const;
@@ -940,7 +940,6 @@ public:
enum vote_mode_t { vote_any, vote_all, vote_uni };
enum vote_mode_t vote_mode() const { return m_vote_mode; }
- unsigned warp_size() const { return m_warp_size; }
int membar_level() const { return m_membar_level; }
bool has_memory_read() const {
@@ -966,6 +965,7 @@ public:
}
private:
+ void get_opcode_info();
basic_block_t *m_basic_block;
unsigned m_uid;
@@ -973,7 +973,6 @@ private:
std::string m_source_file;
unsigned m_source_line;
std::string m_source;
- unsigned m_warp_size;
const symbol *m_pred;
bool m_neg_pred;
@@ -1176,8 +1175,10 @@ public:
static const ptx_instruction* pc_to_instruction(unsigned pc)
{
- assert(pc <= s_g_pc_to_insn.size());
- return s_g_pc_to_insn[pc];
+ if( pc < s_g_pc_to_insn.size() )
+ return s_g_pc_to_insn[pc];
+ else
+ return NULL;
}
unsigned local_mem_framesize() const
{
diff --git a/src/cuda-sim/ptx_parser.cc b/src/cuda-sim/ptx_parser.cc
index 5a65481..c4486a2 100644
--- a/src/cuda-sim/ptx_parser.cc
+++ b/src/cuda-sim/ptx_parser.cc
@@ -68,10 +68,10 @@
extern "C" int ptx_error( const char *s );
extern int ptx_lineno;
-static unsigned g_warp_size;
-void set_ptx_warp_size(unsigned warp_size)
+static const struct shader_core_config *g_shader_core_config;
+void set_ptx_warp_size(const struct shader_core_config * warp_size)
{
- g_warp_size=warp_size;
+ g_shader_core_config=warp_size;
}
static bool g_debug_ir_generation=false;
@@ -292,7 +292,7 @@ const ptx_instruction *ptx_instruction_lookup( const char *filename, unsigned li
void add_instruction()
{
DPRINTF("add_instruction: %s", ((g_opcode>0)?g_opcode_string[g_opcode]:"<label>") );
- assert( g_warp_size != 0 );
+ assert( g_shader_core_config != 0 );
ptx_instruction *i = new ptx_instruction( g_opcode,
g_pred,
g_neg_pred,
@@ -306,7 +306,7 @@ void add_instruction()
g_filename,
ptx_lineno,
linebuf,
- g_warp_size );
+ g_shader_core_config );
g_instructions.push_back(i);
g_inst_lookup[g_filename][ptx_lineno] = i;
init_instruction_state();
diff --git a/src/gpgpu-sim/gpu-sim.cc b/src/gpgpu-sim/gpu-sim.cc
index 7646ee7..9b71aec 100644
--- a/src/gpgpu-sim/gpu-sim.cc
+++ b/src/gpgpu-sim/gpu-sim.cc
@@ -374,12 +374,15 @@ void gpgpu_sim::reg_options(option_parser_t opp)
&m_ptx_force_max_capability,
"Force maximum compute capability",
"0");
- option_parser_register(opp, "-gpgpu_operand_collector_num_units", OPT_INT32, &m_shader_config->gpgpu_operand_collector_num_units,
- "number of collecture units (default = 4)",
+ option_parser_register(opp, "-gpgpu_operand_collector_num_units_sp", OPT_INT32, &m_shader_config->gpgpu_operand_collector_num_units_sp,
+ "number of collector units (default = 4)",
"4");
option_parser_register(opp, "-gpgpu_operand_collector_num_units_sfu", OPT_INT32, &m_shader_config->gpgpu_operand_collector_num_units_sfu,
- "number of collecture units (default = 4)",
+ "number of collector units (default = 4)",
"4");
+ option_parser_register(opp, "-gpgpu_operand_collector_num_units_mem", OPT_INT32, &m_shader_config->gpgpu_operand_collector_num_units_mem,
+ "number of collector units (default = 2)",
+ "2");
option_parser_register(opp, "-gpgpu_coalesce_arch", OPT_INT32, &m_shader_config->gpgpu_coalesce_arch,
"Coalescing arch (default = 13, anything else is off for now)",
"13");
@@ -453,7 +456,7 @@ gpgpu_sim::gpgpu_sim()
gpu_deadlock = false;
}
-void set_ptx_warp_size(unsigned warp_size);
+void set_ptx_warp_size(const struct shader_core_config * warp_size);
void gpgpu_sim::init_gpu()
{
@@ -465,7 +468,7 @@ void gpgpu_sim::init_gpu()
int ntok = sscanf(gpgpu_shader_core_pipeline_opt,"%d:%d",
&m_shader_config->n_thread_per_shader,
&m_shader_config->warp_size);
- set_ptx_warp_size(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) );
@@ -743,8 +746,6 @@ unsigned int gpgpu_sim::run_gpu_sim()
void gpgpu_sim::gpu_print_stat() const
{
- unsigned i;
-
printf("gpu_sim_cycle = %lld\n", gpu_sim_cycle);
printf("gpu_sim_insn = %lld\n", gpu_sim_insn);
printf("gpu_sim_no_ld_const_insn = %lld\n", m_shader_stats->gpu_sim_insn_no_ld_const);
@@ -796,16 +797,16 @@ void gpgpu_sim::gpu_print_stat() const
printf("gpgpu_n_mem_texture = %d\n", m_shader_stats->gpgpu_n_mem_texture);
printf("gpgpu_n_mem_const = %d\n", m_shader_stats->gpgpu_n_mem_const);
- printf("max_n_mshr_used = ");
- for (unsigned i=0; i< m_n_shader; i++) printf("%d ", m_sc[i]->get_max_mshr_used() );
- printf("\n");
+ //printf("max_n_mshr_used = ");
+ //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) {
m_memory_stats->L2c_print_stat( m_n_mem );
}
for (unsigned i=0;i<m_n_mem;i++)
m_memory_partition_unit[i]->print(stdout);
-
+/*
unsigned a,m;
for (unsigned i=0, a=0, m=0;i<m_n_shader;i++)
m_sc[i]->L1cache_print(stdout,a,m);
@@ -816,7 +817,7 @@ void gpgpu_sim::gpu_print_stat() const
for (i=0,a=0,m=0;i<m_n_shader;i++)
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)
L2c_print_cache_stat();
@@ -963,6 +964,20 @@ unsigned char gpgpu_sim::check_icnt_has_buffer(unsigned long long int addr, int
int gpgpu_sim::issue_mf_from_fq(mem_fetch *mf)
{
+ // stats
+ if (mf->get_is_write()) m_shader_stats->made_write_mfs++;
+ else m_shader_stats->made_read_mfs++;
+ switch (mf->get_mem_acc()) {
+ case CONST_ACC_R: m_shader_stats->gpgpu_n_mem_const++; break;
+ case TEXTURE_ACC_R: m_shader_stats->gpgpu_n_mem_texture++; break;
+ case GLOBAL_ACC_R: m_shader_stats->gpgpu_n_mem_read_global++; break;
+ case GLOBAL_ACC_W: m_shader_stats->gpgpu_n_mem_write_global++; break;
+ case LOCAL_ACC_R: m_shader_stats->gpgpu_n_mem_read_local++; break;
+ case LOCAL_ACC_W: m_shader_stats->gpgpu_n_mem_write_local++; break;
+ case INST_ACC_R: m_shader_stats->gpgpu_n_mem_read_inst++; break;
+ default: assert(0);
+ }
+
unsigned destination = mf->get_tlx_addr().chip;
unsigned tpc_id = mf->get_tpc();
mf->set_status(IN_ICNT2MEM,MR_ICNT_PUSHED,gpu_sim_cycle+gpu_tot_sim_cycle);
@@ -985,17 +1000,11 @@ void shader_core_ctx::fill_shd_L1_with_new_line(mem_fetch * mf)
m_L1I->shd_cache_fill(mf->get_addr(),gpu_sim_cycle+gpu_tot_sim_cycle);
m_warp[mf->get_wid()].clear_imiss_pending();
delete mf->get_mshr();
+ delete mf;
} else {
- m_mshr_unit->mshr_return_from_mem(mf->get_mshr());
- if (mf->istexture())
- m_L1T->shd_cache_fill(mf->get_addr(),gpu_sim_cycle+gpu_tot_sim_cycle);
- else if (mf->isconst())
- m_L1C->shd_cache_fill(mf->get_addr(),gpu_sim_cycle+gpu_tot_sim_cycle);
- else if (!m_config->gpgpu_no_dl1)
- m_L1D->shd_cache_fill(mf->get_addr(),gpu_sim_cycle+gpu_tot_sim_cycle);
+ m_ldst_unit->fill(mf);
}
freed_read_mfs++;
- delete mf;
}
void shader_core_ctx::store_ack( class mem_fetch *mf )
@@ -1279,7 +1288,7 @@ void gpgpu_sim::cycle()
// L1 cache + shader core pipeline stages
for (unsigned i=0;i<m_n_shader;i++) {
if (m_sc[i]->get_not_completed() || more_thread) {
- m_sc[i]->cycle_gt200();
+ m_sc[i]->cycle();
}
}
if( g_single_step && ((gpu_sim_cycle+gpu_tot_sim_cycle) >= g_single_step) ) {
@@ -1413,7 +1422,6 @@ void gpgpu_sim::dump_pipeline( int mask, int s, int m ) const
i = s;
}
if(mask&1) m_sc[i]->display_pipeline(stdout, 1, mask & 0x2E );
- if(mask&0x100) m_sc[i]->mshr_print(stdout, mask);
if(s != -1) {
break;
}
diff --git a/src/gpgpu-sim/gpu-sim.h b/src/gpgpu-sim/gpu-sim.h
index 37c87f4..5dbdf51 100644
--- a/src/gpgpu-sim/gpu-sim.h
+++ b/src/gpgpu-sim/gpu-sim.h
@@ -96,51 +96,6 @@
#define SAMPLELOG 222
#define DUMPLOG 333
-enum divergence_support_t {
- POST_DOMINATOR = 1,
- 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;
- int gpgpu_operand_collector_num_units_sfu;
- 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;
-};
-
enum dram_ctrl_t {
DRAM_FIFO=0,
DRAM_IDEAL_FAST=1
@@ -309,7 +264,5 @@ extern unsigned int **concurrent_row_access; //concurrent_row_access[dram chip i
extern unsigned int gpgpu_n_sent_writes;
extern unsigned int gpgpu_n_processed_writes;
-extern unsigned made_write_mfs;
-extern unsigned made_read_mfs;
#endif
diff --git a/src/gpgpu-sim/mem_fetch.cc b/src/gpgpu-sim/mem_fetch.cc
index e2bc3e3..1a4af1e 100644
--- a/src/gpgpu-sim/mem_fetch.cc
+++ b/src/gpgpu-sim/mem_fetch.cc
@@ -107,7 +107,7 @@ void mem_fetch::print( FILE *fp ) const
{
fprintf(fp," mf: uid=%6u, addr=0x%08llx, sid=%u, wid=%u, pc=0x%04x, %s, bank=%u, ",
request_uid, addr, sid, wid, pc, (m_write?"write":"read "), tlx.bk);
- if( mshr ) mshr->print(fp,0x100);
+ if( mshr ) mshr->print(fp);
else fprintf(fp,"\n");
}
diff --git a/src/gpgpu-sim/shader.cc b/src/gpgpu-sim/shader.cc
index 28ec00d..f298a67 100644
--- a/src/gpgpu-sim/shader.cc
+++ b/src/gpgpu-sim/shader.cc
@@ -226,7 +226,7 @@ unsigned mshr_shader_unit::mshr_used() const
return m_shader_config->n_mshr_per_shader - m_free_list.size();
}
-std::deque<mshr_entry*> &mshr_shader_unit::choose_return_queue()
+std::list<mshr_entry*> &mshr_shader_unit::choose_return_queue()
{
// prioritize a ready texture over a global/const...
if ((not m_texture_mshr_pipeline.empty()) and m_texture_mshr_pipeline.front()->fetched())
@@ -244,12 +244,7 @@ void mshr_shader_unit::mshr_return_from_mem(mshr_entry *mshr)
}
}
-void shader_core_ctx::mshr_print(FILE* fp, unsigned mask)
-{
- m_mshr_unit->print(fp, this, mask);
-}
-
-void mshr_shader_unit::print(FILE* fp, shader_core_ctx* shader, unsigned mask)
+void mshr_shader_unit::print(FILE* fp)
{
unsigned n=0;
unsigned num_outstanding = 0;
@@ -257,68 +252,23 @@ void mshr_shader_unit::print(FILE* fp, shader_core_ctx* shader, unsigned mask)
mshr_entry *mshr = &(*it);
if (find(m_free_list.begin(),m_free_list.end(), mshr) == m_free_list.end()) {
num_outstanding++;
- mshr->print(fp,mask);
+ mshr->print(fp);
}
}
+ fprintf(fp,"ready texture mshrs:\n");
+ std::list<mshr_entry*>::iterator m;
+ for( m=m_texture_mshr_pipeline.begin(); m!=m_texture_mshr_pipeline.end(); m++ ) {
+ mshr_entry *mshr = *m;
+ mshr->print(fp);
+ }
+ fprintf(fp,"ready non-texture mshrs:\n");
+ for( m=m_mshr_return_queue.begin(); m!=m_mshr_return_queue.end(); m++ ) {
+ mshr_entry *mshr = *m;
+ mshr->print(fp);
+ }
fprintf(fp,"\nTotal outstanding memory requests = %u\n", num_outstanding );
}
-unsigned char shader_core_ctx::fq_push(unsigned long long int addr,
- int bsize,
- unsigned char write,
- partial_write_mask_t partial_write_mask,
- int wid,
- mshr_entry* mshr,
- enum mem_access_type mem_acc,
- address_type pc)
-{
- assert(write || (partial_write_mask == NO_PARTIAL_WRITE));
- mem_fetch *mf = new mem_fetch(addr,
- bsize,
- (write?WRITE_PACKET_SIZE:READ_PACKET_SIZE),
- m_sid,
- m_tpc,
- wid,
- mshr,
- write,
- partial_write_mask,
- mem_acc,
- (write?WT_REQ:RD_REQ),
- pc);
- if (mshr) mshr->set_mf(mf);
-
- // stats
- if (write) made_write_mfs++;
- else made_read_mfs++;
- switch (mem_acc) {
- case CONST_ACC_R: m_stats->gpgpu_n_mem_const++; break;
- case TEXTURE_ACC_R: m_stats->gpgpu_n_mem_texture++; break;
- case GLOBAL_ACC_R: m_stats->gpgpu_n_mem_read_global++; break;
- case GLOBAL_ACC_W: m_stats->gpgpu_n_mem_write_global++; break;
- case LOCAL_ACC_R: m_stats->gpgpu_n_mem_read_local++; break;
- case LOCAL_ACC_W: m_stats->gpgpu_n_mem_write_local++; break;
- case INST_ACC_R: m_stats->gpgpu_n_mem_read_inst++; break;
- default: assert(0);
- }
-
- return(m_gpu->issue_mf_from_fq(mf));
-}
-
-void shader_core_ctx::L1cache_print( FILE *fp, unsigned &total_accesses, unsigned &total_misses) const
-{
- m_L1D->shd_cache_print(fp,total_accesses,total_misses);
-}
-
-void shader_core_ctx::L1texcache_print( FILE *fp, unsigned &total_accesses, unsigned &total_misses) const
-{
- m_L1T->shd_cache_print(fp,total_accesses,total_misses);
-}
-
-void shader_core_ctx::L1constcache_print( FILE *fp, unsigned &total_accesses, unsigned &total_misses) const
-{
- m_L1C->shd_cache_print(fp,total_accesses,total_misses);
-}
-
std::list<unsigned> shader_core_ctx::get_regs_written( const inst_t &fvt ) const
{
std::list<unsigned> result;
@@ -343,7 +293,7 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu,
const char *name,
unsigned shader_id,
unsigned tpc_id,
- const struct shader_core_config *config,
+ struct shader_core_config *config,
struct shader_core_stats *stats )
: m_barriers( config->max_warps_per_shader, config->max_cta_per_core )
{
@@ -351,19 +301,20 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu,
m_config = config;
m_stats = stats;
unsigned warp_size=config->warp_size;
+ config->max_sfu_latency = 32;
+ config->max_sp_latency = 32;
m_name = name;
m_sid = shader_id;
m_tpc = tpc_id;
+
m_pipeline_reg = new warp_inst_t*[N_PIPELINE_STAGES];
for (int j = 0; j<N_PIPELINE_STAGES; j++)
- m_pipeline_reg[j] = new warp_inst_t(warp_size);
+ m_pipeline_reg[j] = new warp_inst_t(config);
m_thread = (thread_ctx_t*) calloc(sizeof(thread_ctx_t), config->n_thread_per_shader);
- m_not_completed = 0;
-
- m_warp.resize(m_config->max_warps_per_shader, shd_warp_t(this, warp_size));
+ m_not_completed = 0;
m_n_active_cta = 0;
for (unsigned i = 0; i<MAX_CTA_PER_SHADER; i++ )
m_cta_status[i]=0;
@@ -372,41 +323,51 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu,
m_thread[i].m_cta_id = -1;
}
+ // fetch
+ m_last_warp_fetched = 0;
+ m_last_warp_issued = 0;
+
#define STRSIZE 1024
- char L1D_name[STRSIZE];
- char L1T_name[STRSIZE];
- char L1C_name[STRSIZE];
char L1I_name[STRSIZE];
-
- snprintf(L1D_name, STRSIZE, "L1D_%03d", m_sid);
- snprintf(L1T_name, STRSIZE, "L1T_%03d", m_sid);
- snprintf(L1C_name, STRSIZE, "L1C_%03d", m_sid);
snprintf(L1I_name, STRSIZE, "L1I_%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, 0,L1D_policy,m_sid,get_shader_normal_cache_id());
- m_L1T = new cache_t(L1T_name,m_config->gpgpu_cache_texl1_opt, 0,no_writes, m_sid,get_shader_texture_cache_id());
- m_L1C = new cache_t(L1C_name,m_config->gpgpu_cache_constl1_opt,0,no_writes, m_sid,get_shader_constant_cache_id());
m_L1I = new cache_t(L1I_name,m_config->gpgpu_cache_il1_opt, 0,no_writes, m_sid,get_shader_instruction_cache_id());
- m_gpu->ptx_set_tex_cache_linesize(m_L1T->get_line_sz());
- m_mshr_unit = new mshr_shader_unit(m_config);
+ 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];
for (unsigned i = 0; i < config->max_warps_per_shader; ++i)
m_pdom_warp[i] = new pdom_warp_ctx_t(i,this);
- m_mem_rc = NO_RC_FAIL,
-
- // Initialize scoreboard
m_scoreboard = new Scoreboard(m_sid, m_config->max_warps_per_shader);
- m_operand_collector.init( m_config->gpgpu_operand_collector_num_units,
- m_config->gpgpu_operand_collector_num_units_sfu,
- m_config->gpgpu_num_reg_banks, this,
- &m_pipeline_reg[OC_EX_SP],
- &m_pipeline_reg[OC_EX_SFU] );
+ m_operand_collector.add_port( m_config->gpgpu_operand_collector_num_units_sp,
+ &m_pipeline_reg[ID_OC_SP],
+ &m_pipeline_reg[OC_EX_SP] );
+ m_operand_collector.add_port( m_config->gpgpu_operand_collector_num_units_sfu,
+ &m_pipeline_reg[ID_OC_SFU],
+ &m_pipeline_reg[OC_EX_SFU] );
+ m_operand_collector.add_port( m_config->gpgpu_operand_collector_num_units_mem,
+ &m_pipeline_reg[ID_OC_MEM],
+ &m_pipeline_reg[OC_EX_MEM] );
+ m_operand_collector.init( m_config->gpgpu_num_reg_banks, this );
- // fetch
- m_last_warp_fetched = 0;
- m_last_warp_issued = 0;
+ // execute
+ m_num_function_units = 3; // sp_unit, sfu, ldst_unit
+ m_dispatch_port = new enum pipeline_stage_name_t[ m_num_function_units ];
+ m_issue_port = new enum pipeline_stage_name_t[ m_num_function_units ];
+
+ m_fu = new simd_function_unit*[m_num_function_units];
+
+ m_fu[0] = new sp_unit( &m_pipeline_reg[EX_WB], m_config );
+ m_dispatch_port[0] = ID_OC_SP;
+ m_issue_port[0] = OC_EX_SP;
+
+ m_fu[1] = new sfu( &m_pipeline_reg[EX_WB], m_config );
+ m_dispatch_port[1] = ID_OC_SFU;
+ m_issue_port[1] = OC_EX_SFU;
+
+ m_ldst_unit = new ldst_unit( m_gpu, this, &m_pipeline_reg[EX_WB], config, m_stats, m_sid, m_tpc );
+ m_fu[2] = m_ldst_unit;
+ m_dispatch_port[2] = ID_OC_MEM;
+ m_issue_port[2] = OC_EX_MEM;
}
void shader_core_ctx::reinit(unsigned start_thread, unsigned end_thread, bool reset_not_completed )
@@ -589,14 +550,6 @@ void pdom_warp_ctx_t::print (FILE *fout) const
}
}
-
-void shader_core_ctx::new_cache_window()
-{
- m_L1D->shd_cache_new_window();
- m_L1T->shd_cache_new_window();
- m_L1C->shd_cache_new_window();
-}
-
void gpgpu_sim::print_shader_cycle_distro( FILE *fout ) const
{
fprintf(fout, "Warp Occupancy Distribution:\n");
@@ -613,7 +566,7 @@ void gpgpu_sim::print_shader_cycle_distro( FILE *fout ) const
#define PROGRAM_MEM_START 0xF0000000 /* should be distinct from other memory spaces...
check ptx_ir.h to verify this does not overlap
other memory spaces */
-void shader_core_ctx::fetch_new()
+void shader_core_ctx::fetch()
{
if( m_inst_fetch_buffer.m_valid ) {
// decode 1 or 2 instructions and place them into ibuffer
@@ -666,11 +619,22 @@ void shader_core_ctx::fetch_new()
m_last_warp_fetched=warp_id;
mshr_entry *mshr = new mshr_entry();
mshr->init(ppc,false,instruction_space,warp_id);
- fq_push( pc, req_size, false,
- NO_PARTIAL_WRITE,
- warp_id,
- mshr,
- INST_ACC_R, pc );
+
+ mem_fetch *mf = new mem_fetch(pc,
+ req_size,
+ READ_PACKET_SIZE,
+ m_sid,
+ m_tpc,
+ warp_id,
+ mshr,
+ false,
+ NO_PARTIAL_WRITE,
+ INST_ACC_R,
+ RD_REQ,
+ pc);
+ mshr->set_mf(mf);
+ m_gpu->issue_mf_from_fq(mf);
+
m_warp[warp_id].set_imiss_pending(mshr);
m_warp[warp_id].set_last_fetch(gpu_sim_cycle);
}
@@ -719,7 +683,7 @@ void shader_core_ctx::issue_warp( warp_inst_t *&pipe_reg, const warp_inst_t *nex
m_warp[warp_id].set_next_pc(next_inst->pc + next_inst->isize);
}
-void shader_core_ctx::decode_new()
+void shader_core_ctx::decode()
{
for ( unsigned i=0; i < m_config->max_warps_per_shader; i++ ) {
unsigned warp_id = (m_last_warp_issued+1+i) % m_config->max_warps_per_shader;
@@ -739,13 +703,25 @@ void shader_core_ctx::decode_new()
} else if ( !m_scoreboard->checkCollision(warp_id, pI) ) {
unsigned active_mask = m_pdom_warp[warp_id]->get_active_mask();
assert( m_warp[warp_id].inst_in_pipeline() );
- if ( (pI->op != SFU_OP) && m_pipeline_reg[ID_OC_SP]->empty() ) {
- issue_warp(m_pipeline_reg[ID_OC_SP],pI,active_mask,warp_id);
- issued++;
- } else if ( (pI->op == SFU_OP || pI->op == ALU_SFU_OP) && m_pipeline_reg[ID_OC_SFU]->empty() ) {
- issue_warp(m_pipeline_reg[ID_OC_SFU],pI,active_mask,warp_id);
- issued++;
- }
+ if ( (pI->op == LOAD_OP) || (pI->op == STORE_OP) || (pI->op == MEMORY_BARRIER_OP) ) {
+ if( m_pipeline_reg[ID_OC_MEM]->empty() ) {
+ issue_warp(m_pipeline_reg[ID_OC_MEM],pI,active_mask,warp_id);
+ issued++;
+ }
+ } else {
+ bool sp_pipe_avail = m_pipeline_reg[ID_OC_SP]->empty();
+ bool sfu_pipe_avail = m_pipeline_reg[ID_OC_SFU]->empty();
+ if( sp_pipe_avail && (pI->op != SFU_OP) ) {
+ // always prefer SP pipe for operations that can use both SP and SFU pipelines
+ issue_warp(m_pipeline_reg[ID_OC_SP],pI,active_mask,warp_id);
+ issued++;
+ } else if ( (pI->op == SFU_OP) || (pI->op == ALU_SFU_OP) ) {
+ if( sfu_pipe_avail ) {
+ issue_warp(m_pipeline_reg[ID_OC_SFU],pI,active_mask,warp_id);
+ issued++;
+ }
+ }
+ }
}
} else if( valid ) {
// this case can happen after a return instruction in diverged warp
@@ -767,7 +743,7 @@ address_type coalesced_segment(address_type addr, unsigned segment_size_lg2bytes
return (addr >> segment_size_lg2bytes);
}
-address_type shader_core_ctx::translate_local_memaddr(address_type localaddr, int tid, unsigned num_shader )
+address_type shader_core_ctx::translate_local_memaddr( address_type localaddr, unsigned tid, unsigned num_shader )
{
// During functional execution, each thread sees its own memory space for local memory, but these
// need to be mapped to a shared address space for timing simulation. We do that mapping here.
@@ -795,22 +771,26 @@ address_type shader_core_ctx::translate_local_memaddr(address_type localaddr, in
/////////////////////////////////////////////////////////////////////////////////////////
-void shader_core_ctx::execute_pipe( unsigned current_stage, unsigned next_stage )
+void shader_core_ctx::execute()
{
- if( !m_pipeline_reg[current_stage]->empty() ) {
- if( m_pipeline_reg[current_stage]->cycles > 1 ) {
- m_pipeline_reg[current_stage]->cycles--;
- return;
+ m_result_bus >>= 1;
+ for( unsigned n=0; n < m_num_function_units; n++ ) {
+ m_fu[n]->cycle();
+ enum pipeline_stage_name_t issue_port = m_issue_port[n];
+ warp_inst_t *& issue_inst = m_pipeline_reg[ issue_port ];
+ if( !issue_inst->empty() && m_fu[n]->can_issue( *issue_inst ) ) {
+ bool schedule_wb_now = !m_fu[n]->stallable();
+ if( schedule_wb_now && !m_result_bus.test( issue_inst->latency ) ) {
+ assert( issue_inst->latency < MAX_ALU_LATENCY );
+ m_result_bus.set( issue_inst->latency );
+ m_fu[n]->issue( issue_inst );
+ } else if( !schedule_wb_now ) {
+ m_fu[n]->issue( issue_inst );
+ } else {
+ // stall issue (cannot reserve result bus)
+ }
}
}
- if( m_pipeline_reg[next_stage]->empty() )
- move_warp(m_pipeline_reg[next_stage],m_pipeline_reg[current_stage]);
-}
-
-void shader_core_ctx::execute()
-{
- execute_pipe(OC_EX_SFU,EX_MM);
- execute_pipe(OC_EX_SP,EX_MM);
}
mshr_entry* mshr_shader_unit::add_mshr(mem_access_t &access, warp_inst_t* pinst)
@@ -844,35 +824,18 @@ address_type null_tag_func(address_type address, unsigned line_size)
return address; //no modification: each address is its own tag.
}
-// only 1 bank
-int shader_core_ctx::null_bank_func(address_type add, unsigned line_size)
-{
- return 1;
-}
-
-int shader_core_ctx::shmem_bank_func(address_type addr, unsigned line_size)
+unsigned shader_core_config::shmem_bank_func(address_type addr, unsigned) const
{
- //returns the integer number of the physical bank addr would go in.
- return ((int)(addr/((address_type)WORD_SIZE)) % m_config->gpgpu_n_shmem_bank);
+ return ((addr/WORD_SIZE) % gpgpu_n_shmem_bank);
}
-int shader_core_ctx::dcache_bank_func(address_type add, unsigned line_size)
+unsigned shader_core_config::dcache_bank_func(address_type add, unsigned line_size) const
{
- //returns the integer number of the physical bank addr would go in.
- if (m_config->gpgpu_no_dl1) return 1; //no banks
- else return (add / line_size) & (m_config->gpgpu_n_cache_bank - 1);
+ if (gpgpu_no_dl1) return 1; //no banks
+ else return (add / line_size) & (gpgpu_n_cache_bank - 1);
}
-typedef int (shader_core_ctx::*bank_func_t)(address_type add, unsigned line_size);
-typedef address_type (*tag_func_t)(address_type add, unsigned line_size);
-
-void shader_core_ctx::get_memory_access_list(
- shader_core_ctx::bank_func_t bank_func,
- tag_func_t tag_func,
- unsigned warp_parts,
- unsigned line_size,
- bool limit_broadcast,
- warp_inst_t &inst )
+void warp_inst_t::get_memory_access_list()
{
// Calculates memory accesses generated by this warp
// Returns acesses which are "coalesced"
@@ -882,6 +845,9 @@ void shader_core_ctx::get_memory_access_list(
// 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.
@@ -890,6 +856,59 @@ void shader_core_ctx::get_memory_access_list(
//
// 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
@@ -898,76 +917,83 @@ void shader_core_ctx::get_memory_access_list(
// keep track of broadcasts with unique orders if limit_broadcast
// the normally calculated orders will never be greater than warp_size
- unsigned broadcast_order = m_config->warp_size;
- unsigned qbegin = inst.get_accessq_size();
+ unsigned broadcast_order = warp_size();
+ unsigned qbegin = get_accessq_size();
unsigned qpartbegin = qbegin;
- unsigned mem_pipe_size = m_config->warp_size / warp_parts;
- for (unsigned part = 0; part < m_config->warp_size; part += mem_pipe_size) {
+ 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 ( !inst.active(i) )
+ if ( !active(i) )
continue;
- assert( inst.space != undefined_space );
- new_addr_type addr = inst.get_addr(i);
+ 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( !inst.isatomic() ) { //atomics must have own request
- for( unsigned j = qpartbegin; j <inst.get_accessq_size(); j++ ) {
- if (lane_segment_address == inst.accessq(j).addr) {
- inst.accessq(j).quarter_count[quarter]++;
- inst.accessq(j).warp_indices.push_back(i);
+ 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.
- inst.accessq(j).order = ++broadcast_order; //do broadcast in its own cycle.
+ 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( inst.space != undefined_space );
- inst.accessq_push_back( mem_access_t( lane_segment_address, line_size, quarter, i) );
+ assert( space != undefined_space );
+ m_accessq.push_back( mem_access_t( lane_segment_address, line_size, quarter, i) );
// Determine Bank Conflicts:
- unsigned bank = (this->*bank_func)(inst.get_addr(i), line_size);
+ 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;
- inst.accessq_back().order = bank_accs[bank];
+ accessq_back().order = bank_accs[bank];
bank_accs[bank]++;
}
}
- qpartbegin = inst.get_accessq_size(); //don't coalesce accross warp parts
+ qpartbegin = get_accessq_size(); //don't coalesce accross warp parts
}
//sort requests by order they will be processed in
- inst.sort_accessq(qbegin);
-}
+ std::stable_sort( m_accessq.begin()+qbegin,m_accessq.end());
-void shader_core_ctx::memory_shared_process_warp(warp_inst_t &inst)
-{
- // initial processing of shared memory warps
- get_memory_access_list(&shader_core_ctx::shmem_bank_func,
- null_tag_func,
- m_config->gpgpu_shmem_pipe_speedup,
- 1, //shared memory doesn't care about line_size, needs to be at least 1;
- true,
- inst); // limit broadcasts to single cycle.
-}
+ 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 shader_core_ctx::memory_const_process_warp(warp_inst_t &inst)
+void ldst_unit::const_cache_access(warp_inst_t &inst)
{
- // initial processing of const memory warps
- unsigned qbegin = inst.get_accessq_size();
- get_memory_access_list( &shader_core_ctx::null_bank_func,
- line_size_based_tag_func,
- 1, //warp parts
- m_L1C->get_line_sz(),
- false, //no broadcast limit.
- inst);
// do cache checks here for each request (non-physical), could be
// done later for more accurate timing of cache accesses, but probably uneccesary;
- for (unsigned i = qbegin; i < inst.get_accessq_size(); i++) {
+ for (unsigned i = 0; i < inst.get_accessq_size(); i++) {
mem_access_t &req = inst.accessq(i);
if ( inst.space == param_space_kernel ) {
req.cache_hit = true;
@@ -984,19 +1010,11 @@ void shader_core_ctx::memory_const_process_warp(warp_inst_t &inst)
}
}
-void shader_core_ctx::memory_texture_process_warp(warp_inst_t &inst)
+void ldst_unit::tex_cache_access(warp_inst_t &inst)
{
- // initial processing of shared texture warps
- unsigned qbegin = inst.get_accessq_size();
- get_memory_access_list(&shader_core_ctx::null_bank_func,
- &line_size_based_tag_func,
- 1, //warp parts
- m_L1T->get_line_sz(),
- false, //no broadcast limit.
- inst);
// do cache checks here for each request (non-hardware), could be done later
// for more accurate timing of cache accesses, but probably uneccesary;
- for (unsigned i = qbegin; i < inst.get_accessq_size(); i++) {
+ for (unsigned i = 0; i < inst.get_accessq_size(); i++) {
mem_access_t &req = inst.accessq(i);
cache_request_status status = m_L1T->access( req.addr,
0, //should always be a read
@@ -1009,78 +1027,35 @@ void shader_core_ctx::memory_texture_process_warp(warp_inst_t &inst)
}
}
-void shader_core_ctx::memory_global_process_warp( warp_inst_t &inst )
-{
- unsigned qbegin = inst.get_accessq_size();
- unsigned warp_parts = 1;
- unsigned line_size = m_L1D->get_line_sz();
- if (m_config->gpgpu_coalesce_arch == 13) {
- warp_parts = 2;
- if(m_config->gpgpu_no_dl1) {
- unsigned data_size = inst.data_size;
- // 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);
- }
- }
- }
- get_memory_access_list( &shader_core_ctx::dcache_bank_func,
- &line_size_based_tag_func,
- warp_parts,
- line_size,
- false,
- inst );
-
- // 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 = qbegin; i < inst.get_accessq_size(); i++) {
- if (m_config->gpgpu_coalesce_arch == 13 and m_config->gpgpu_no_dl1) {
- //if there is no l1 cache it makes sense to do coalescing here.
- //reduce memory request sizes.
- char* quarter_counts = inst.accessq(i).quarter_count;
- bool low = quarter_counts[0] or quarter_counts[1];
- bool high = quarter_counts[2] or quarter_counts[3];
- if (inst.accessq(i).req_size == 128) {
- if (low xor high) { //can reduce size
- inst.accessq(i).req_size = 64;
- if (high) inst.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 (inst.accessq(i).req_size == 64) {
- if (low xor high) { //can reduce size
- inst.accessq(i).req_size = 32;
- if (high) inst.accessq(i).addr += 32;
- }
- }
- }
- }
-}
-
-mem_stage_stall_type shader_core_ctx::send_mem_request(warp_inst_t &inst, mem_access_t &access)
+mem_stage_stall_type ldst_unit::send_mem_request(warp_inst_t &inst, mem_access_t &access)
{
// Attempt to send an request/write to memory based on information in access.
// If the cache told us it needed to write back a dirty line, do this now
// It is possible to do this writeback in the same cycle as the access request, this may not be realistic.
if (access.need_wb) {
- unsigned req_size = m_L1D->get_line_sz() + WRITE_PACKET_SIZE;
- if ( ! m_gpu->fq_has_buffer(access.wb_addr, req_size, true, m_sid) ) {
+ unsigned req_size = m_config->gpgpu_cache_dl1_linesize + WRITE_PACKET_SIZE;
+ if ( !m_gpu->fq_has_buffer(access.wb_addr, req_size, true, m_sid) ) {
m_stats->gpu_stall_sh2icnt++;
return WB_ICNT_RC_FAIL;
}
- fq_push( access.wb_addr, req_size, true, NO_PARTIAL_WRITE, -1, NULL,
- inst.space.is_local()?LOCAL_ACC_W:GLOBAL_ACC_W, //space of cache line is same as new request
- -1);
+ mem_fetch *mf = new mem_fetch(access.wb_addr,
+ req_size,
+ READ_PACKET_SIZE,
+ m_sid,
+ m_tpc,
+ -1,
+ NULL,
+ true,
+ NO_PARTIAL_WRITE,
+ inst.space.is_local()?LOCAL_ACC_W:GLOBAL_ACC_W, //space of cache line is same as new request
+ WT_REQ,
+ -1);
+ m_gpu->issue_mf_from_fq(mf);
m_stats->L1_writeback++;
access.need_wb = false;
}
-
bool is_write = inst.is_store();
mem_access_type access_type;
switch(inst.space.get_type()) {
@@ -1098,7 +1073,8 @@ mem_stage_stall_type shader_core_ctx::send_mem_request(warp_inst_t &inst, mem_ac
if (not m_mshr_unit->has_mshr(1))
return MSHR_RC_FAIL;
access.reserved_mshr = m_mshr_unit->add_mshr(access, &inst);
- access.recheck_cache = false; //we have an mshr now, so have checked cache in same cycle as checking mshrs, so have merged if necessary.
+ access.recheck_cache = false;
+ //we have an mshr now, so have checked cache in same cycle as checking mshrs, so have merged if necessary.
}
//require inct if access is this far without reserved mshr, or has and mshr but not merged with another request
bool requires_icnt = (!access.reserved_mshr) || (!access.reserved_mshr->ismerged());
@@ -1120,7 +1096,7 @@ mem_stage_stall_type shader_core_ctx::send_mem_request(warp_inst_t &inst, mem_ac
partial_write_mask_t write_mask = NO_PARTIAL_WRITE;
unsigned warp_id = inst.warp_id();
if (is_write) {
- m_warp[warp_id].inc_store_req();
+ m_core->inc_store_req(warp_id);
for (unsigned i=0;i < access.warp_indices.size();i++) {
unsigned w = access.warp_indices[i];
int data_offset = inst.get_addr(w) & ((unsigned long long int)access.req_size - 1);
@@ -1129,29 +1105,40 @@ mem_stage_stall_type shader_core_ctx::send_mem_request(warp_inst_t &inst, mem_ac
if (write_mask.count() != access.req_size)
m_stats->gpgpu_n_partial_writes++;
}
- fq_push( access.addr, request_size,
- is_write, write_mask, warp_id , access.reserved_mshr,
- access_type, inst.pc );
+ mem_fetch *mf = new mem_fetch(access.addr,
+ request_size,
+ is_write?WRITE_PACKET_SIZE:READ_PACKET_SIZE,
+ m_sid,
+ m_tpc,
+ warp_id,
+ access.reserved_mshr,
+ is_write,
+ write_mask,
+ access_type,
+ is_write?WT_REQ:RD_REQ,
+ inst.pc);
+ if( access.reserved_mshr )
+ access.reserved_mshr->set_mf(mf);
+ m_gpu->issue_mf_from_fq(mf);
}
return NO_RC_FAIL;
}
void shader_core_ctx::writeback()
{
- mshr_entry *m = m_mshr_unit->return_head();
- if( m )
- m_mshr_unit->pop_return_head();
- if( !m_pipeline_reg[MM_WB]->empty() ) {
- m_scoreboard->releaseRegisters( m_pipeline_reg[MM_WB] );
- m_warp[m_pipeline_reg[MM_WB]->warp_id()].dec_inst_in_pipeline();
+ warp_inst_t *&pipe_reg = m_pipeline_reg[EX_WB];
+ if( !pipe_reg->empty() ) {
+ unsigned warp_id = pipe_reg->warp_id();
+ m_scoreboard->releaseRegisters( pipe_reg );
+ m_warp[warp_id].dec_inst_in_pipeline();
m_gpu->gpu_sim_insn_last_update_sid = m_sid;
m_gpu->gpu_sim_insn_last_update = gpu_sim_cycle;
- m_gpu->gpu_sim_insn += m_pipeline_reg[MM_WB]->active_count();
+ m_gpu->gpu_sim_insn += pipe_reg->active_count();
+ pipe_reg->clear();
}
- move_warp(m_pipeline_reg[WB_RT],m_pipeline_reg[MM_WB]);
}
-bool shader_core_ctx::memory_shared_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type)
+bool ldst_unit::shared_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type)
{
// Process a single cycle of activity from the shared memory queue.
if( inst.space.get_type() != shared_space )
@@ -1174,10 +1161,10 @@ bool shader_core_ctx::memory_shared_cycle( warp_inst_t &inst, mem_stage_stall_ty
return inst.accessq_empty(); //done if empty.
}
-mem_stage_stall_type shader_core_ctx::process_memory_access_queue( shader_core_ctx::cache_check_t cache_check,
- unsigned ports_per_bank,
- unsigned memory_send_max,
- warp_inst_t &inst )
+mem_stage_stall_type ldst_unit::process_memory_access_queue( ldst_unit::cache_check_t cache_check,
+ unsigned ports_per_bank,
+ unsigned memory_send_max,
+ warp_inst_t &inst )
{
// Generic algorithm for processing a single cycle of accesses for the memory space types that go to L2 or DRAM.
@@ -1211,13 +1198,13 @@ mem_stage_stall_type shader_core_ctx::process_memory_access_queue( shader_core_c
return hazard_cond;
}
-bool shader_core_ctx::memory_constant_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type)
+bool ldst_unit::constant_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type)
{
if( (inst.space.get_type() != const_space) && (inst.space.get_type() != param_space_kernel) )
return true;
// Process a single cycle of activity from the the constant memory queue.
- mem_stage_stall_type fail = process_memory_access_queue(&shader_core_ctx::ccache_check,
+ mem_stage_stall_type fail = process_memory_access_queue(&ldst_unit::ccache_check,
m_config->gpgpu_const_port_per_bank,
1, //memory send max per cycle
inst );
@@ -1231,14 +1218,14 @@ bool shader_core_ctx::memory_constant_cycle( warp_inst_t &inst, mem_stage_stall_
return inst.accessq_empty(); //done if empty.
}
-bool shader_core_ctx::memory_texture_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type)
+bool ldst_unit::texture_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type)
{
if( inst.space.get_type() != tex_space )
return true;
// Process a single cycle of activity from the the texture memory queue.
- mem_stage_stall_type fail = process_memory_access_queue(&shader_core_ctx::tcache_check,
+ mem_stage_stall_type fail = process_memory_access_queue(&ldst_unit::tcache_check,
1, //how is tex memory banked?
1, //memory send max per cycle
inst );
@@ -1250,7 +1237,7 @@ bool shader_core_ctx::memory_texture_cycle( warp_inst_t &inst, mem_stage_stall_t
}
-mem_stage_stall_type shader_core_ctx::dcache_check(warp_inst_t &inst, mem_access_t& access)
+mem_stage_stall_type ldst_unit::dcache_check(warp_inst_t &inst, mem_access_t& access)
{
// Global memory (data cache) checks the cache for each access at the time it is processed.
// This is more accurate to hardware, and necessary for proper action of the writeback cache.
@@ -1311,7 +1298,7 @@ mem_stage_stall_type shader_core_ctx::dcache_check(warp_inst_t &inst, mem_access
return NO_RC_FAIL;
}
-bool shader_core_ctx::memory_cycle( warp_inst_t &inst, mem_stage_stall_type &stall_reason, mem_stage_access_type &access_type )
+bool ldst_unit::memory_cycle( warp_inst_t &inst, mem_stage_stall_type &stall_reason, mem_stage_access_type &access_type )
{
if( (inst.space.get_type() != global_space) &&
(inst.space.get_type() != local_space) &&
@@ -1319,7 +1306,7 @@ bool shader_core_ctx::memory_cycle( warp_inst_t &inst, mem_stage_stall_type &sta
return true;
// Process a single cycle of activity from the the global/local memory queue.
- mem_stage_stall_type stall_cond = process_memory_access_queue(&shader_core_ctx::dcache_check,m_config->gpgpu_cache_port_per_bank,1,inst);
+ mem_stage_stall_type stall_cond = process_memory_access_queue(&ldst_unit::dcache_check,m_config->gpgpu_cache_port_per_bank,1,inst);
if (stall_cond != NO_RC_FAIL) {
stall_reason = stall_cond;
bool iswrite = inst.is_store();
@@ -1333,36 +1320,114 @@ bool shader_core_ctx::memory_cycle( warp_inst_t &inst, mem_stage_stall_type &sta
return inst.accessq_empty(); //done if empty.
}
-void shader_core_ctx::memory_queue( warp_inst_t &pipe_reg )
+void ldst_unit::fill( mem_fetch *mf )
+{
+ m_mshr_unit->mshr_return_from_mem(mf->get_mshr());
+ if (mf->istexture())
+ m_L1T->shd_cache_fill(mf->get_addr(),gpu_sim_cycle+gpu_tot_sim_cycle);
+ else if (mf->isconst())
+ m_L1C->shd_cache_fill(mf->get_addr(),gpu_sim_cycle+gpu_tot_sim_cycle);
+ else if (!m_config->gpgpu_no_dl1)
+ m_L1D->shd_cache_fill(mf->get_addr(),gpu_sim_cycle+gpu_tot_sim_cycle);
+}
+
+void ldst_unit::flush()
+{
+ m_L1D->flush();
+ // TODO: add flush 'interface' object to provide functionality commented out below
+ /*
+
+ unsigned int i;
+ unsigned int set;
+ unsigned long long int flush_addr;
+ cache_t *cp = m_L1D;
+ cache_block_t *pline;
+ for (i=0; i<cp->m_nset*cp->m_assoc; i++) {
+ pline = &(cp->m_lines[i]);
+ set = i / cp->m_assoc;
+ if ((pline->status & (DIRTY|VALID)) == (DIRTY|VALID)) {
+ flush_addr = pline->addr;
+ fq_push(flush_addr, m_L1D->get_line_sz(), 1, NO_PARTIAL_WRITE, 0, NULL, 0, GLOBAL_ACC_W, -1);
+ pline->status &= ~VALID;
+ pline->status &= ~DIRTY;
+ } else if (pline->status & VALID) {
+ pline->status &= ~VALID;
+ }
+ }
+ */
+}
+
+void ldst_unit::generate_mem_accesses(warp_inst_t &inst)
{
- // Called once per warp when warp enters memory stage.
- // Generates a list of memory accesses, but does not perform the memory access.
- if( pipe_reg.empty() )
+ // Called once per warp when warp enters ld/st unit.
+ // Generates a list of memory accesses, but does not perform the memory access.
+ if( inst.empty() )
return;
- if( pipe_reg.mem_accesses_computed() )
+ if( inst.op == MEMORY_BARRIER_OP )
return;
- m_gpu->mem_instruction_stats(pipe_reg);
- switch( pipe_reg.space.get_type() ) {
- case shared_space: memory_shared_process_warp(pipe_reg); break;
- case tex_space: memory_texture_process_warp(pipe_reg); break;
- case const_space: case param_space_kernel: memory_const_process_warp(pipe_reg); break;
- case global_space: case local_space: case param_space_local: memory_global_process_warp(pipe_reg); break;
+ if( inst.mem_accesses_created() )
+ return;
+ inst.get_memory_access_list();
+ switch( inst.space.get_type() ) {
+ case shared_space: break;
+ case tex_space: tex_cache_access(inst); break;
+ case const_space: case param_space_kernel: const_cache_access(inst); break;
+ case global_space: case local_space: case param_space_local: break;
case param_space_unclassified: abort(); break;
default: break; // non-memory operations
}
- pipe_reg.set_mem_accesses_computed();
+ m_gpu->mem_instruction_stats(inst);
+ inst.set_mem_accesses_created();
}
-void shader_core_ctx::memory()
+ldst_unit::ldst_unit( gpgpu_sim *gpu,
+ shader_core_ctx *core,
+ warp_inst_t **result_port,
+ shader_core_config *config,
+ shader_core_stats *stats,
+ unsigned sid,
+ unsigned tpc ) : simd_function_unit(result_port,config)
{
- warp_inst_t &pipe_reg = *m_pipeline_reg[EX_MM];
- memory_queue(pipe_reg);
- bool done = true;
+ m_gpu = gpu;
+ m_core = core;
+ m_stats = stats;
+ m_sid = sid;
+ m_tpc = tpc;
+ #define STRSIZE 1024
+ char L1D_name[STRSIZE];
+ char L1T_name[STRSIZE];
+ char L1C_name[STRSIZE];
+ 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,0,L1D_policy,m_sid,get_shader_normal_cache_id());
+ m_L1T = new cache_t(L1T_name,m_config->gpgpu_cache_texl1_opt,0,no_writes, m_sid,get_shader_texture_cache_id());
+ m_L1C = new cache_t(L1C_name,m_config->gpgpu_cache_constl1_opt,0,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_gpu->ptx_set_tex_cache_linesize(m_L1T->get_line_sz());
+ m_mshr_unit = new mshr_shader_unit(m_config);
+ m_mem_rc = NO_RC_FAIL;
+}
+
+void ldst_unit::cycle()
+{
+ mshr_entry *m = m_mshr_unit->return_head();
+ if( m ) {
+ delete m->get_mf();
+ m_mshr_unit->pop_return_head();
+ }
+
+ warp_inst_t &pipe_reg = *m_dispatch_reg;
+ generate_mem_accesses(pipe_reg);
enum mem_stage_stall_type rc_fail = NO_RC_FAIL;
mem_stage_access_type type;
- done &= memory_shared_cycle(pipe_reg, rc_fail, type);
- done &= memory_constant_cycle(pipe_reg, rc_fail, type);
- done &= memory_texture_cycle(pipe_reg, rc_fail, type);
+ bool done = true;
+ done &= shared_cycle(pipe_reg, rc_fail, type);
+ done &= constant_cycle(pipe_reg, rc_fail, type);
+ done &= texture_cycle(pipe_reg, rc_fail, type);
done &= memory_cycle(pipe_reg, rc_fail, type);
m_mem_rc = rc_fail;
if (!done) { // log stall types and return
@@ -1371,9 +1436,9 @@ void shader_core_ctx::memory()
m_stats->gpu_stall_shd_mem_breakdown[type][rc_fail]++;
return;
}
- if( !m_pipeline_reg[MM_WB]->empty() )
+ if( !(*m_result_port)->empty() )
return; // writeback stalled
- move_warp(m_pipeline_reg[MM_WB],m_pipeline_reg[EX_MM]);
+ move_warp(*m_result_port,m_dispatch_reg);
}
void shader_core_ctx::register_cta_thread_exit(int tid )
@@ -1467,33 +1532,24 @@ void gpgpu_sim::shader_print_l1_miss_stat( FILE *fout )
fprintf(fout, "\n");
}
-void shader_core_ctx::print_warp( warp_inst_t *warp, FILE *fout, int print_mem, int mask ) const
+void warp_inst_t::print( FILE *fout ) const
{
- if ( warp->empty() ) {
+ if (empty() ) {
fprintf(fout,"bubble\n" );
return;
} else
- fprintf(fout,"0x%04x ", warp->pc );
- unsigned warp_id = warp->warp_id();
- fprintf(fout, "w%02d[", warp_id);
+ fprintf(fout,"0x%04x ", pc );
+ fprintf(fout, "w%02d[", m_warp_id);
for (unsigned j=0; j<m_config->warp_size; j++)
- fprintf(fout, "%c", (warp->active(j)?'1':'0') );
+ fprintf(fout, "%c", (active(j)?'1':'0') );
fprintf(fout, "]: ");
- if ( m_config->model == POST_DOMINATOR ) {
- unsigned rp = m_pdom_warp[warp_id]->get_rp();
- if ( rp == (unsigned)-1 ) {
- fprintf(fout," rp:--- ");
- } else {
- fprintf(fout," rp:0x%03x ", rp );
- }
- }
- ptx_print_insn( warp->pc, fout );
+ ptx_print_insn( pc, fout );
fprintf(fout, "\n");
}
-void shader_core_ctx::print_stage(unsigned int stage, FILE *fout, int print_mem, int mask )
+void shader_core_ctx::print_stage(unsigned int stage, FILE *fout ) const
{
- print_warp(m_pipeline_reg[stage],fout,print_mem,mask);
+ m_pipeline_reg[stage]->print(fout);
}
void shader_core_ctx::display_pdom_state(FILE *fout, int mask )
@@ -1523,6 +1579,27 @@ void shader_core_ctx::display_pdom_state(FILE *fout, int mask )
}
}
+void ldst_unit::print(FILE *fout) const
+{
+ fprintf(fout,"LD/ST unit = ");
+ m_dispatch_reg->print(fout);
+ if ( m_mem_rc != NO_RC_FAIL ) {
+ fprintf(fout," LD/ST stall condition: ");
+ switch ( m_mem_rc ) {
+ case BK_CONF: fprintf(fout,"BK_CONF"); break;
+ case MSHR_RC_FAIL: fprintf(fout,"MSHR_RC_FAIL"); break;
+ case ICNT_RC_FAIL: fprintf(fout,"ICNT_RC_FAIL"); break;
+ case COAL_STALL: fprintf(fout,"COAL_STALL"); break;
+ case WB_ICNT_RC_FAIL: fprintf(fout,"WB_ICNT_RC_FAIL"); break;
+ case WB_CACHE_RSRV_FAIL: fprintf(fout,"WB_CACHE_RSRV_FAIL"); break;
+ case N_MEM_STAGE_STALL_TYPE: fprintf(fout,"N_MEM_STAGE_STALL_TYPE"); break;
+ default: abort();
+ }
+ fprintf(fout,"\n");
+ }
+ m_mshr_unit->print(fout);
+}
+
void shader_core_ctx::display_pipeline(FILE *fout, int print_mem, int mask )
{
fprintf(fout, "=================================================\n");
@@ -1553,34 +1630,27 @@ void shader_core_ctx::display_pipeline(FILE *fout, int print_mem, int mask )
m_scoreboard->printContents();
fprintf(fout,"ID/OC (SP) = ");
- print_stage(ID_OC_SP, fout, print_mem, mask);
+ print_stage(ID_OC_SP, fout);
fprintf(fout,"ID/OC (SFU) = ");
- print_stage(ID_OC_SFU, fout, print_mem, mask);
+ print_stage(ID_OC_SFU, fout);
+ fprintf(fout,"ID/OC (MEM) = ");
+ print_stage(ID_OC_MEM, fout);
+
m_operand_collector.dump(fout);
- fprintf(fout, "ID/EX (SP) = ");
- print_stage(OC_EX_SP, fout, print_mem, mask);
- fprintf(fout, "ID/EX (SFU) = ");
- print_stage(OC_EX_SFU, fout, print_mem, mask);
- fprintf(fout, "EX/MEM = ");
- print_stage(EX_MM, fout, print_mem, mask);
- if( m_mem_rc != NO_RC_FAIL ) {
- fprintf(fout, "EX/MEM (stall condition: ");
- switch ( m_mem_rc ) {
- case BK_CONF: fprintf(fout,"BK_CONF"); break;
- case MSHR_RC_FAIL: fprintf(fout,"MSHR_RC_FAIL"); break;
- case ICNT_RC_FAIL: fprintf(fout,"ICNT_RC_FAIL"); break;
- case COAL_STALL: fprintf(fout,"COAL_STALL"); break;
- case WB_ICNT_RC_FAIL: fprintf(fout,"WB_ICNT_RC_FAIL"); break;
- case WB_CACHE_RSRV_FAIL: fprintf(fout,"WB_CACHE_RSRV_FAIL"); break;
- case N_MEM_STAGE_STALL_TYPE: fprintf(fout,"N_MEM_STAGE_STALL_TYPE"); break;
- default: abort();
- }
- fprintf(fout,")\n");
- }
- fprintf(fout, "MEM/WB = ");
- print_stage(MM_WB, fout, print_mem, mask);
+
+ fprintf(fout, "OC/EX (SP) = ");
+ print_stage(OC_EX_SP, fout);
+ fprintf(fout, "OC/EX (SFU) = ");
+ print_stage(OC_EX_SFU, fout);
+ fprintf(fout, "OC/EX (MEM) = ");
+ print_stage(OC_EX_MEM, fout);
+ for( unsigned n=0; n < m_num_function_units; n++ )
+ m_fu[n]->print(fout);
+ std::string bits = m_result_bus.to_string();
+ fprintf(fout, "EX/WB sched= %s\n", bits.c_str() );
+ fprintf(fout, "EX/WB = ");
+ print_stage(EX_WB, fout);
fprintf(fout, "\n");
- mshr_print(fout,0);
}
unsigned int shader_core_ctx::max_cta( class function_info *kernel )
@@ -1632,43 +1702,20 @@ unsigned int shader_core_ctx::max_cta( class function_info *kernel )
return result;
}
-void shader_core_ctx::cycle_gt200()
+void shader_core_ctx::cycle()
{
- m_pipeline_reg[WB_RT]->clear();
writeback();
- memory();
execute();
- m_operand_collector.step(m_pipeline_reg[ID_OC_SP],m_pipeline_reg[ID_OC_SFU]);
- decode_new();
- fetch_new();
+ m_operand_collector.step();
+ decode();
+ fetch();
}
// Flushes all content of the cache to memory
void shader_core_ctx::cache_flush()
{
- m_L1D->flush();
- // TODO: add flush 'interface' object to provide functionality commented out below
-/*
-
- unsigned int i;
- unsigned int set;
- unsigned long long int flush_addr;
- cache_t *cp = m_L1D;
- cache_block_t *pline;
- for (i=0; i<cp->m_nset*cp->m_assoc; i++) {
- pline = &(cp->m_lines[i]);
- set = i / cp->m_assoc;
- if ((pline->status & (DIRTY|VALID)) == (DIRTY|VALID)) {
- flush_addr = pline->addr;
- fq_push(flush_addr, m_L1D->get_line_sz(), 1, NO_PARTIAL_WRITE, 0, NULL, 0, GLOBAL_ACC_W, -1);
- pline->status &= ~VALID;
- pline->status &= ~DIRTY;
- } else if (pline->status & VALID) {
- pline->status &= ~VALID;
- }
- }
-*/
+ m_ldst_unit->flush();
}
static int *_inmatch;
@@ -2057,43 +2104,42 @@ void mshr_entry::set_status( enum mshr_status status )
#endif
}
-void mshr_entry::print(FILE *fp, unsigned mask) const
+void mshr_entry::print(FILE *fp) const
{
- if ( mask & 0x100 ) {
- fprintf(fp, "MSHR(%u): w%2u req uid=%5u, %s (0x%llx) merged:%d status:%s ",
- m_id,
- m_warp_id,
- m_request_uid,
- (m_iswrite)? "store" : "load ",
- m_addr,
- (m_merged_requests != NULL || m_merged_on_other_reqest),
- MSHR_Status_str[m_status]);
- if ( m_mf )
- ptx_print_insn( m_mf->get_pc(), fp );
- fprintf(fp,"\n");
- }
+ fprintf(fp, "MSHR(%u): w%2u req uid=%5u, %s (0x%llx) merged:%d status:%s ",
+ m_id,
+ m_warp_id,
+ m_request_uid,
+ (m_iswrite)? "store" : "load ",
+ m_addr,
+ (m_merged_requests != NULL || m_merged_on_other_reqest),
+ MSHR_Status_str[m_status]);
+ if ( m_mf )
+ ptx_print_insn( m_mf->get_pc(), fp );
+ fprintf(fp,"\n");
}
-void opndcoll_rfu_t::init( unsigned num_collectors_alu,
- unsigned num_collectors_sfu,
- unsigned num_banks,
- shader_core_ctx *shader,
- warp_inst_t **alu_port,
- warp_inst_t **sfu_port )
+void opndcoll_rfu_t::add_port( unsigned num_collector_units,
+ warp_inst_t **input_port,
+ warp_inst_t **output_port )
+{
+ m_num_ports++;
+ m_num_collectors += num_collector_units;
+ m_input.resize(m_num_ports);
+ m_output.resize(m_num_ports);
+ m_num_collector_units.resize(m_num_ports);
+ m_input[m_num_ports-1]=input_port;
+ m_output[m_num_ports-1]=output_port;
+ m_num_collector_units[m_num_ports-1]=num_collector_units;
+}
+
+void opndcoll_rfu_t::init( unsigned num_banks, shader_core_ctx *shader )
{
- m_num_collectors = num_collectors_alu+num_collectors_sfu;
-
m_shader=shader;
m_arbiter.init(m_num_collectors,num_banks);
-
- m_alu_port = alu_port;
- m_sfu_port = sfu_port;
-
- m_dispatch_units[ m_alu_port ].init( num_collectors_alu );
- m_dispatch_units[ m_sfu_port ].init( num_collectors_sfu );
-
+ for( unsigned n=0; n<m_num_ports;n++ )
+ m_dispatch_units[m_output[n]].init( m_num_collector_units[n] );
m_num_banks = num_banks;
-
m_bank_warp_shift = 0;
m_warp_size = shader->get_config()->warp_size;
m_bank_warp_shift = (unsigned)(int) (log(m_warp_size+0.5) / log(2.0));
@@ -2102,15 +2148,12 @@ void opndcoll_rfu_t::init( unsigned num_collectors_alu,
m_cu = new collector_unit_t[m_num_collectors];
unsigned c=0;
- for(; c<num_collectors_alu; c++) {
- m_cu[c].init(c,m_alu_port,num_banks,m_bank_warp_shift,m_warp_size,this);
- m_free_cu[m_alu_port].push_back(&m_cu[c]);
- m_dispatch_units[m_alu_port].add_cu(&m_cu[c]);
- }
- for(; c<m_num_collectors; c++) {
- m_cu[c].init(c,m_sfu_port,num_banks,m_bank_warp_shift,m_warp_size,this);
- m_free_cu[m_sfu_port].push_back(&m_cu[c]);
- m_dispatch_units[m_sfu_port].add_cu(&m_cu[c]);
+ for( unsigned n=0; n<m_num_ports;n++ ) {
+ for( unsigned j=0; j<m_num_collector_units[n]; j++, c++) {
+ m_cu[c].init(c,m_output[n],num_banks,m_bank_warp_shift,shader->get_config(),this);
+ m_free_cu[m_output[n]].push_back(&m_cu[c]);
+ m_dispatch_units[m_output[n]].add_cu(&m_cu[c]);
+ }
}
}
@@ -2158,18 +2201,14 @@ void opndcoll_rfu_t::dispatch_ready_cu()
}
}
-void opndcoll_rfu_t::allocate_cu( warp_inst_t *&id_oc_reg )
+void opndcoll_rfu_t::allocate_cu( unsigned port_num )
{
- if( !id_oc_reg->empty() ) {
- warp_inst_t **port = NULL;
- if( id_oc_reg->op == SFU_OP )
- port = m_sfu_port;
- else
- port = m_alu_port;
+ if( !(*m_input[port_num])->empty() ) {
+ warp_inst_t **port = m_output[port_num];
if( !m_free_cu[port].empty() ) {
collector_unit_t *cu = m_free_cu[port].back();
m_free_cu[port].pop_back();
- cu->allocate(id_oc_reg);
+ cu->allocate(*m_input[port_num]);
m_arbiter.add_read_requests(cu);
}
}
@@ -2215,7 +2254,7 @@ void opndcoll_rfu_t::collector_unit_t::dump(FILE *fp, const shader_core_ctx *sha
if( m_free ) {
fprintf(fp," <free>\n");
} else {
- shader->print_warp(m_warp,fp,0,0);
+ m_warp->print(fp);
for( unsigned i=0; i < MAX_REG_OPERANDS; i++ ) {
if( m_not_ready.test(i) ) {
std::string r = m_src_op[i].get_reg_string();
@@ -2229,7 +2268,7 @@ void opndcoll_rfu_t::collector_unit_t::init( unsigned n,
warp_inst_t **port,
unsigned num_banks,
unsigned log2_warp_size,
- unsigned warp_size,
+ const shader_core_config *config,
opndcoll_rfu_t *rfu )
{
m_rfu=rfu;
@@ -2237,7 +2276,7 @@ void opndcoll_rfu_t::collector_unit_t::init( unsigned n,
m_port=port;
m_num_banks=num_banks;
assert(m_warp==NULL);
- m_warp = new warp_inst_t(warp_size);
+ m_warp = new warp_inst_t(config);
m_bank_warp_shift=log2_warp_size;
}
diff --git a/src/gpgpu-sim/shader.h b/src/gpgpu-sim/shader.h
index 8e98749..d6ef552 100644
--- a/src/gpgpu-sim/shader.h
+++ b/src/gpgpu-sim/shader.h
@@ -107,8 +107,6 @@
#define WRITE_MASK_SIZE 8
#define NO_PARTIAL_WRITE (partial_write_mask_t())
-#define WORD_SIZE 4
-
//Set a hard limit of 32 CTAs per shader [cuda only has 8]
#define MAX_CTA_PER_SHADER 32
@@ -319,6 +317,7 @@ public:
void init( new_addr_type address, bool wr, memory_space_t space, unsigned warp_id );
void clear() { m_insts.clear(); }
void set_mf( class mem_fetch *mf ) { m_mf=mf; }
+ class mem_fetch *get_mf() { return m_mf; }
void add_inst( warp_inst_t inst ) { m_insts.push_back(inst); }
void set_status( enum mshr_status status );
void merge( mshr_entry *mshr )
@@ -346,7 +345,7 @@ public:
{
done_insts.insert(done_insts.end(),m_insts.begin(),m_insts.end());
}
- void add_to_queue( std::deque<mshr_entry*> &q )
+ void add_to_queue( std::list<mshr_entry*> &q )
{
// place all merged requests in return queue
mshr_entry *req = this;
@@ -380,7 +379,7 @@ public:
return m_insts[0].isatomic();
}
new_addr_type get_addr() const { return m_addr; }
- void print(FILE *fp, unsigned mask) const;
+ void print(FILE *fp) const;
private:
unsigned m_id;
@@ -416,25 +415,22 @@ public:
m_num_banks=0;
m_cu = NULL;
m_shader=NULL;
- m_sfu_port=NULL;
- m_alu_port=NULL;
+ m_num_ports=0;
}
- void init( unsigned num_collectors_alu,
- unsigned num_collectors_sfu,
- unsigned num_banks,
- shader_core_ctx *shader,
- warp_inst_t **alu_port,
- warp_inst_t **sfu_port );
+ void add_port( unsigned num_collector_units,
+ warp_inst_t **input_port,
+ warp_inst_t **output_port );
+ void init( unsigned num_banks, shader_core_ctx *shader );
// modifiers
bool writeback( const warp_inst_t &warp ); // might cause stall
- void step( warp_inst_t *&alu_issue_port, warp_inst_t *&sfu_issue_port )
+ void step()
{
dispatch_ready_cu();
allocate_reads();
- allocate_cu(alu_issue_port);
- allocate_cu(sfu_issue_port);
+ for( unsigned p=0; p < m_num_ports; p++ )
+ allocate_cu( p );
process_banks();
}
@@ -459,7 +455,7 @@ private:
}
void dispatch_ready_cu();
- void allocate_cu( warp_inst_t *&id_oc_reg );
+ void allocate_cu( unsigned port );
void allocate_reads();
// types
@@ -671,7 +667,7 @@ private:
warp_inst_t **port,
unsigned num_banks,
unsigned log2_warp_size,
- unsigned warp_size,
+ const shader_core_config *config,
opndcoll_rfu_t *rfu );
void allocate( warp_inst_t *&pipeline_reg );
@@ -747,8 +743,11 @@ private:
collector_unit_t *m_cu;
arbiter_t m_arbiter;
+ unsigned m_num_ports;
+ std::vector<warp_inst_t**> m_input;
+ std::vector<warp_inst_t**> m_output;
+ std::vector<unsigned> m_num_collector_units;
warp_inst_t **m_alu_port;
- warp_inst_t **m_sfu_port;
typedef std::map<warp_inst_t**/*port*/,dispatch_unit_t> port_to_du_t;
port_to_du_t m_dispatch_units;
@@ -825,7 +824,7 @@ public:
mshr_entry* add_mshr(mem_access_t &access, warp_inst_t* inst);
void mshr_return_from_mem(mshr_entry *mshr);
unsigned get_max_mshr_used() const {return m_max_mshr_used;}
- void print(FILE* fp, class shader_core_ctx* shader,unsigned mask);
+ void print(FILE* fp);
private:
mshr_entry *alloc_free_mshr(bool istexture);
@@ -836,15 +835,15 @@ private:
return (not m_mshr_return_queue.empty()) or
((not m_texture_mshr_pipeline.empty()) and m_texture_mshr_pipeline.front()->fetched());
}
- std::deque<mshr_entry*> &choose_return_queue();
+ std::list<mshr_entry*> &choose_return_queue();
const struct shader_core_config *m_shader_config;
typedef std::vector<mshr_entry> mshr_storage_type;
mshr_storage_type m_mshrs;
- std::deque<mshr_entry*> m_free_list;
- std::deque<mshr_entry*> m_mshr_return_queue;
- std::deque<mshr_entry*> m_texture_mshr_pipeline;
+ std::list<mshr_entry*> m_free_list;
+ std::list<mshr_entry*> m_mshr_return_queue;
+ std::list<mshr_entry*> m_texture_mshr_pipeline;
unsigned m_max_mshr_used;
mshr_lookup m_mshr_lookup;
};
@@ -871,7 +870,196 @@ struct ifetch_buffer_t {
unsigned m_warp_id;
};
-typedef address_type (*tag_func_t)(address_type add, unsigned line_size);
+class simd_function_unit {
+public:
+ simd_function_unit( warp_inst_t **result_port, const shader_core_config *config )
+ {
+ m_result_port = result_port;
+ m_config=config;
+ m_dispatch_reg = new warp_inst_t(config);
+ }
+ ~simd_function_unit() { delete m_dispatch_reg; }
+
+ // modifiers
+ virtual void issue( warp_inst_t *&inst ) { move_warp(m_dispatch_reg,inst); }
+ virtual void cycle() = 0;
+
+ // accessors
+ virtual bool can_issue( const warp_inst_t & ) const { return m_dispatch_reg->empty(); }
+ virtual bool stallable() const = 0;
+ virtual void print( FILE *fp ) const
+ {
+ fprintf(fp,"%s dispatch= ", m_name.c_str() );
+ m_dispatch_reg->print(fp);
+ }
+protected:
+ std::string m_name;
+ const shader_core_config *m_config;
+ warp_inst_t **m_result_port;
+ warp_inst_t *m_dispatch_reg;
+};
+
+class alu : public simd_function_unit {
+public:
+ alu( warp_inst_t **result_port, const shader_core_config *config, unsigned max_latency )
+ : simd_function_unit(result_port,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 );
+ }
+
+ //modifiers
+ virtual void cycle()
+ {
+ if( !m_pipeline_reg[0]->empty() )
+ move_warp(*m_result_port,m_pipeline_reg[0]); // non-stallable pipeline
+ for( unsigned stage=0; (stage+1)<m_pipeline_depth; stage++ )
+ move_warp(m_pipeline_reg[stage], m_pipeline_reg[stage+1]);
+ if( !m_dispatch_reg->empty() ) {
+ if( !m_dispatch_reg->dispatch_delay() ) {
+ int start_stage = m_dispatch_reg->latency - m_dispatch_reg->initiation_interval;
+ move_warp(m_pipeline_reg[start_stage],m_dispatch_reg);
+ }
+ }
+ }
+ virtual void issue( warp_inst_t *&inst )
+ {
+ move_warp(m_dispatch_reg,inst);
+ }
+
+ // accessors
+ virtual bool stallable() const { return false; }
+ virtual bool can_issue( const warp_inst_t &inst ) const
+ {
+ return simd_function_unit::can_issue(inst);
+ }
+ virtual void print(FILE *fp) const
+ {
+ simd_function_unit::print(fp);
+ for( int s=m_pipeline_depth-1; s>=0; s-- ) {
+ if( !m_pipeline_reg[s]->empty() ) {
+ fprintf(fp," %s[%2d] ", m_name.c_str(), s );
+ m_pipeline_reg[s]->print(fp);
+ }
+ }
+ }
+private:
+ unsigned m_pipeline_depth;
+ warp_inst_t **m_pipeline_reg;
+};
+
+class sfu : public alu
+{
+public:
+ sfu( warp_inst_t **result_port, const shader_core_config *config )
+ : alu(result_port,config,config->max_sfu_latency) { m_name = "SFU"; }
+ virtual bool can_issue( const warp_inst_t &inst ) const
+ {
+ switch(inst.op) {
+ case SFU_OP: break;
+ case ALU_SFU_OP: break;
+ default: return false;
+ }
+ return alu::can_issue(inst);
+ }
+};
+
+class sp_unit : public alu
+{
+public:
+ sp_unit( warp_inst_t **result_port, const shader_core_config *config )
+ : alu(result_port,config,config->max_sp_latency) { m_name = "SP "; }
+ virtual bool can_issue( const warp_inst_t &inst ) const
+ {
+ switch(inst.op) {
+ case SFU_OP: return false;
+ case LOAD_OP: return false;
+ case STORE_OP: return false;
+ case MEMORY_BARRIER_OP: return false;
+ default: break;
+ }
+ return alu::can_issue(inst);
+ }
+};
+
+class ldst_unit : public simd_function_unit {
+public:
+ ldst_unit( gpgpu_sim *gpu,
+ shader_core_ctx *core,
+ warp_inst_t **result_port,
+ shader_core_config *config,
+ shader_core_stats *stats,
+ unsigned sid, unsigned tpc );
+
+ // modifiers
+ virtual void cycle();
+ void fill( mem_fetch *mf );
+ void flush();
+
+ // accessors
+ virtual bool can_issue( const warp_inst_t &inst ) const
+ {
+ switch(inst.op) {
+ case LOAD_OP: break;
+ case STORE_OP: break;
+ case MEMORY_BARRIER_OP: break;
+ default: return false;
+ }
+ return simd_function_unit::can_issue(inst);
+ }
+ virtual bool stallable() const { return true; }
+ void print(FILE *fout) const;
+
+private:
+ void generate_mem_accesses(warp_inst_t &pipe_reg);
+ void tex_cache_access(warp_inst_t &inst);
+ void const_cache_access(warp_inst_t &inst);
+
+ bool shared_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type);
+ bool constant_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type);
+ bool texture_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type);
+ bool memory_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type);
+
+ mem_stage_stall_type ccache_check(warp_inst_t &inst, mem_access_t& access){ return NO_RC_FAIL;}
+ mem_stage_stall_type tcache_check(warp_inst_t &inst, mem_access_t& access){ return NO_RC_FAIL;}
+ mem_stage_stall_type dcache_check(warp_inst_t &inst, mem_access_t& access);
+
+ typedef mem_stage_stall_type (ldst_unit::*cache_check_t)(warp_inst_t &,mem_access_t&);
+
+ mem_stage_stall_type process_memory_access_queue( ldst_unit::cache_check_t cache_check,
+ unsigned ports_per_bank,
+ unsigned memory_send_max,
+ warp_inst_t &inst );
+ mem_stage_stall_type send_mem_request(warp_inst_t &inst, mem_access_t &access);
+
+ gpgpu_sim *m_gpu;
+ shader_core_ctx *m_core;
+ unsigned m_sid;
+ unsigned m_tpc;
+
+ cache_t *m_L1D; // data cache (global/local memory accesses)
+ cache_t *m_L1T; // texture cache
+ cache_t *m_L1C; // constant cache
+ mshr_shader_unit *m_mshr_unit;
+
+ enum mem_stage_stall_type m_mem_rc;
+
+ shader_core_stats *m_stats;
+};
+
+enum pipeline_stage_name_t {
+ ID_OC_SP=0,
+ ID_OC_SFU,
+ ID_OC_MEM,
+ OC_EX_SP,
+ OC_EX_SFU,
+ OC_EX_MEM,
+ EX_WB,
+ N_PIPELINE_STAGES
+};
class shader_core_ctx : public core_t
{
@@ -880,12 +1068,11 @@ public:
const char *name,
unsigned shader_id,
unsigned tpc_id,
- const struct shader_core_config *config,
+ struct shader_core_config *config,
struct shader_core_stats *stats );
void issue_block2core( class kernel_info_t &kernel );
void get_pdom_stack_top_info( unsigned tid, unsigned *pc, unsigned *rpc );
- void new_cache_window();
bool ptx_thread_done( unsigned hw_thread_id ) const;
class ptx_thread_info *get_thread_state( unsigned hw_thread_id );
@@ -900,7 +1087,7 @@ public:
void deallocate_barrier( unsigned cta_id );
void decrement_atomic_count( unsigned wid );
- void cycle_gt200();
+ void cycle();
void reinit(unsigned start_thread, unsigned end_thread, bool reset_not_completed );
void init_warps(unsigned cta_id, unsigned start_thread, unsigned end_thread);
@@ -913,10 +1100,8 @@ public:
void fill_shd_L1_with_new_line( class mem_fetch * mf );
void store_ack( class mem_fetch *mf );
void dump_istream_state( FILE *fout );
- void mshr_print(FILE* fp, unsigned mask);
unsigned first_valid_thread( unsigned stage );
class ptx_thread_info* get_functional_thread( unsigned tid ) { return m_thread[tid].m_functional_model_thread_state; }
- void print_warp( warp_inst_t *warp, FILE *fout, int print_mem, int mask ) const;
std::list<unsigned> get_regs_written( const inst_t &fvt ) const;
const shader_core_config *get_config() const { return m_config; }
unsigned get_num_sim_insn() const { return m_num_sim_insn; }
@@ -927,14 +1112,8 @@ public:
unsigned get_thread_n_l1_mis_ac( unsigned tid ) const { return m_thread[tid].n_l1_mis_ac; }
unsigned get_thread_n_l1_mrghit_ac( unsigned tid ) const { return m_thread[tid].n_l1_mrghit_ac; }
unsigned get_thread_n_l1_access_ac( unsigned tid ) const { return m_thread[tid].n_l1_access_ac; }
- unsigned get_max_mshr_used() const { return m_mshr_unit->get_max_mshr_used(); }
- void L1cache_print( FILE *fp, unsigned &total_accesses, unsigned &total_misses) const;
- void L1texcache_print( FILE *fp, unsigned &total_accesses, unsigned &total_misses) const;
- void L1constcache_print( FILE *fp, unsigned &total_accesses, unsigned &total_misses) const;
unsigned get_n_active_cta() const { return m_n_active_cta; }
- float L1_windowed_cache_miss_rate( int x ) const { return m_L1D->shd_cache_windowed_cache_miss_rate(x); }
- float L1tex_windowed_cache_miss_rate( int x ) const { return m_L1T->shd_cache_windowed_cache_miss_rate(x); }
- float L1const_windowed_cache_miss_rate( int x ) const { return m_L1C->shd_cache_windowed_cache_miss_rate(x); }
+ void inc_store_req( unsigned warp_id) { m_warp[warp_id].inc_store_req(); }
private:
@@ -942,64 +1121,20 @@ private:
address_type next_pc( int tid ) const;
- void func_exec_inst( warp_inst_t &inst );
- void fetch_new();
+ void fetch();
+
+ void decode();
void issue_warp( warp_inst_t *&warp, const warp_inst_t *pI, unsigned active_mask, unsigned warp_id );
- void decode_new();
+ void func_exec_inst( warp_inst_t &inst );
+ address_type translate_local_memaddr(address_type localaddr, unsigned tid, unsigned num_shader );
void execute();
- void execute_pipe( unsigned pipeline, unsigned next_stage );
-
- void memory(); // advance memory pipeline stage
- void memory_queue(warp_inst_t &pipe_reg);
- void memory_shared_process_warp(warp_inst_t &inst);
- void memory_const_process_warp(warp_inst_t &inst);
- void memory_texture_process_warp(warp_inst_t &inst);
- void memory_global_process_warp(warp_inst_t &inst);
- bool memory_shared_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type);
- bool memory_constant_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type);
- bool memory_texture_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type);
- bool memory_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type);
- address_type translate_local_memaddr(address_type localaddr, int tid, unsigned num_shader );
-
- mem_stage_stall_type ccache_check(warp_inst_t &inst, mem_access_t& access){ return NO_RC_FAIL;}
- mem_stage_stall_type tcache_check(warp_inst_t &inst, mem_access_t& access){ return NO_RC_FAIL;}
- mem_stage_stall_type dcache_check(warp_inst_t &inst, mem_access_t& access);
-
- typedef mem_stage_stall_type (shader_core_ctx::*cache_check_t)(warp_inst_t &,mem_access_t&);
-
- mem_stage_stall_type process_memory_access_queue( shader_core_ctx::cache_check_t cache_check,
- unsigned ports_per_bank,
- unsigned memory_send_max,
- warp_inst_t &inst );
-
- typedef int (shader_core_ctx::*bank_func_t)(address_type add, unsigned line_size);
-
- int null_bank_func(address_type add, unsigned line_size);
- int shmem_bank_func(address_type add, unsigned line_size);
- int dcache_bank_func(address_type add, unsigned line_size);
-
- void get_memory_access_list( bank_func_t bank_func,
- tag_func_t tag_func,
- unsigned warp_parts,
- unsigned line_size,
- bool limit_broadcast,
- warp_inst_t &inst );
- mem_stage_stall_type send_mem_request(warp_inst_t &inst, mem_access_t &access);
void writeback();
- unsigned char fq_push( unsigned long long int addr,
- int bsize,
- unsigned char write,
- partial_write_mask_t partial_write_mask,
- int wid, mshr_entry* mshr,
- enum mem_access_type mem_acc,
- address_type pc );
-
void call_thread_done(inst_t &done_inst );
- void print_stage(unsigned int stage, FILE *fout, int print_mem, int mask );
+ void print_stage(unsigned int stage, FILE *fout) const;
// general information
unsigned m_sid; // shader id
@@ -1020,37 +1155,29 @@ private:
// thread contexts
thread_ctx_t *m_thread; // functional state, per thread fetch state
+
+ // fetch
+ cache_t *m_L1I; // instruction cache
+ int m_last_warp_fetched;
+
+ // decode/dispatch
+ int m_last_warp_issued;
std::vector<shd_warp_t> m_warp; // per warp information array
barrier_set_t m_barriers;
ifetch_buffer_t m_inst_fetch_buffer;
pdom_warp_ctx_t **m_pdom_warp; // pdom reconvergence context for each warp
-
warp_inst_t** m_pipeline_reg;
Scoreboard *m_scoreboard;
opndcoll_rfu_t m_operand_collector;
- mshr_shader_unit *m_mshr_unit;
- // fetch
- int m_last_warp_fetched;
- int m_last_warp_issued;
-
- cache_t *m_L1I; // instruction cache
- cache_t *m_L1D; // data cache (global/local memory accesses)
- cache_t *m_L1T; // texture cache
- cache_t *m_L1C; // constant cache
-
- enum mem_stage_stall_type m_mem_rc;
-};
-
-enum pipeline_stage_name_t {
- ID_OC_SP=0,
- ID_OC_SFU,
- OC_EX_SP,
- OC_EX_SFU,
- EX_MM,
- MM_WB,
- WB_RT,
- N_PIPELINE_STAGES
+ // execute
+ unsigned m_num_function_units;
+ enum pipeline_stage_name_t *m_dispatch_port;
+ enum pipeline_stage_name_t *m_issue_port;
+ simd_function_unit **m_fu; // stallable pipelines should be last in this array
+ ldst_unit *m_ldst_unit;
+ static const unsigned MAX_ALU_LATENCY = 64;
+ std::bitset<MAX_ALU_LATENCY> m_result_bus;
};
#endif /* SHADER_H */
diff --git a/src/gpgpu-sim/stats.h b/src/gpgpu-sim/stats.h
index 76e6699..2c494eb 100644
--- a/src/gpgpu-sim/stats.h
+++ b/src/gpgpu-sim/stats.h
@@ -133,6 +133,9 @@ struct shader_core_stats
int n_pdom_sc_orig_stat;
int n_pdom_sc_single_stat;
+
+ unsigned made_write_mfs;
+ unsigned made_read_mfs;
};
#endif
diff --git a/src/gpgpu-sim/visualizer.cc b/src/gpgpu-sim/visualizer.cc
index fd0a422..4474dcd 100644
--- a/src/gpgpu-sim/visualizer.cc
+++ b/src/gpgpu-sim/visualizer.cc
@@ -142,6 +142,7 @@ void gpgpu_sim::visualizer_printstat()
shader_CTA_count_visualizer_gzprint(visualizer_file);
// per shader core cache miss rate
+/*
gzprintf(visualizer_file, "CacheMissRate_GlobalLocalL1_All: ");
for (unsigned i=0;i<m_n_shader;i++)
gzprintf(visualizer_file, "%0.4f ", m_sc[i]->L1_windowed_cache_miss_rate(0));
@@ -166,10 +167,10 @@ void gpgpu_sim::visualizer_printstat()
for (unsigned i=0;i<m_n_shader;i++)
gzprintf(visualizer_file, "%0.4f ", m_sc[i]->L1const_windowed_cache_miss_rate(1));
gzprintf(visualizer_file, "\n");
-
// reset for next interval
for (unsigned i=0;i<m_n_shader;i++)
m_sc[i]->new_cache_window();
+*/
for (unsigned i=0;i<m_n_mem;i++)
m_memory_partition_unit[i]->visualizer_print(visualizer_file);