diff options
| author | Tor Aamodt <[email protected]> | 2010-10-10 21:19:52 -0800 |
|---|---|---|
| committer | Tor Aamodt <[email protected]> | 2010-10-10 21:19:52 -0800 |
| commit | b3ce70a797756285ea9b15b3e5cf515d8b6a2b63 (patch) | |
| tree | 5b84d880e646f80611cc5b01931fdde622c5e06c /src/gpgpu-sim/shader.cc | |
| parent | 0151c5c566dcbcbb962acf35c86a8e0f4a4a6eb6 (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/gpgpu-sim/shader.cc')
| -rw-r--r-- | src/gpgpu-sim/shader.cc | 893 |
1 files changed, 466 insertions, 427 deletions
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; } |
