summaryrefslogtreecommitdiff
path: root/src/gpgpu-sim/shader.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/gpgpu-sim/shader.cc')
-rw-r--r--src/gpgpu-sim/shader.cc893
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;
}