diff options
| -rw-r--r-- | configs/QuadroFX5800/gpgpusim.config | 4 | ||||
| -rw-r--r-- | src/abstract_hardware_model.cc | 4 | ||||
| -rw-r--r-- | src/abstract_hardware_model.h | 107 | ||||
| -rw-r--r-- | src/cuda-sim/cuda-sim.cc | 102 | ||||
| -rw-r--r-- | src/cuda-sim/ptx_ir.cc | 3 | ||||
| -rw-r--r-- | src/cuda-sim/ptx_ir.h | 11 | ||||
| -rw-r--r-- | src/cuda-sim/ptx_parser.cc | 10 | ||||
| -rw-r--r-- | src/gpgpu-sim/gpu-sim.cc | 52 | ||||
| -rw-r--r-- | src/gpgpu-sim/gpu-sim.h | 47 | ||||
| -rw-r--r-- | src/gpgpu-sim/mem_fetch.cc | 2 | ||||
| -rw-r--r-- | src/gpgpu-sim/shader.cc | 893 | ||||
| -rw-r--r-- | src/gpgpu-sim/shader.h | 345 | ||||
| -rw-r--r-- | src/gpgpu-sim/stats.h | 3 | ||||
| -rw-r--r-- | src/gpgpu-sim/visualizer.cc | 3 |
14 files changed, 894 insertions, 692 deletions
diff --git a/configs/QuadroFX5800/gpgpusim.config b/configs/QuadroFX5800/gpgpusim.config index 2805674..e5e29bc 100644 --- a/configs/QuadroFX5800/gpgpusim.config +++ b/configs/QuadroFX5800/gpgpusim.config @@ -4,7 +4,6 @@ -gpgpu_ptx_force_max_capability 11 # high level architecture configuration --gpgpu_sm_uarch GT200 -gpgpu_n_shader 30 -gpgpu_n_mem 8 -gpgpu_clock_domains 325.0:650.0:650.0:800.0 @@ -56,8 +55,7 @@ -gpgpu_ptx_save_converted_ptxplus 1 # enable operand collector --gpgpu_operand_collector 1 --gpgpu_operand_collector_num_units 6 +-gpgpu_operand_collector_num_units_sp 6 -gpgpu_operand_collector_num_units_sfu 8 -visualizer_enabled 0 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); |
