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.cc1601
1 files changed, 166 insertions, 1435 deletions
diff --git a/src/gpgpu-sim/shader.cc b/src/gpgpu-sim/shader.cc
index 495c4c0..976671a 100644
--- a/src/gpgpu-sim/shader.cc
+++ b/src/gpgpu-sim/shader.cc
@@ -69,8 +69,6 @@
#include "gpu-sim.h"
#include "addrdec.h"
#include "dram.h"
-#include "dwf.h"
-#include "warp_tracker.h"
#include "stat-tool.h"
#include "gpu-misc.h"
#include "../cuda-sim/ptx_sim.h"
@@ -308,40 +306,11 @@ unsigned char shader_core_ctx::fq_push(unsigned long long int addr,
return(m_gpu->issue_mf_from_fq(mf));
}
-inst_t *shader_core_ctx::first_valid_thread( inst_t *warp )
+unsigned shader_core_ctx::first_valid_thread( unsigned stage )
{
- for(unsigned t=0; t < m_config->warp_size; t++ )
- if( warp[t].hw_thread_id != -1 )
- return warp+t;
- return NULL;
+ abort();
}
-inst_t *shader_core_ctx::first_valid_thread( unsigned stage )
-{
- return first_valid_thread(m_pipeline_reg[stage]);
-}
-
-void shader_core_ctx::move_warp( inst_t *&dst, inst_t *&src )
-{
-
- assert( pipeline_regster_empty(dst) );
- inst_t* temp = dst;
- dst = src;
- src = temp;
- for( unsigned t=0; t < m_config->warp_size; t++)
- src[t] = inst_t();
-}
-
-void shader_core_ctx::clear_stage( inst_t *warp )
-{
- for( unsigned t=0; t < m_config->warp_size; t++)
- warp[t] = inst_t();
-}
-
-bool shader_core_ctx::pipeline_regster_empty( inst_t *reg )
-{
- return first_valid_thread(reg) == NULL;
-}
void shader_core_ctx::L1cache_print( FILE *fp, unsigned &total_accesses, unsigned &total_misses) const
{
@@ -390,28 +359,14 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu,
m_config = config;
m_stats = stats;
unsigned warp_size=config->warp_size;
- assert( !((config->model == DWF) && m_config->gpgpu_operand_collector) );
m_name = name;
m_sid = shader_id;
m_tpc = tpc_id;
- m_dwf_RR_k = 0;
- m_pipeline_reg = (inst_t**) calloc(N_PIPELINE_STAGES, sizeof(inst_t*));
- for (int j = 0; j<N_PIPELINE_STAGES; j++) {
- m_pipeline_reg[j] = (inst_t*) calloc(warp_size, sizeof(inst_t));
- for (unsigned i=0; i<warp_size; i++)
- m_pipeline_reg[j][i] = inst_t();
- }
+ 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);
- if (m_config->gpgpu_pre_mem_stages) {
- pre_mem_pipeline = (inst_t**) calloc(m_config->gpgpu_pre_mem_stages+1, sizeof(inst_t*));
- for (unsigned j = 0; j<=m_config->gpgpu_pre_mem_stages; j++) {
- pre_mem_pipeline[j] = (inst_t*) calloc(warp_size, sizeof(inst_t));
- for (unsigned i=0; i<warp_size; i++) {
- pre_mem_pipeline[j][i] = inst_t();
- }
- }
- }
m_thread = (thread_ctx_t*) calloc(sizeof(thread_ctx_t), config->n_thread_per_shader);
m_not_completed = 0;
@@ -420,11 +375,8 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu,
m_n_active_cta = 0;
for (unsigned i = 0; i<MAX_CTA_PER_SHADER; i++ )
m_cta_status[i]=0;
- m_next_warp = 0;
for (unsigned i = 0; i<config->n_thread_per_shader; i++) {
m_thread[i].m_functional_model_thread_state = NULL;
- m_thread[i].m_avail4fetch = false;
- m_thread[i].m_waiting_at_barrier = false;
m_thread[i].m_cta_id = -1;
}
@@ -449,8 +401,6 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu,
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);
- if (m_config->using_commit_queue)
- m_thd_commit_queue = new fifo_pipeline<std::vector<int> >("thd_commit_queue", 0, 0,gpu_sim_cycle);
m_shader_memory_new_instruction_processed = false;
// Initialize scoreboard
@@ -477,27 +427,12 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu,
// fetch
m_last_warp_fetched = 0;
m_last_warp_issued = 0;
- m_ready_warps = (int*)calloc(m_config->max_warps_per_shader,sizeof(int));
- m_tmp_ready_warps = (int*)calloc(m_config->max_warps_per_shader,sizeof(int));
- m_last_warp=0;
- m_last_issued_thread=0; // MIMD
-
- m_warp_tracker = NULL;
- m_thread_pc_tracker = NULL;
- if (m_config->gpgpu_no_divg_load) {
- m_warp_tracker = new warp_tracker_pool(this);
- m_thread_pc_tracker = new thread_pc_tracker(warp_size, config->n_thread_per_shader);
- }
- m_fetch_tid_out = (int*) malloc(sizeof(int) * warp_size);
- m_dwf_rrstage_bank_access_counter = (int*) malloc(sizeof(int) * m_config->gpgpu_dwf_rr_stage_n_reg_banks);
}
void shader_core_ctx::reinit(unsigned start_thread, unsigned end_thread, bool reset_not_completed )
{
if( reset_not_completed )
m_not_completed = 0;
- m_next_warp = 0;
- m_last_issued_thread=0;
for (unsigned i = start_thread; i<end_thread; i++) {
m_thread[i].n_insn = 0;
m_thread[i].m_cta_id = -1;
@@ -508,9 +443,8 @@ void shader_core_ctx::reinit(unsigned start_thread, unsigned end_thread, bool re
}
}
-void shader_core_ctx::init_warps( unsigned start_thread, unsigned end_thread )
+void shader_core_ctx::init_warps( unsigned cta_id, unsigned start_thread, unsigned end_thread )
{
- unsigned num_threads = end_thread - start_thread;
address_type start_pc = next_pc(start_thread);
if (m_config->model == POST_DOMINATOR) {
unsigned start_warp = start_thread / m_config->warp_size;
@@ -525,45 +459,16 @@ void shader_core_ctx::init_warps( unsigned start_thread, unsigned end_thread )
}
}
m_pdom_warp[i]->launch(start_pc,initial_active_mask);
- m_warp[i].init(start_pc,i,n_active);
+ m_warp[i].init(start_pc,cta_id,i,n_active);
m_not_completed += n_active;
}
- } else if (m_config->model == DWF) {
- dwf_init_CTA(m_sid, start_thread, num_threads, start_pc);
- for (unsigned i = start_thread; i<end_thread; i++)
- m_thread[i].m_in_scheduler = true;
- }
- for (unsigned tid=start_thread;tid<end_thread;tid++) {
- m_thread[tid].m_avail4fetch = true;
- }
-}
-
-// register id for unused register slot in instruction
-#define DNA (0)
-
-unsigned g_next_shader_inst_uid=1;
-
-bool shader_core_ctx::fetch_stalled()
-{
- for (unsigned i=0; i<m_config->warp_size; i++) {
- if (m_pipeline_reg[TS_IF][i].hw_thread_id != -1 ) {
- return true; // stalled
- }
}
- for (unsigned i=0; i<m_config->warp_size; i++) {
- if (m_pipeline_reg[IF_ID][i].hw_thread_id != -1 ) {
- return true; // stalled
- }
- }
-
- m_new_warp_TS = true;
- return false; // not stalled
}
// initalize the pipeline stage register to nops
void shader_core_ctx::clear_stage_reg(int stage)
{
- clear_stage( m_pipeline_reg[stage] );
+ m_pipeline_reg[stage]->clear();
}
// return the next pc of a thread
@@ -577,186 +482,6 @@ address_type shader_core_ctx::next_pc( int tid ) const
return the_thread->get_pc(); // PC should already be updatd to next PC at this point (was set in shader_decode() last time thread ran)
}
-// issue thread to the warp
-// tid - thread id, warp_id - used by PDOM, wlane - position in warp
-void shader_core_ctx::shader_issue_thread(int tid, int wlane, unsigned active_mask )
-{
- m_thread[tid].m_functional_model_thread_state->ptx_fetch_inst( m_pipeline_reg[TS_IF][wlane] );
- m_pipeline_reg[TS_IF][wlane].hw_thread_id = tid;
- m_pipeline_reg[TS_IF][wlane].wlane = wlane;
- m_pipeline_reg[TS_IF][wlane].memreqaddr = 0;
- m_pipeline_reg[TS_IF][wlane].uid = g_next_shader_inst_uid++;
- m_pipeline_reg[TS_IF][wlane].warp_active_mask = active_mask;
- m_pipeline_reg[TS_IF][wlane].issue_cycle = gpu_tot_sim_cycle + gpu_sim_cycle;
-
- assert( m_thread[tid].m_avail4fetch );
- m_thread[tid].m_avail4fetch = false;
- assert( m_warp[wid_from_hw_tid(tid,m_config->warp_size)].get_avail4fetch() > 0 );
- m_warp[wid_from_hw_tid(tid,m_config->warp_size)].dec_avail4fetch();
-}
-
-int shader_core_ctx::pdom_sched_find_next_warp (int ready_warp_count)
-{
- bool found = false;
- int selected_warp = m_ready_warps[0];
- switch (m_config->pdom_sched_type) {
- case 0: selected_warp = m_ready_warps[0]; found=true; break; // first ok warp found
- case 1: selected_warp = m_ready_warps[rand()%ready_warp_count]; found=true; break; //random
- case 8:
- // "loose" round robin:
- // execute the next available warp which is after the warp execued last time
- selected_warp = (m_last_warp + 1) % m_config->max_warps_per_shader;
- while (!found) {
- for (int i=0;i<ready_warp_count;i++) {
- if (selected_warp==m_ready_warps[i])
- found=true;
- }
- if( !found )
- selected_warp = (selected_warp + 1) % m_config->max_warps_per_shader;
- }
- break;
- default: assert(0);
- }
- if (found) {
- if (ready_warp_count==1)
- m_stats->n_pdom_sc_single_stat++;
- else
- m_stats->n_pdom_sc_orig_stat++;
- return selected_warp;
- } else {
- return -1;
- }
-}
-
-void shader_core_ctx::fetch_simd_postdominator()
-{
- int warp_ok = 0;
- bool complete = false;
- int tmp_warp;
- int warp_id;
-
- address_type check_pc = -1;
-
- // First, check to see if entire program is completed,
- // if it is, then break out of loop
- for (unsigned i=0; i<m_config->n_thread_per_shader; i++) {
- if (!ptx_thread_done(i)) {
- complete = false;
- break;
- } else {
- complete = true;
- }
- }
- if (complete)
- return;
-
- if (fetch_stalled())
- return;
- clear_stage_reg(TS_IF);
-
- unsigned ready_warp_count = 0;
- for (unsigned i=0; i<m_config->max_warps_per_shader; i++) {
- m_ready_warps[i]=-1;
- m_tmp_ready_warps[i]=-1;
- }
-
- // Finds a warp where all threads in it are available for fetching
- // simultaneously(all threads are not yet in pipeline, or, the ones
- // that are not available, are completed already
- for (unsigned i=0; i<m_config->max_warps_per_shader; i++) {
- if( m_warp[m_next_warp].waiting() ) {
- // waiting for kernel launch, barrier, membar, atomic
- } else if( (m_warp[m_next_warp].get_n_completed()+m_warp[m_next_warp].get_avail4fetch()) < m_config->warp_size) {
- // waiting for instruction still in pipeline barrel processing
- } else if ( !warp_scoreboard_hazard(m_next_warp) ) {
- // this warp is ready and can be issued if selected
- m_tmp_ready_warps[ready_warp_count] = m_next_warp;
- ready_warp_count++;
- }
- m_next_warp = (m_next_warp + 1) % m_config->max_warps_per_shader;
- }
- for (unsigned i=0;i<ready_warp_count;i++)
- m_ready_warps[i]=m_tmp_ready_warps[i];
- m_stats->num_warps_issuable[ready_warp_count]++;
- m_stats->num_warps_issuable_pershader[m_sid]+= ready_warp_count;
- if (ready_warp_count) {
- tmp_warp = pdom_sched_find_next_warp (ready_warp_count);
- if (tmp_warp != -1) {
- m_next_warp = tmp_warp;
- warp_ok=1;
- }
- }
-
- if (!warp_ok) {
- // None of the instructions from inside the warp can be scheduled -> should
- // probably just stall, ie nops into pipeline
- clear_stage_reg(TS_IF);
- m_next_warp = (m_next_warp+1) % m_config->max_warps_per_shader;
- return;
- }
-
- /************************************************************/
- // at this point we have a warp to execute which is pointed to by next_warp
-
- warp_id = m_next_warp;
- m_last_warp = warp_id;
- int wtid = m_config->warp_size*warp_id;
- pdom_warp_ctx_t *scheduled_warp = m_pdom_warp[warp_id];
-
- // schedule threads according to active mask on the top of pdom stack
- unsigned active_mask = scheduled_warp->get_active_mask();
-
- for (unsigned i = 0; i < m_config->warp_size; i++) {
- unsigned int mask = (1 << i);
- if ((active_mask & mask) == mask) {
- assert (!ptx_thread_done(wtid+i));
- shader_issue_thread(wtid+i,i,active_mask);
- }
- }
- m_next_warp = (m_next_warp+1)%m_config->max_warps_per_shader;
-
- // check if all issued threads have the same pc
- for (unsigned i = 0; i < m_config->warp_size; i++) {
- if ( m_pipeline_reg[TS_IF][i].hw_thread_id != -1 ) {
- if ( check_pc == (unsigned)-1 ) {
- check_pc = m_pipeline_reg[TS_IF][i].pc;
- } else {
- assert( check_pc == m_pipeline_reg[TS_IF][i].pc );
- }
- }
- }
-}
-
-/**
- * check if warp has data hazard
- *
- * @param warp_id
- *
- * @return bool : false if hazard exists
- */
-bool shader_core_ctx::warp_scoreboard_hazard(int warp_id)
-{
- inst_t active_inst;
-
- // Get an active thread in the warp
- int wtid = m_config->warp_size*warp_id;
- pdom_warp_ctx_t *scheduled_warp = m_pdom_warp[warp_id];
- thread_ctx_t *active_thread = NULL;
- unsigned active_mask = scheduled_warp->get_active_mask();
- for (unsigned i = 0; i < m_config->warp_size; i++) {
- unsigned int mask = (1 << i);
- if ((active_mask & mask) == mask) {
- active_thread = &(m_thread[wtid+i]);
- }
- }
- if(active_thread == NULL)
- return false;
-
- // Decode instruction
- active_thread->m_functional_model_thread_state->ptx_fetch_inst( active_inst );
- return m_scoreboard->checkCollision(warp_id, &active_inst);
-}
-
void pdom_warp_ctx_t::pdom_update_warp_mask()
{
int wtid = m_warp_size*m_warp_id;
@@ -892,213 +617,6 @@ void shader_core_ctx::new_cache_window()
m_L1C->shd_cache_new_window();
}
-void shader_core_ctx::fetch_mimd()
-{
- if (fetch_stalled())
- return;
- clear_stage_reg(TS_IF);
-
- for (unsigned i=0, j=0;i<m_config->n_thread_per_shader && j< m_config->warp_size;i++) {
- int thd_id = (i + m_last_issued_thread + 1) % m_config->n_thread_per_shader;
- if (m_thread[thd_id].m_avail4fetch && !m_thread[thd_id].m_waiting_at_barrier ) {
- shader_issue_thread(thd_id, j,(unsigned)-1);
- m_last_issued_thread = thd_id;
- j++;
- }
- }
-}
-
-// seperate the incoming warp into multiple warps with seperate pcs
-int shader_core_ctx::split_warp_by_pc(int *tid_in, int **tid_split, address_type *pc)
-{
- unsigned n_pc = 0;
- static int *pc_cnt = NULL; // count the number of threads with the same pc
-
- assert(tid_in);
- assert(tid_split);
- assert(pc);
- memset(pc,0,sizeof(address_type)*m_config->warp_size);
-
- if (!pc_cnt) pc_cnt = (int*) malloc(sizeof(int)*m_config->warp_size);
- memset(pc_cnt,0,sizeof(int)*m_config->warp_size);
-
- // go through each thread in the given warp
- for (unsigned i=0; i< m_config->warp_size; i++) {
- if (tid_in[i] < 0) continue;
- int matched = 0;
- address_type thd_pc;
- thd_pc = next_pc(tid_in[i]);
-
- // check to see if the pc has occured before
- for (unsigned j=0; j<n_pc; j++) {
- if (thd_pc == pc[j]) {
- tid_split[j][pc_cnt[j]] = tid_in[i];
- pc_cnt[j]++;
- matched = 1;
- break;
- }
- }
- // if not, put the tid in a seperate warp
- if (!matched) {
- assert(n_pc < m_config->warp_size);
- tid_split[n_pc][0] = tid_in[i];
- pc[n_pc] = thd_pc;
- pc_cnt[n_pc] = 1;
- n_pc++;
- }
- }
- return n_pc;
-}
-
-// see if this warp just executed the barrier instruction
-int shader_core_ctx::warp_reached_barrier(int *tid_in)
-{
- int reached_barrier = 0;
- for (unsigned i=0; i<m_config->warp_size; i++) {
- if (tid_in[i] < 0) continue;
- if (m_thread[tid_in[i]].m_reached_barrier) {
- reached_barrier = 1;
- break;
- }
- }
- return reached_barrier;
-}
-
-// seperate the incoming warp into multiple warps with seperate pcs and cta
-int shader_core_ctx::split_warp_by_cta(int *tid_in, int **tid_split, address_type *pc, int *cta)
-{
- unsigned n_pc = 0;
- static int *pc_cnt = NULL; // count the number of threads with the same pc
-
- assert(tid_in);
- assert(tid_split);
- assert(pc);
- memset(pc,0,sizeof(address_type)*m_config->warp_size);
-
- if (!pc_cnt) pc_cnt = (int*) malloc(sizeof(int)*m_config->warp_size);
- memset(pc_cnt,0,sizeof(int)*m_config->warp_size);
-
- // go through each thread in the given warp
- for (unsigned i=0; i<m_config->warp_size; i++) {
- if (tid_in[i] < 0) continue;
- int matched = 0;
- address_type thd_pc;
- thd_pc = next_pc(tid_in[i]);
-
- int thd_cta = ptx_thread_get_cta_uid( m_thread[tid_in[i]].m_functional_model_thread_state );
-
- // check to see if the pc has occured before
- for (unsigned j=0; j<n_pc; j++) {
- if (thd_pc == pc[j] && thd_cta == cta[j]) {
- tid_split[j][pc_cnt[j]] = tid_in[i];
- pc_cnt[j]++;
- matched = 1;
- break;
- }
- }
- // if not, put the tid in a seperate warp
- if (!matched) {
- assert(n_pc < m_config->warp_size);
- tid_split[n_pc][0] = tid_in[i];
- pc[n_pc] = thd_pc;
- cta[n_pc] = thd_cta;
- pc_cnt[n_pc] = 1;
- n_pc++;
- }
- }
- return n_pc;
-}
-
-void shader_core_ctx::fetch_simd_dwf()
-{
- static int *tid_in = NULL;
- static int *tid_out = NULL;
-
- if (!tid_in) {
- tid_in = (int*) malloc(sizeof(int)*m_config->warp_size);
- memset(tid_in, -1, sizeof(int)*m_config->warp_size);
- }
- if (!tid_out) {
- tid_out = (int*) malloc(sizeof(int)*m_config->warp_size);
- memset(tid_out, -1, sizeof(int)*m_config->warp_size);
- }
-
-
- static int **tid_split = NULL;
- if (!tid_split) {
- tid_split = (int**)malloc(sizeof(int*)*m_config->warp_size);
- tid_split[0] = (int*)malloc(sizeof(int)*m_config->warp_size*m_config->warp_size);
- for (unsigned i=1; i<m_config->warp_size; i++) {
- tid_split[i] = tid_split[0] + m_config->warp_size * i;
- }
- }
-
- static address_type *thd_pc = NULL;
- if (!thd_pc) thd_pc = (address_type*)malloc(sizeof(address_type)*m_config->warp_size);
- static int *thd_cta = NULL;
- if (!thd_cta) thd_cta = (int*)malloc(sizeof(int)*m_config->warp_size);
-
- int warpupdate_bw = 1;
- while (!m_thd_commit_queue->empty() && warpupdate_bw > 0) {
- // grab a committed warp, split it into multiple BRUs (tid_split) by PC
- std::vector<int> *tid_commit = m_thd_commit_queue->pop(gpu_sim_cycle);
- memset(tid_split[0], -1, sizeof(int)*m_config->warp_size*m_config->warp_size);
- memset(thd_pc, 0, sizeof(address_type)*m_config->warp_size);
- memset(thd_cta, -1, sizeof(int)*m_config->warp_size);
-
- int reached_barrier = warp_reached_barrier(tid_commit->data());
-
- unsigned n_warp_update;
- if (reached_barrier) {
- n_warp_update = split_warp_by_cta(tid_commit->data(), tid_split, thd_pc, thd_cta);
- } else {
- n_warp_update = split_warp_by_pc(tid_commit->data(), tid_split, thd_pc);
- }
-
- if (n_warp_update > 2) m_stats->gpgpu_commit_pc_beyond_two++;
- warpupdate_bw -= n_warp_update;
- // put the splitted warp updates into the DWF scheduler
- for (unsigned i=0;i<n_warp_update;i++) {
- for (unsigned j=0;j<m_config->warp_size;j++) {
- if (tid_split[i][j] < 0) continue;
- assert(m_thread[tid_split[i][j]].m_avail4fetch);
- assert(!m_thread[tid_split[i][j]].m_in_scheduler);
- m_thread[tid_split[i][j]].m_in_scheduler = true;
- }
- dwf_clear_accessed(m_sid);
- if (reached_barrier) {
- dwf_update_warp_at_barrier(m_sid, tid_split[i], thd_pc[i], thd_cta[i]);
- } else {
- dwf_update_warp(m_sid, tid_split[i], thd_pc[i]);
- }
- }
-
- delete tid_commit;
- }
-
- // Track the #PC right after the warps are input to the scheduler
- dwf_update_statistics(m_sid);
- dwf_clear_policy_access(m_sid);
-
- if (fetch_stalled()) {
- return;
- }
- clear_stage_reg(TS_IF);
-
- address_type scheduled_pc;
- dwf_issue_warp(m_sid, tid_out, &scheduled_pc);
-
- for (unsigned i=0; i<m_config->warp_size; i++) {
- int issue_tid = tid_out[i];
- if (issue_tid >= 0) {
- shader_issue_thread(issue_tid, i, (unsigned)-1);
- m_thread[issue_tid].m_in_scheduler = false;
- m_thread[issue_tid].m_reached_barrier = false;
- assert(m_pipeline_reg[TS_IF][i].pc == scheduled_pc);
- }
- }
-}
-
void gpgpu_sim::print_shader_cycle_distro( FILE *fout ) const
{
fprintf(fout, "Warp Occupancy Distribution:\n");
@@ -1120,11 +638,11 @@ void shader_core_ctx::fetch_new()
if( m_inst_fetch_buffer.m_valid ) {
// decode 1 or 2 instructions and place them into ibuffer
address_type pc = m_inst_fetch_buffer.m_pc;
- const inst_t* pI1 = ptx_fetch_inst(pc);
+ const warp_inst_t* pI1 = ptx_fetch_inst(pc);
assert(pI1);
m_warp[m_inst_fetch_buffer.m_warp_id].ibuffer_fill(0,pI1);
m_warp[m_inst_fetch_buffer.m_warp_id].inc_inst_in_pipeline();
- const inst_t* pI2 = ptx_fetch_inst(pc+pI1->isize);
+ const warp_inst_t* pI2 = ptx_fetch_inst(pc+pI1->isize);
if( pI2 ) {
m_warp[m_inst_fetch_buffer.m_warp_id].ibuffer_fill(1,pI2);
m_warp[m_inst_fetch_buffer.m_warp_id].inc_inst_in_pipeline();
@@ -1207,60 +725,38 @@ int is_local ( memory_space_t space )
}
-void shader_core_ctx::ptx_exec_inst( inst_t &inst )
+void shader_core_ctx::func_exec_inst( warp_inst_t &inst )
{
- m_thread[inst.hw_thread_id].m_functional_model_thread_state->ptx_exec_inst(inst);
- if( inst.callback.function != NULL )
- m_warp[inst.hw_thread_id/m_config->warp_size].inc_n_atomic();
- if (is_local(inst.space.get_type()) && (is_load(inst) || is_store(inst)))
- inst.memreqaddr = translate_local_memaddr(inst.memreqaddr, inst.hw_thread_id, m_gpu->num_shader());
-}
-
-void shader_core_ctx::issue_warp( const inst_t *pI, unsigned active_mask, inst_t *&warp, unsigned warp_id )
-{
- m_warp[warp_id].ibuffer_free();
- assert(pI->valid());
- unsigned cta_id = (unsigned)-1;
for ( unsigned t=0; t < m_config->warp_size; t++ ) {
- unsigned tid=m_config->warp_size*warp_id+t;
- warp[t] = *pI;
- warp[t].warp_active_mask = active_mask;
- if( active_mask & (1<<t) ) {
- cta_id = m_thread[tid].m_cta_id;
- warp[t].hw_thread_id = tid;
- warp[t].wlane = t;
- warp[t].uid = g_next_shader_inst_uid++;
- warp[t].issue_cycle = gpu_tot_sim_cycle + gpu_sim_cycle;
- ptx_exec_inst( warp[t] );
+ if( inst.active(t) ) {
+ unsigned tid=m_config->warp_size*inst.warp_id()+t;
+ m_thread[tid].m_functional_model_thread_state->ptx_exec_inst(inst,t);
+ if( inst.has_callback(t) )
+ m_warp[inst.warp_id()].inc_n_atomic();
+ if (is_local(inst.space.get_type()) && (is_load(inst) || is_store(inst)))
+ inst.set_addr(t, translate_local_memaddr(inst.get_addr(t), tid, m_gpu->num_shader()) );
if ( ptx_thread_done(tid) ) {
- m_warp[warp_id].inc_n_completed();
- m_warp[warp_id].ibuffer_flush();
+ m_warp[inst.warp_id()].inc_n_completed();
+ m_warp[inst.warp_id()].ibuffer_flush();
}
}
}
- assert( cta_id != (unsigned)-1 );
- if( pI->op == BARRIER_OP )
- set_at_barrier(cta_id,warp_id);
- else if( pI->op == MEMORY_BARRIER_OP )
+}
+
+void shader_core_ctx::issue_warp( warp_inst_t *&pipe_reg, const warp_inst_t *next_inst, unsigned active_mask, unsigned warp_id )
+{
+ m_warp[warp_id].ibuffer_free();
+ assert(next_inst->valid());
+ *pipe_reg = *next_inst; // static instruction information
+ pipe_reg->issue( active_mask, warp_id, gpu_tot_sim_cycle + gpu_sim_cycle ); // dynamic instruction information
+ func_exec_inst( *pipe_reg );
+ if( next_inst->op == BARRIER_OP )
+ set_at_barrier(m_warp[warp_id].get_cta_id(),warp_id);
+ else if( next_inst->op == MEMORY_BARRIER_OP )
set_at_memory_barrier(warp_id);
m_pdom_warp[warp_id]->pdom_update_warp_mask();
- m_scoreboard->reserveRegisters(warp_id, pI);
- m_warp[warp_id].set_next_pc(pI->pc + pI->isize);
-
- /////
- memset(m_fetch_tid_out, -1, sizeof(int)*m_config->warp_size);
- int n_thd_in_warp = 0;
- for (unsigned i=0; i<m_config->warp_size; i++) {
- m_fetch_tid_out[i] = warp[i].hw_thread_id;
- if (m_fetch_tid_out[i] >= 0)
- n_thd_in_warp += 1;
- }
-
- m_new_warp_TS = false;
-
- // warp tracker keeps track of warps in the pipeline, let it know we are going to issue this warp
- assert( n_thd_in_warp > 0 );
- m_warp_tracker->wpt_register_warp(m_fetch_tid_out, pI->pc, n_thd_in_warp,m_config->warp_size);
+ m_scoreboard->reserveRegisters(warp_id, next_inst);
+ m_warp[warp_id].set_next_pc(next_inst->pc + next_inst->isize);
}
void shader_core_ctx::decode_new()
@@ -1271,7 +767,7 @@ void shader_core_ctx::decode_new()
unsigned issued=0;
while( !m_warp[warp_id].waiting() && !m_warp[warp_id].ibuffer_empty() && (checked < 2) && (issued < 2) ) {
unsigned active_mask = m_pdom_warp[warp_id]->get_active_mask();
- const inst_t *pI = m_warp[warp_id].ibuffer_next();
+ const warp_inst_t *pI = m_warp[warp_id].ibuffer_next();
unsigned pc,rpc;
m_pdom_warp[warp_id]->get_pdom_stack_top_info(&pc,&rpc);
if( pI ) {
@@ -1281,11 +777,11 @@ void shader_core_ctx::decode_new()
m_warp[warp_id].ibuffer_flush();
} else if ( !m_scoreboard->checkCollision(warp_id, pI) ) {
assert( m_warp[warp_id].inst_in_pipeline() );
- if ( (pI->op != SFU_OP) && pipeline_regster_empty(m_pipeline_reg[ID_OC]) ) {
- issue_warp(pI, active_mask, m_pipeline_reg[ID_OC], warp_id);
+ if ( (pI->op != SFU_OP) && m_pipeline_reg[ID_OC]->empty() ) {
+ issue_warp(m_pipeline_reg[ID_OC],pI,active_mask,warp_id);
issued++;
- } else if ( (pI->op == SFU_OP || pI->op == ALU_SFU_OP) && pipeline_regster_empty(m_pipeline_reg[ID_OC_SFU]) ) {
- issue_warp(pI, active_mask, m_pipeline_reg[ID_OC_SFU], warp_id);
+ } 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++;
}
}
@@ -1300,92 +796,6 @@ void shader_core_ctx::decode_new()
}
}
-void shader_core_ctx::fetch()
-{
- // check if decode stage is stalled
- bool decode_stalled = !pipeline_regster_empty( m_pipeline_reg[IF_ID] );
-
- // find a ready warp and put it in the TS_IF pipeline register
- switch (m_config->model) {
- case POST_DOMINATOR: fetch_simd_postdominator(); break;
- case DWF: fetch_simd_dwf(); break;
- case MIMD: fetch_mimd(); break;
- default: fprintf(stderr, "Unknown scheduler: %d\n", m_config->model); assert(0); break;
- }
-
- memset(m_fetch_tid_out, -1, sizeof(int)*m_config->warp_size);
-
- if (m_config->gpgpu_no_divg_load && m_new_warp_TS && !decode_stalled) {
-
- // count number of active threads in this warp, determine PC value
- // record active threads in tid_out
- int n_thd_in_warp = 0;
- address_type pc_out = 0xDEADBEEF;
- for (unsigned i=0; i<m_config->warp_size; i++) {
- m_fetch_tid_out[i] = m_pipeline_reg[TS_IF][i].hw_thread_id;
- if (m_fetch_tid_out[i] >= 0) {
- n_thd_in_warp += 1;
- pc_out = m_pipeline_reg[TS_IF][i].pc;
- }
- }
-
- m_new_warp_TS = false;
-
- // warp tracker keeps track of warps in the pipeline, let it know we are going to issue this warp
- if( n_thd_in_warp > 0 )
- m_warp_tracker->wpt_register_warp(m_fetch_tid_out, pc_out, n_thd_in_warp,m_config->warp_size);
-
- // some statistics collection
- if (gpu_runtime_stat_flag & GPU_RSTAT_DWF_MAP)
- m_thread_pc_tracker->set_threads_pc( m_fetch_tid_out, pc_out );
- if (gpgpu_cflog_interval != 0) {
- insn_warp_occ_log( m_sid, pc_out, n_thd_in_warp);
- shader_warp_occ_log( m_sid, n_thd_in_warp);
- }
- if ( m_config->gpgpu_warpdistro_shader < 0 || m_sid == (unsigned)m_config->gpgpu_warpdistro_shader ) {
- m_stats->shader_cycle_distro[n_thd_in_warp + 2] += 1;
- if (n_thd_in_warp == 0)
- if (m_pending_mem_access == 0)
- m_stats->shader_cycle_distro[1]++;
- }
- } else {
- if ( m_config->gpgpu_warpdistro_shader < 0 || m_sid == (unsigned)m_config->gpgpu_warpdistro_shader ) {
- m_stats->shader_cycle_distro[0] += 1;
- }
- }
-
- if (!decode_stalled) {
- for (unsigned i = 0; i < m_config->warp_size; i++) {
- int tid_tsif = m_pipeline_reg[TS_IF][i].hw_thread_id;
- address_type pc_out = m_pipeline_reg[TS_IF][i].pc;
- cflog_update_thread_pc(m_sid, tid_tsif, pc_out);
- }
- }
-
- if (enable_ptx_file_line_stats && !decode_stalled) {
- int TS_stage_empty = 1;
- for (unsigned i = 0; i < m_config->warp_size; i++) {
- if (m_pipeline_reg[TS_IF][i].hw_thread_id >= 0) {
- TS_stage_empty = 0;
- break;
- }
- }
- if (TS_stage_empty) {
- if (enable_ptx_file_line_stats)
- ptx_file_line_stats_commit_exposed_latency(m_sid, 1);
- }
- }
-
- // if not, send the warp part to decode stage
- if (!decode_stalled) {
- check_stage_pcs(TS_IF);
- inst_t *fvi = first_valid_thread(m_pipeline_reg[TS_IF]);
- if( fvi )
- m_warp[fvi->hw_thread_id/m_config->warp_size].set_last_fetch(gpu_sim_cycle);
- move_warp(m_pipeline_reg[IF_ID],m_pipeline_reg[TS_IF]);
- }
-}
-
address_type coalesced_segment(address_type addr, unsigned segment_size_lg2bytes)
{
return (addr >> segment_size_lg2bytes);
@@ -1419,232 +829,16 @@ address_type shader_core_ctx::translate_local_memaddr(address_type localaddr, in
/////////////////////////////////////////////////////////////////////////////////////////
-void shader_core_ctx::decode()
-{
- op_type op = NO_OP;
- unsigned warp_id = -1;
- unsigned cta_id = -1;
-
- address_type regs_regs_PC = 0xDEADBEEF;
- address_type warp_current_pc = 0x600DBEEF;
- address_type warp_next_pc = 0x600DBEEF;
- int warp_diverging = 0;
- const int nextstage = (m_config->gpgpu_operand_collector) ? ID_OC : \
- (m_config->m_using_dwf_rrstage ? ID_RR : ID_EX);
-
- if( !pipeline_regster_empty(m_pipeline_reg[nextstage]) )
- return;
-
- check_stage_pcs(IF_ID);
-
- // decode the instruction
- int first_valid_thread = -1;
- for (unsigned i=0; i<m_config->warp_size;i++) {
- if (m_pipeline_reg[IF_ID][i].hw_thread_id == -1 )
- continue; /* bubble or masked off */
- if (first_valid_thread == -1) {
- first_valid_thread = i;
- op = m_pipeline_reg[IF_ID][i].op;
- int tid = m_pipeline_reg[IF_ID][i].hw_thread_id;
- warp_id = tid/m_config->warp_size;
- assert( !warp_waiting_at_barrier(warp_id) );
- cta_id = m_thread[tid].m_cta_id;
- }
- }
-
- // execute the instruction functionally
- short last_hw_thread_id = -1;
- bool first_thread_in_warp = true;
- for (unsigned i=0; i<m_config->warp_size;i++) {
- if (m_pipeline_reg[IF_ID][i].hw_thread_id == -1 )
- continue; /* bubble or masked off */
-
- if(last_hw_thread_id > -1)
- first_thread_in_warp = false;
- last_hw_thread_id = m_pipeline_reg[IF_ID][i].hw_thread_id;
-
- /* get the next instruction to execute from fetch stage */
- int tid = m_pipeline_reg[IF_ID][i].hw_thread_id;
-
- // Functionally execute instruction
- m_thread[tid].m_functional_model_thread_state->ptx_exec_inst( m_pipeline_reg[IF_ID][i] );
- if( m_pipeline_reg[IF_ID][i].callback.function != NULL )
- m_warp[warp_id].inc_n_atomic();
- if (is_local(m_pipeline_reg[IF_ID][i].space) && (is_load(m_pipeline_reg[IF_ID][i]) || is_store(m_pipeline_reg[IF_ID][i])))
- m_pipeline_reg[IF_ID][i].memreqaddr = translate_local_memaddr(m_pipeline_reg[IF_ID][i].memreqaddr, tid, m_gpu->num_shader());
-
- // Mark destination registers as write-pending in scoreboard
- // Only do this for the first thread in warp
- if(first_thread_in_warp)
- m_scoreboard->reserveRegisters(warp_id, &(m_pipeline_reg[IF_ID][i]));
- warp_current_pc = m_pipeline_reg[IF_ID][i].pc;
- regs_regs_PC = next_pc( tid );
-
- if ( ptx_thread_at_barrier( m_thread[tid].m_functional_model_thread_state ) ) {
- if (m_config->model == DWF) {
- m_thread[tid].m_waiting_at_barrier=true;
- m_thread[tid].m_reached_barrier=true; // not reset at barrier release, but at the issue after that
- m_warp[wid_from_hw_tid(tid,m_config->warp_size)].inc_waiting_at_barrier();
- int cta_uid = ptx_thread_get_cta_uid( m_thread[tid].m_functional_model_thread_state );
- dwf_hit_barrier( m_sid, cta_uid );
-
- int release = ptx_thread_all_at_barrier( m_thread[tid].m_functional_model_thread_state ); //test if all threads arrived at the barrier
- if ( release ) { //All threads arrived at barrier...releasing
- int cta_uid = ptx_thread_get_cta_uid( m_thread[tid].m_functional_model_thread_state );
- for ( unsigned t=0; t < m_config->n_thread_per_shader; ++t ) {
- if ( !ptx_thread_at_barrier( m_thread[t].m_functional_model_thread_state ) )
- continue;
- int other_cta_uid = ptx_thread_get_cta_uid( m_thread[t].m_functional_model_thread_state );
- if ( other_cta_uid == cta_uid ) { //reseting @barrier tracking info
- m_warp[wid_from_hw_tid(t,m_config->warp_size)].clear_waiting_at_barrier();
- m_thread[t].m_waiting_at_barrier=false;
- ptx_thread_reset_barrier( m_thread[t].m_functional_model_thread_state );
- }
- }
- if (m_config->model == DWF) {
- dwf_release_barrier( m_sid, cta_uid );
- }
- ptx_thread_release_barrier( m_thread[tid].m_functional_model_thread_state );
- }
- }
- } else {
- assert( !m_thread[tid].m_waiting_at_barrier );
- }
-
- // branch divergence detection
- if (warp_next_pc != regs_regs_PC) {
- if (warp_next_pc == 0x600DBEEF) {
- warp_next_pc = regs_regs_PC;
- } else {
- warp_diverging = 1;
- }
- }
- }
-
- move_warp(m_pipeline_reg[nextstage],m_pipeline_reg[IF_ID]);
-
- if( op == BARRIER_OP )
- set_at_barrier(cta_id,warp_id);
- else if( op == MEMORY_BARRIER_OP )
- set_at_memory_barrier(warp_id);
-
- m_n_diverge += warp_diverging;
- if (warp_diverging == 1) {
- assert(warp_current_pc != 0x600DBEEF); // guard against empty warp causing warp divergence
- ptx_file_line_stats_add_warp_divergence(warp_current_pc, 1);
- }
-}
-
-unsigned int n_regconflict_stall = 0;
-
-
-int regfile_hash(signed thread_number, unsigned simd_size, unsigned n_banks) {
- if (gpgpu_thread_swizzling) {
- signed warp_ID = thread_number / simd_size;
- return((thread_number + warp_ID) % n_banks);
- } else {
- return(thread_number % n_banks);
- }
-}
-
-void shader_core_ctx::preexecute()
-{
- if( m_config->gpgpu_dwf_reg_bankconflict) {
- // Model register bank conflicts as in
- // Fung et al. MICRO'07 / ACM TACO'09 papers.
- //
- // This models conflicts due to moving threads to different SIMD lanes
- // (which occur if not using "lane aware" dynamic warp formation).
-
- inst_t *fvi = first_valid_thread(m_pipeline_reg[RR_EX]);
- if( fvi ) {
- if (m_dwf_RR_k) {
- //stalled due to register access conflict, but can still service a register read
- m_dwf_RR_k--;
- return;
- }
-
- int n_access_per_cycle = m_config->warp_size / m_config->gpgpu_dwf_rr_stage_n_reg_banks;
- int max_reg_bank_acc = 0;
- for (unsigned i=0; i<m_config->gpgpu_dwf_rr_stage_n_reg_banks; i++)
- m_dwf_rrstage_bank_access_counter[i] = 0;
- for (unsigned i=0; i<m_config->warp_size; i++) {
- if (m_pipeline_reg[ID_RR][i].hw_thread_id != -1 )
- m_dwf_rrstage_bank_access_counter[regfile_hash(m_pipeline_reg[ID_RR][i].hw_thread_id,
- m_config->warp_size,
- m_config->gpgpu_dwf_rr_stage_n_reg_banks)]++;
- }
- for (unsigned i=0; i<m_config->gpgpu_dwf_rr_stage_n_reg_banks; i++) {
- if (m_dwf_rrstage_bank_access_counter[i] > max_reg_bank_acc )
- max_reg_bank_acc = m_dwf_rrstage_bank_access_counter[i];
- }
- // calculate the number of cycles needed for each register bank to fulfill all accesses
- m_dwf_RR_k = (max_reg_bank_acc / n_access_per_cycle) + ((max_reg_bank_acc % n_access_per_cycle)? 1 : 0);
-
- // if there is more than one access cycle needed at a bank, stall
- if (m_dwf_RR_k > 1) {
- n_regconflict_stall++;
- m_dwf_RR_k--;
- return;
- }
- }
-
- check_stage_pcs(ID_RR);
- m_dwf_RR_k = 0;
- }
-
- if( pipeline_regster_empty(m_pipeline_reg[ID_EX]) )
- move_warp(m_pipeline_reg[ID_EX],m_pipeline_reg[ID_RR]);
-}
-
-
void shader_core_ctx::execute_pipe( unsigned pipeline, unsigned next_stage )
{
- if (m_config->gpgpu_pre_mem_stages) {
- if( !pipeline_regster_empty(pre_mem_pipeline[0]) )
- return; // stalled
- } else {
- if( !pipeline_regster_empty(m_pipeline_reg[next_stage]) )
- return; // stalled
- }
-
- check_stage_pcs(ID_EX);
-
- // Check that all threads have the same delay cycles
- unsigned cycles = -1;
- for (unsigned i=0; i<m_config->warp_size; i++) {
- if (m_pipeline_reg[pipeline][i].hw_thread_id == -1 )
- continue; // bubble
- if(cycles == (unsigned)-1)
- cycles = m_pipeline_reg[pipeline][i].cycles;
- else {
- if( cycles != m_pipeline_reg[pipeline][i].cycles ) {
- printf("Shader %d: threads do not have the same delay cycles.\n", m_sid);
- assert(0);
- }
- }
- }
-
- bool stall_inst_not_done = false;
- for (unsigned i=0; i<m_config->warp_size; i++) {
- if (m_pipeline_reg[pipeline][i].hw_thread_id == -1 )
- continue;
- m_pipeline_reg[pipeline][i].cycles--;
- if( m_pipeline_reg[pipeline][i].cycles > 0 ) {
- // Stall here to model instruction throughput for different types of instructions
- stall_inst_not_done=true;
- continue;
- }
- }
- if( stall_inst_not_done )
- return;
- if (m_config->gpgpu_pre_mem_stages) {
- move_warp(pre_mem_pipeline[0], m_pipeline_reg[pipeline]);
- } else {
- move_warp(m_pipeline_reg[next_stage],m_pipeline_reg[pipeline]);
- // inform memory stage that a new instruction has arrived
- m_shader_memory_new_instruction_processed = false;
- }
+ if( !m_pipeline_reg[next_stage]->empty() )
+ return;
+ if( m_pipeline_reg[pipeline]->cycles ) {
+ m_pipeline_reg[pipeline]->cycles--;
+ return;
+ }
+ move_warp(m_pipeline_reg[next_stage],m_pipeline_reg[pipeline]);
+ m_shader_memory_new_instruction_processed = false;
}
void shader_core_ctx::execute()
@@ -1653,32 +847,15 @@ void shader_core_ctx::execute()
execute_pipe(ID_EX, EX_MM);
}
-void shader_core_ctx::pre_memory()
-{
- // This stage can be used to approximately model a deeper pipeline.
- // The main effect this models is the register read-after-write delay.
- // We walk through pre-memory stages in reverse order
- // (highest number = stage closest to writeback, 0 = stage closest to fetch
- if( pipeline_regster_empty(m_pipeline_reg[EX_MM]) ) {
- move_warp( m_pipeline_reg[EX_MM], pre_mem_pipeline[m_config->gpgpu_pre_mem_stages] );
- // inform memory stage that a new instruction has arrived
- m_shader_memory_new_instruction_processed = false;
- }
- for (unsigned j = m_config->gpgpu_pre_mem_stages; j > 0; j--) {
- if( pipeline_regster_empty(pre_mem_pipeline[j]) )
- move_warp( pre_mem_pipeline[j], pre_mem_pipeline[j-1]);
- }
-}
-
-mshr_entry* mshr_shader_unit::add_mshr(mem_access_t &access, inst_t* warp)
+mshr_entry* mshr_shader_unit::add_mshr(mem_access_t &access, warp_inst_t* warp)
{
- //creates an mshr based on the access struct information
+ // creates an mshr based on the access struct information
mshr_entry* mshr = alloc_free_mshr(access.space == tex_space);
- mshr->init(access.addr,access.iswrite,access.space,warp->hw_thread_id/m_shader_config->warp_size);
+ mshr->init(access.addr,access.iswrite,access.space,warp->warp_id());
assert(access.warp_indices.size()); //code assumes at least one instruction attached to mshr.
for (unsigned i = 0; i < access.warp_indices.size(); i++)
mshr->add_inst(warp[access.warp_indices[i]]);
- if (m_shader_config->gpgpu_interwarp_mshr_merge) {
+ if( m_shader_config->gpgpu_interwarp_mshr_merge ) {
mshr_entry* mergehit = m_mshr_lookup.shader_get_mergeable_mshr(mshr);
if (mergehit) {
mergehit->merge(mshr);
@@ -1732,7 +909,7 @@ void shader_core_ctx::get_memory_access_list(
bool limit_broadcast,
std::vector<mem_access_t> &accessq )
{
- const inst_t* insns = m_pipeline_reg[EX_MM];
+ const warp_inst_t* insns = m_pipeline_reg[EX_MM];
// Calculates memory accesses generated by this warp
// Returns acesses which are "coalesced"
// Does not coalesce nor overlap bank accesses across warp "parts".
@@ -1768,28 +945,23 @@ void shader_core_ctx::get_memory_access_list(
unsigned mem_pipe_size = m_config->warp_size / warp_parts;
for (unsigned part = 0; part < m_config->warp_size; part += mem_pipe_size) {
for (unsigned i = part; i < part + mem_pipe_size; i++) {
- if ( insns[i].hw_thread_id == -1 )
+ if ( !insns->active(i) )
continue;
-
- if( insns[i].space == undefined_space ) {
- // Instruction must have been predicated off
- continue;
- }
-
- address_type lane_segment_address = tag_func(insns[i].memreqaddr, line_size);
+ if( insns->space == undefined_space )
+ continue; // this happens when thread predicated off
+ new_addr_type addr = insns->get_addr(i);
+ address_type lane_segment_address = tag_func(addr, line_size);
unsigned quarter = 0;
if( line_size>=4 )
- quarter = (insns[i].memreqaddr / (line_size/4)) & 3;
- bool isatomic = (insns[i].callback.function != NULL);
+ quarter = (addr / (line_size/4)) & 3;
bool match = false;
- if (not isatomic) { //atomics must have own request
+ if( !insns->isatomic() ) { //atomics must have own request
for (unsigned j = qpartbegin; j < accessq.size(); j++) {
if (lane_segment_address == accessq[j].addr) {
assert( not accessq[j].isatomic );
accessq[j].quarter_count[quarter]++;
accessq[j].warp_indices.push_back(i);
- if (limit_broadcast)
- // two threads access this address, so its a broadcast.
+ if (limit_broadcast) // two threads access this address, so its a broadcast.
accessq[j].order = ++broadcast_order; //do broadcast in its own cycle.
match = true;
break;
@@ -1797,15 +969,15 @@ void shader_core_ctx::get_memory_access_list(
}
}
if (!match) { // does not match an previous request by another thread, so need a new request
- assert( insns[i].space != undefined_space );
+ assert( insns->space != undefined_space );
accessq.push_back( mem_access_t( lane_segment_address,
- insns[i].space,
+ insns->space,
mem_pipe,
- isatomic,
- is_store(insns[i]),
+ insns->isatomic(),
+ is_store(*insns),
line_size, quarter, i) );
// Determine Bank Conflicts:
- unsigned bank = (this->*bank_func)(insns[i].memreqaddr, line_size);
+ unsigned bank = (this->*bank_func)(insns->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)
@@ -1820,7 +992,6 @@ void shader_core_ctx::get_memory_access_list(
std::stable_sort(accessq.begin()+qbegin,accessq.end());
}
-
void shader_core_ctx::memory_shared_process_warp()
{
// initial processing of shared memory warps
@@ -1835,31 +1006,31 @@ void shader_core_ctx::memory_shared_process_warp()
void shader_core_ctx::memory_const_process_warp()
{
- // initial processing of const memory warps
- std::vector<mem_access_t> &accessq = m_memory_queue.constant;
- unsigned qbegin = accessq.size();
- get_memory_access_list(
- &shader_core_ctx::null_bank_func,
- line_size_based_tag_func,
- CONSTANT_MEM_PATH,
- 1, //warp parts
- m_L1C->get_line_sz(), false, //no broadcast limit.
- accessq);
- //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 < accessq.size(); i++) {
- if ( accessq[i].space == param_space_kernel ) {
- accessq[i].cache_hit = true;
- } else {
- cache_request_status status = m_L1C->access( accessq[i].addr,
- 0, //should always be a read
- gpu_sim_cycle+gpu_tot_sim_cycle,
- NULL/*should never writeback*/);
- accessq[i].cache_hit = (status == HIT);
- if (m_config->gpgpu_perfect_mem) accessq[i].cache_hit = true;
- if (accessq[i].cache_hit) m_stats->L1_const_miss++;
- }
- accessq[i].cache_checked = true;
- }
+ // initial processing of const memory warps
+ std::vector<mem_access_t> &accessq = m_memory_queue.constant;
+ unsigned qbegin = accessq.size();
+ get_memory_access_list( &shader_core_ctx::null_bank_func,
+ line_size_based_tag_func,
+ CONSTANT_MEM_PATH,
+ 1, //warp parts
+ m_L1C->get_line_sz(), false, //no broadcast limit.
+ accessq);
+ // 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 < accessq.size(); i++) {
+ if ( accessq[i].space == param_space_kernel ) {
+ accessq[i].cache_hit = true;
+ } else {
+ cache_request_status status = m_L1C->access( accessq[i].addr,
+ 0, //should always be a read
+ gpu_sim_cycle+gpu_tot_sim_cycle,
+ NULL/*should never writeback*/);
+ accessq[i].cache_hit = (status == HIT);
+ if (m_config->gpgpu_perfect_mem) accessq[i].cache_hit = true;
+ if (accessq[i].cache_hit) m_stats->L1_const_miss++;
+ }
+ accessq[i].cache_checked = true;
+ }
}
void shader_core_ctx::memory_texture_process_warp()
@@ -1874,7 +1045,8 @@ void shader_core_ctx::memory_texture_process_warp()
m_L1T->get_line_sz(),
false, //no broadcast limit.
accessq);
- //do cache checks here for each request (non-hardware), could be done later for more accurate timing of cache accesses, but probably uneccesary;
+ // 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 < accessq.size(); i++) {
cache_request_status status = m_L1T->access( accessq[i].addr,
0, //should always be a read
@@ -1896,7 +1068,7 @@ void shader_core_ctx::memory_global_process_warp()
if (m_config->gpgpu_coalesce_arch == 13) {
warp_parts = 2;
if(m_config->gpgpu_no_dl1) {
- unsigned data_size = first_valid_thread( m_pipeline_reg[EX_MM] )->data_size;
+ unsigned data_size = m_pipeline_reg[EX_MM]->data_size;
// line size is dependant on instruction;
switch (data_size) {
case 1: line_size = 32; break;
@@ -1940,15 +1112,11 @@ void shader_core_ctx::memory_global_process_warp()
}
}
}
-
-
mem_stage_stall_type shader_core_ctx::send_mem_request(mem_access_t &access)
{
- //Atempt to send an request/write to memory based on information in access.
-
- inst_t* warp = m_pipeline_reg[EX_MM];
- inst_t* req_head = warp + access.warp_indices[0];
+ // Attempt to send an request/write to memory based on information in access.
+ warp_inst_t* warp = m_pipeline_reg[EX_MM];
// 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.
@@ -1976,7 +1144,7 @@ mem_stage_stall_type shader_core_ctx::send_mem_request(mem_access_t &access)
default: assert(0); break;
}
//reserve mshr
- bool requires_mshr = (m_config->model != MIMD) and (not access.iswrite);
+ bool requires_mshr = (not access.iswrite);
if (requires_mshr and not access.reserved_mshr) {
if (not m_mshr_unit->has_mshr(1))
return MSHR_RC_FAIL;
@@ -2001,46 +1169,34 @@ mem_stage_stall_type shader_core_ctx::send_mem_request(mem_access_t &access)
}
//send over interconnect
partial_write_mask_t write_mask = NO_PARTIAL_WRITE;
- unsigned warp_id = req_head->hw_thread_id/m_config->warp_size;
+ unsigned warp_id = warp->warp_id();
if (access.iswrite) {
if (!strcmp("GT200",m_config->pipeline_model) )
m_warp[warp_id].inc_store_req();
for (unsigned i=0;i < access.warp_indices.size();i++) {
unsigned w = access.warp_indices[i];
- int data_offset = warp[w].memreqaddr & ((unsigned long long int)access.req_size - 1);
- for (unsigned b = data_offset; b < data_offset + warp[w].data_size; b++) write_mask.set(b);
+ int data_offset = warp->get_addr(w) & ((unsigned long long int)access.req_size - 1);
+ for (unsigned b = data_offset; b < data_offset + warp->data_size; b++) write_mask.set(b);
}
if (write_mask.count() != access.req_size)
m_stats->gpgpu_n_partial_writes++;
}
fq_push( access.addr, request_size,
access.iswrite, write_mask, warp_id , access.reserved_mshr,
- access_type, req_head->pc);
- }
-
- // book keeping for mshr : this request is done (sent/accounted for)
- if (requires_mshr) {
- for (unsigned i = 0; i < access.warp_indices.size(); i++) {
- unsigned o = access.warp_indices[i];
- m_pending_mem_access++;
- if (enable_ptx_file_line_stats)
- ptx_file_line_stats_add_inflight_memory_insn(m_sid, warp[o].pc);
- }
-
- // Scoreboard addition: do not make cache miss instructions wait for memory,
- // let the scoreboard handle stalling of instructions.
- // Mark thread as a cache miss
- if (not access.iswrite) {
- // set the pipeline instructions in this request to noops, they all wait for memory;
- for (unsigned i = 0; i < access.warp_indices.size(); i++) {
- unsigned o = access.warp_indices[i];
- m_pipeline_reg[EX_MM][o].cache_miss = true;
- }
- }
+ access_type, warp->pc );
}
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] );
+ move_warp(m_pipeline_reg[WB_RT],m_pipeline_reg[MM_WB]);
+}
bool shader_core_ctx::memory_shared_cycle( mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type)
{
@@ -2184,8 +1340,7 @@ mem_stage_stall_type shader_core_ctx::dcache_check(mem_access_t& access)
if (access.isatomic) {
if (m_config->gpgpu_perfect_mem) {
// complete functional execution of atomic here
- dram_callback_t &atom_exec = m_pipeline_reg[EX_MM][access.warp_indices[0]].callback;
- atom_exec.function(atom_exec.instruction, atom_exec.thread);
+ m_pipeline_reg[EX_MM]->do_atomic();
} else {
// atomics always go to memory
access.cache_hit = false;
@@ -2224,11 +1379,10 @@ void shader_core_ctx::memory_queue()
// Called once per warp when warp enters memory stage.
// Generates a list of memory accesses, but does not perform the memory access.
- if( pipeline_regster_empty(m_pipeline_reg[EX_MM]) )
+ if( m_pipeline_reg[EX_MM]->empty() )
return;
m_gpu->mem_instruction_stats(m_pipeline_reg[EX_MM]);
- inst_t *inst = first_valid_thread(m_pipeline_reg[EX_MM]);
- switch (inst->space.get_type()) {
+ switch( m_pipeline_reg[EX_MM]->space.get_type() ) {
case shared_space: memory_shared_process_warp(); break;
case tex_space: memory_texture_process_warp(); break;
case const_space: case param_space_kernel: memory_const_process_warp(); break;
@@ -2258,9 +1412,8 @@ void shader_core_ctx::memory()
m_stats->gpu_stall_shd_mem_breakdown[type][rc_fail]++;
return;
}
- if( not pipeline_regster_empty( m_pipeline_reg[MM_WB] ) )
+ if( not m_pipeline_reg[MM_WB]->empty() )
return; // writeback stalled
- check_stage_pcs(EX_MM);
move_warp(m_pipeline_reg[MM_WB],m_pipeline_reg[EX_MM]);
}
@@ -2281,292 +1434,6 @@ void shader_core_ctx::register_cta_thread_exit(int tid )
}
}
-void obtain_insn_latency_info(insn_latency_info *latinfo, const inst_t *insn)
-{
- latinfo->pc = insn->pc;
- latinfo->latency = gpu_tot_sim_cycle + gpu_sim_cycle - insn->issue_cycle;
-}
-
-int debug_tid = 0;
-
-void shader_core_ctx::writeback()
-{
- std::vector<inst_t> done_insts;
- std::vector<insn_latency_info> unlock_lat_infos;
- bool w2rf = false;
- memset(m_pl_tid,-1, sizeof(int)*m_config->warp_size);
- check_stage_pcs(MM_WB);
-
- // detect if a valid instruction is in MM_WB
- for (unsigned i=0; i<m_config->warp_size; i++) {
- w2rf |= (m_pipeline_reg[MM_WB][i].hw_thread_id >= 0);
- m_pl_tid[i] = m_pipeline_reg[MM_WB][i].hw_thread_id;
- }
-
- //check mshrs for commit;
- unsigned mshr_threads_unlocked = 0;
- bool stalled_by_MSHR = false;
-
- mshr_entry *mshr_head = m_mshr_unit->return_head();
- if (mshr_head && (mshr_threads_unlocked + mshr_head->num_inst() <= m_config->warp_size) ) {
- assert (mshr_head->num_inst());
- for (unsigned j = 0; j < mshr_head->num_inst(); j++) {
- const inst_t &insn = mshr_head->get_inst(j);
- time_vector_update(insn.uid,MR_WRITEBACK,gpu_sim_cycle+gpu_tot_sim_cycle,RD_REQ);
- obtain_insn_latency_info(&m_mshr_lat_info[mshr_threads_unlocked], &insn);
- if (enable_ptx_file_line_stats)
- ptx_file_line_stats_sub_inflight_memory_insn(m_sid, insn.pc);
- assert (insn.hw_thread_id >= 0);
- m_pending_mem_access--;
- mshr_threads_unlocked++;
- if (m_config->gpgpu_operand_collector) {
- if ( j== 0 )
- m_operand_collector.writeback(insn);
- } else
- stalled_by_MSHR = true;
- }
- mshr_head->get_insts(done_insts);
-
- m_mshr_unit->pop_return_head();
- unlock_lat_infos.resize(mshr_threads_unlocked);
- std::copy(m_mshr_lat_info, m_mshr_lat_info + mshr_threads_unlocked, unlock_lat_infos.begin());
- assert(mshr_threads_unlocked);
- }
-
- if ( m_config->gpgpu_operand_collector )
- stalled_by_MSHR = !m_operand_collector.writeback( m_pipeline_reg[MM_WB] );
-
- if (!stalled_by_MSHR) {
- inst_t inst;
- for (unsigned i=0; i<m_config->warp_size; i++) {
- op_type op;
- if (m_pipeline_reg[MM_WB][i].hw_thread_id > -1)
- op = m_pipeline_reg[MM_WB][i].op;
- obtain_insn_latency_info(&m_pl_lat_info[i], &m_pipeline_reg[MM_WB][i]);
- if (!m_pipeline_reg[MM_WB][i].cache_miss) { // Do not include cache misses for a writeback
- if (m_pipeline_reg[MM_WB][i].hw_thread_id > -1) {
- done_insts.push_back(m_pipeline_reg[MM_WB][i]);
- unlock_lat_infos.push_back(m_pl_lat_info[i]);
- }
- }
- if (m_pl_tid[i] > -1 )
- inst = m_pipeline_reg[MM_WB][i];
- }
-
- // Unlock the warp for re-fetching (put it in the fixed delay queue)
- if (w2rf) // Only need to unlock if this is a valid instruction
- queue_warp_unlocking(m_pl_tid, inst);
- } else
- m_stats->gpu_stall_by_MSHRwb++;
-
- for (unsigned i=0; i<done_insts.size(); i++) {
- inst_t done_inst = done_insts[i];
- call_thread_done(done_inst);
-
- gpu_sim_insn++; // a (scalar) instruction is done
- if ( !is_const(done_inst.space) )
- m_stats->gpu_sim_insn_no_ld_const++;
- m_gpu->gpu_sim_insn_last_update = gpu_sim_cycle;
- m_gpu->gpu_sim_insn_last_update_sid = m_sid;
- m_num_sim_insn++;
- m_thread[done_inst.hw_thread_id].n_insn++;
- m_thread[done_inst.hw_thread_id].n_insn_ac++;
-
- if (enable_ptx_file_line_stats) {
- unsigned pc = unlock_lat_infos[i].pc;
- unsigned long latency = unlock_lat_infos[i].latency;
- ptx_file_line_stats_add_latency(pc, latency);
- }
- }
-
- if (!stalled_by_MSHR) {
- if (!strcmp("GT200",m_config->pipeline_model) ) {
- inst_t *fvt=first_valid_thread(m_pipeline_reg[MM_WB]);
- if( fvt ) {
- unsigned warp_id = fvt->hw_thread_id/m_config->warp_size;
- m_warp[warp_id].dec_inst_in_pipeline();
- }
- }
- move_warp(m_pipeline_reg[WB_RT], m_pipeline_reg[MM_WB]);
- }
-
- process_delay_queue();
-}
-
-/*
- * Queues a warp into fixed delay queue for unlocking
- *
- * The amount of delay to add is determined by the instruction type.
- *
- * @param *tid Array of tid in the warp to unlock
- * @param space Address space for the current instruction in the warp
- *
- */
-void shader_core_ctx::queue_warp_unlocking(int *tids, const inst_t &inst )
-{
- // Create a delay queue object and add it to the queue
- fixeddelay_queue_warp_t fixeddelay_queue_warp;
-
- // Set ready_cycle based on instruction space
- fixeddelay_queue_warp.inst = inst;
- switch(inst.space.get_type()) {
- case shared_space:
- fixeddelay_queue_warp.ready_cycle = gpu_tot_sim_cycle + gpu_sim_cycle + 5; // Adds 5*4=20 cycles
- break;
- default:
- fixeddelay_queue_warp.ready_cycle = gpu_tot_sim_cycle + gpu_sim_cycle;
- break;
- }
-
- // Store threads in delay queue warp object
- fixeddelay_queue_warp.tids.resize(m_config->warp_size);
- std::copy(tids, tids+m_config->warp_size, fixeddelay_queue_warp.tids.begin());
- m_fixeddelay_queue.insert(fixeddelay_queue_warp);
-}
-
-/*
- * Process a delay queue by unlocking warps ready this cycle
- *
- * @param *shader Pointer to shader core
- *
- */
-void shader_core_ctx::process_delay_queue() {
- shader_core_ctx *shader=this;
- // Unlock warps in fixeddelay_queue_warp
- std::multiset<fixeddelay_queue_warp_t, fixeddelay_queue_warp_comp>::iterator it;
- std::multiset<fixeddelay_queue_warp_t, fixeddelay_queue_warp_comp>::iterator it_last;
- for ( it=shader->m_fixeddelay_queue.begin() ;
- it != shader->m_fixeddelay_queue.end();
- ) {
- if(it->ready_cycle <= gpu_tot_sim_cycle + gpu_sim_cycle) {
- if(!m_config->gpgpu_stall_on_use) {
- // This disables stall-on-use
- // If thread is still in warp_tracker, do not unlock yet
- bool skip_unlock = false;
- for(unsigned i=0; i<m_config->warp_size; i++) {
- int tid = it->tids[i];
- if(tid < 0) continue;
- if(m_warp_tracker->wpt_thread_in_wpt(tid)) {
- skip_unlock = true;
- break;
- }
- }
- if(skip_unlock) {
- it_last = it++;
- continue;
- }
- }
-
- if (!strcmp("GT200",m_config->pipeline_model) ) {
- if( it->inst.space == shared_space ) {
- for(unsigned i=0; i < m_config->warp_size; i++ ) {
- if( it->tids[i]>= 0 ) {
- unsigned warp_id = it->tids[i]/m_config->warp_size;
- m_scoreboard->releaseRegisters(warp_id,&it->inst);
- break;
- }
- }
- }
- }
-
- // Unlock warp
- unlock_warp(it->tids);
-
- // Remove warp information from delay queue
- it_last = it++;
- shader->m_fixeddelay_queue.erase(it_last);
- } else {
- break;
- }
- }
-}
-
-/*
- * Unlock a warp
- *
- * @param tids Vector of tid in the warp to unlock
- *
- */
-void shader_core_ctx::unlock_warp( std::vector<int> tids )
-{
- assert( tids.size() == m_config->warp_size ); // required by thd_commit_queue usage in fetch_simd_dwf()
- int thd_unlocked = 0;
- int thd_exited = 0;
- int tid;
- int valid_tid = -1;
-
- if (!strcmp("GPGPUSIM_ORIG",m_config->pipeline_model) ) {
- // Unlock
- for (unsigned i=0; i<m_config->warp_size; i++) {
- tid = tids[i];
- if (tid >= 0) {
- valid_tid = tid;
- // thread completed if it is going to fetching beyond code boundary
- if ( ptx_thread_done(tid) ) {
- m_not_completed -= 1;
- m_stats->gpu_completed_thread += 1;
- int warp_id = wid_from_hw_tid(tid,m_config->warp_size);
- if (!(m_warp[warp_id].get_n_completed() < m_config->warp_size))
- printf("GPGPU-Sim uArch: shader[%d]->warp[%d].n_completed = %d; warp_size = %d\n",
- m_sid,warp_id, m_warp[warp_id].get_n_completed(), m_config->warp_size);
- assert( m_warp[warp_id].get_n_completed() < m_config->warp_size );
- m_warp[warp_id].inc_n_completed();
- register_cta_thread_exit( tid );
- thd_exited = 1;
- } else {
- if (!strcmp("GPGPUSIM_ORIG",m_config->pipeline_model) ) {
- assert(!m_thread[tid].m_avail4fetch);
- m_thread[tid].m_avail4fetch=true;
- assert( m_warp[tid/m_config->warp_size].get_avail4fetch() < m_config->warp_size );
- m_warp[tid/m_config->warp_size].inc_avail4fetch();
- }
- thd_unlocked = 1;
- }
- }
- }
- }
-
- if (!strcmp("GPGPUSIM_ORIG",m_config->pipeline_model) ) {
- if(thd_unlocked || thd_exited) {
- // Update the warp active mask
- m_pdom_warp[wid_from_hw_tid(valid_tid,m_config->warp_size)]->pdom_update_warp_mask();
- }
- }
-
- if (m_config->model == POST_DOMINATOR) {
- // Do nothing
- } else {
- // For this case, submit to commit_queue
- if (m_config->using_commit_queue && thd_unlocked)
- m_thd_commit_queue->push( new std::vector<int>(tids), gpu_sim_cycle );
- }
-}
-
-
-/*
- * Signals to the warp_tracker that a thread in a warp (for a given pc/instruction) is done
- *
- * @param *shd Pointer to shader core
- * @param done_inst Completed instruction
- *
- */
-void shader_core_ctx::call_thread_done( inst_t &done_inst )
-{
- if (m_config->gpgpu_no_divg_load) {
- // Signal to unlock the thread. If all threads are done, deregister warp
- if( m_warp_tracker->wpt_signal_avail(done_inst.hw_thread_id, done_inst.pc) == 1 ) {
- // Entire warp has returned
- // Deregister warp
- m_warp_tracker->wpt_deregister_warp(done_inst.hw_thread_id, done_inst.pc);
-
- if (! (!strcmp("GT200",m_config->pipeline_model) && (done_inst.space == shared_space)) )
- // Signal scoreboard to release register
- m_scoreboard->releaseRegisters( wid_from_hw_tid(done_inst.hw_thread_id, m_config->warp_size), &done_inst );
- }
- }
-}
-
-
void gpgpu_sim::shader_print_runtime_stat( FILE *fout )
{
fprintf(fout, "SHD_INSN: ");
@@ -2641,118 +1508,35 @@ void gpgpu_sim::shader_print_l1_miss_stat( FILE *fout )
fprintf(fout, "\n");
}
-void shader_core_ctx::print_warp( inst_t *warp, FILE *fout, int print_mem, int mask ) const
+void shader_core_ctx::print_warp( warp_inst_t *warp, FILE *fout, int print_mem, int mask ) const
{
- unsigned i, j, warp_id = (unsigned)-1;
- for (i=0; i<m_config->warp_size; i++) {
- if (warp[i].hw_thread_id > -1) {
- warp_id = warp[i].hw_thread_id / m_config->warp_size;
- break;
- }
- }
- i = (i>=m_config->warp_size)? 0 : i;
-
- if( warp[i].pc != (address_type)-1 )
- fprintf(fout,"0x%04x ", warp[i].pc );
- else
- fprintf(fout,"bubble " );
-
- if( mask & 2 ) {
- fprintf(fout, "(" );
- for (j=0; j<m_config->warp_size; j++)
- fprintf(fout, "%03d ", warp[j].hw_thread_id);
- fprintf(fout, "): ");
- } else {
- fprintf(fout, "w%02d[", warp_id);
- for (j=0; j<m_config->warp_size; j++)
- fprintf(fout, "%c", ((warp[j].hw_thread_id != -1)?'1':'0') );
- fprintf(fout, "]: ");
- }
-
- if( warp_id != (unsigned)-1 && 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[i].pc, fout );
-
- if( mask & 0x10 ) {
- if ( (warp[i].op == STORE_OP ||
- warp[i].op == LOAD_OP) && print_mem )
- fprintf(fout, " mem: 0x%016llx", warp[i].memreqaddr);
- }
- fprintf(fout, "\n");
+ if ( warp->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);
+ for (unsigned j=0; j<m_config->warp_size; j++)
+ fprintf(fout, "%c", (warp->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 );
+ fprintf(fout, "\n");
}
void shader_core_ctx::print_stage(unsigned int stage, FILE *fout, int print_mem, int mask )
{
- inst_t *warp = m_pipeline_reg[stage];
- print_warp(warp,fout,print_mem,mask);
+ print_warp(m_pipeline_reg[stage],fout,print_mem,mask);
}
-void shader_core_ctx::print_pre_mem_stages( FILE *fout, int print_mem, int mask )
-{
- unsigned i, j;
- int warp_id;
-
- if (!m_config->gpgpu_pre_mem_stages) return;
-
- for (unsigned pms = 0; pms <= m_config->gpgpu_pre_mem_stages; pms++) {
- fprintf(fout, "PM[%01d] = ", pms);
-
- warp_id = -1;
-
- for (i=0; i<m_config->warp_size; i++) {
- if (pre_mem_pipeline[pms][i].hw_thread_id > -1) {
- warp_id = pre_mem_pipeline[pms][i].hw_thread_id / m_config->warp_size;
- break;
- }
- }
- i = (i>=m_config->warp_size)? 0 : i;
-
- if( pre_mem_pipeline[pms][i].pc != (address_type)-1 )
- fprintf(fout,"0x%04x ", pre_mem_pipeline[pms][i].pc );
- else
- fprintf(fout,"bubble " );
-
- if( mask & 2 ) {
- fprintf(fout, "(" );
- for (j=0; j<m_config->warp_size; j++)
- fprintf(fout, "%03d ", pre_mem_pipeline[pms][j].hw_thread_id);
- fprintf(fout, "): ");
- } else {
- fprintf(fout, "w%02d[", warp_id);
- for (j=0; j<m_config->warp_size; j++)
- fprintf(fout, "%c", ((pre_mem_pipeline[pms][j].hw_thread_id != -1)?'1':'0') );
- fprintf(fout, "]: ");
- }
-
- if( warp_id != -1 && 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( pre_mem_pipeline[pms][i].pc, fout );
-
- if( mask & 0x10 ) {
- if ( ( pre_mem_pipeline[pms][i].op == LOAD_OP ||
- pre_mem_pipeline[pms][i].op == STORE_OP ) && print_mem )
- fprintf(fout, " mem: 0x%016llx", pre_mem_pipeline[pms][i].memreqaddr);
- }
- fprintf(fout, "\n");
- }
-}
-
-const char * ptx_get_fname( unsigned PC );
-
void shader_core_ctx::display_pdom_state(FILE *fout, int mask )
{
if ( (mask & 4) && m_config->model == POST_DOMINATOR ) {
@@ -2765,7 +1549,7 @@ void shader_core_ctx::display_pdom_state(FILE *fout, int mask )
int done = ptx_thread_done(tid);
nactive += (ptx_thread_done(tid)?0:1);
if ( done && (mask & 8) ) {
- unsigned done_cycle = ptx_thread_donecycle( m_thread[tid].m_functional_model_thread_state );
+ unsigned done_cycle = m_thread[tid].m_functional_model_thread_state->donecycle();
if ( done_cycle ) {
printf("\n w%02u:t%03u: done @ cycle %u", i, tid, done_cycle );
}
@@ -2787,9 +1571,6 @@ void shader_core_ctx::display_pipeline(FILE *fout, int print_mem, int mask )
gpu_tot_sim_cycle, gpu_sim_cycle, m_not_completed);
fprintf(fout, "=================================================\n");
- if (!strcmp("GPGPUSIM_ORIG",m_config->pipeline_model) )
- display_pdom_state(fout,mask);
-
if (!strcmp("GT200",m_config->pipeline_model) ) {
dump_istream_state(fout);
fprintf(fout,"\n");
@@ -2829,24 +1610,14 @@ void shader_core_ctx::display_pipeline(FILE *fout, int print_mem, int mask )
print_stage(ID_OC_SFU, fout, print_mem, mask);
m_operand_collector.dump(fout);
}
- if (m_config->m_using_dwf_rrstage) {
- fprintf(fout, "ID/RR = ");
- print_stage(ID_RR, fout, print_mem, mask);
- }
if (!strcmp("GT200",m_config->pipeline_model) )
fprintf(fout, "ID/EX (SP) = ");
- else
- fprintf(fout, "ID/EX = ");
print_stage(ID_EX, fout, print_mem, mask);
if (!strcmp("GT200",m_config->pipeline_model) ) {
fprintf(fout, "ID/EX (SFU) = ");
print_stage(OC_EX_SFU, fout, print_mem, mask);
}
- print_pre_mem_stages(fout, print_mem, mask);
- if (!m_config->gpgpu_pre_mem_stages)
- fprintf(fout, "EX/MEM = ");
- else
- fprintf(fout, "PM/MEM = ");
+ fprintf(fout, "EX/MEM = ");
print_stage(EX_MM, fout, print_mem, mask);
fprintf(fout, "MEM/WB = ");
print_stage(MM_WB, fout, print_mem, mask);
@@ -2905,7 +1676,7 @@ unsigned int shader_core_ctx::max_cta( class function_info *kernel )
void shader_core_ctx::cycle_gt200()
{
- clear_stage(m_pipeline_reg[WB_RT]);
+ m_pipeline_reg[WB_RT]->clear();
writeback();
memory();
execute();
@@ -2914,23 +1685,6 @@ void shader_core_ctx::cycle_gt200()
fetch_new();
}
-void shader_core_ctx::cycle()
-{
- clear_stage(m_pipeline_reg[WB_RT]);
- writeback();
- memory();
- if (m_config->gpgpu_pre_mem_stages) // for modeling deeper pipelines
- pre_memory();
- execute();
- if (m_config->m_using_dwf_rrstage) {
- preexecute();
- }
- if (m_config->gpgpu_operand_collector)
- m_operand_collector.step(m_pipeline_reg[ID_OC]);
- decode();
- fetch();
-}
-
// Flushes all content of the cache to memory
void shader_core_ctx::cache_flush()
@@ -3052,7 +1806,6 @@ std::list<opndcoll_rfu_t::op_t> opndcoll_rfu_t::arbiter_t::allocate_reads()
return result;
}
-
barrier_set_t::barrier_set_t( unsigned max_warps_per_core, unsigned max_cta_per_core )
{
m_max_warps_per_core = max_warps_per_core;
@@ -3244,15 +1997,13 @@ bool shd_warp_t::waiting()
void shd_warp_t::print( FILE *fout ) const
{
if ( n_completed < m_warp_size ) {
- fprintf( fout, "w%02u npc: 0x%04x, done:%2u a4f:%2u, i:%u s:%u a:%u b:%2u, (done: ",
+ fprintf( fout, "w%02u npc: 0x%04x, done:%2u i:%u s:%u a:%u (done: ",
m_warp_id,
m_next_pc,
n_completed,
- n_avail4fetch,
m_inst_in_pipeline,
m_stores_outstanding,
- m_n_atomic,
- n_waiting_at_barrier );
+ m_n_atomic );
for (unsigned i = m_warp_id*m_warp_size; i < (m_warp_id+1)*m_warp_size; i++ ) {
if ( m_shader->ptx_thread_done(i) ) fprintf(fout,"1");
else fprintf(fout,"0");
@@ -3360,12 +2111,6 @@ void mshr_entry::print(FILE *fp, unsigned mask) const
if ( m_mf )
ptx_print_insn( m_mf->get_pc(), fp );
fprintf(fp,"\n");
- if ( mask & 0x200 ) {
- for (unsigned i = 0; i < m_insts.size(); i++) {
- fprintf(fp,"\tthread: UID:%d HW:%d ReqAddr:0x%llx\n",
- m_insts[i].uid, m_insts[i].hw_thread_id, m_insts[i].memreqaddr);
- }
- }
}
}
@@ -3373,8 +2118,8 @@ void opndcoll_rfu_t::init( unsigned num_collectors_alu,
unsigned num_collectors_sfu,
unsigned num_banks,
shader_core_ctx *shader,
- inst_t **alu_port,
- inst_t **sfu_port )
+ warp_inst_t **alu_port,
+ warp_inst_t **sfu_port )
{
m_num_collectors = num_collectors_alu+num_collectors_sfu;
@@ -3409,36 +2154,26 @@ void opndcoll_rfu_t::init( unsigned num_collectors_alu,
}
}
-bool opndcoll_rfu_t::writeback( inst_t *warp )
-{
- // prefer not to stall writeback
- inst_t *fvt=m_shader->first_valid_thread(warp);
- if (!fvt)
- return true; // nothing to do
- return writeback(*fvt);
-}
-
-int register_bank(int regnum, int tid, unsigned num_banks, unsigned bank_warp_shift)
+int register_bank(int regnum, int wid, unsigned num_banks, unsigned bank_warp_shift)
{
int bank = regnum;
if (bank_warp_shift)
- bank += tid >> bank_warp_shift;
+ bank += wid;
return bank % num_banks;
}
-bool opndcoll_rfu_t::writeback( const inst_t &fvt )
+bool opndcoll_rfu_t::writeback( const warp_inst_t &warp )
{
- int tid = fvt.hw_thread_id;
- assert( tid >= 0 ); // must be a valid instruction
- std::list<unsigned> regs = m_shader->get_regs_written(fvt);
+ assert( !warp.empty() );
+ std::list<unsigned> regs = m_shader->get_regs_written(warp);
std::list<unsigned>::iterator r;
unsigned last_reg = -1;
unsigned n=0;
for( r=regs.begin(); r!=regs.end();r++,n++ ) {
unsigned reg = *r;
- unsigned bank = register_bank(reg,tid,m_num_banks,m_bank_warp_shift);
+ unsigned bank = register_bank(reg,warp.warp_id(),m_num_banks,m_bank_warp_shift);
if( m_arbiter.bank_idle(bank) ) {
- m_arbiter.allocate_bank_for_write(bank,op_t(&fvt,reg,m_num_banks,m_bank_warp_shift));
+ m_arbiter.allocate_bank_for_write(bank,op_t(&warp,reg,m_num_banks,m_bank_warp_shift));
} else {
return false;
}
@@ -3451,8 +2186,8 @@ void opndcoll_rfu_t::dispatch_ready_cu()
{
port_to_du_t::iterator p;
for( p=m_dispatch_units.begin(); p!=m_dispatch_units.end(); ++p ) {
- inst_t **port = p->first;
- if( !m_shader->pipeline_regster_empty(*port) )
+ warp_inst_t **port = p->first;
+ if( !(*port)->empty() )
continue;
dispatch_unit_t &du = p->second;
collector_unit_t *cu = du.find_ready();
@@ -3463,12 +2198,11 @@ void opndcoll_rfu_t::dispatch_ready_cu()
}
}
-void opndcoll_rfu_t::allocate_cu( inst_t *&id_oc_reg )
+void opndcoll_rfu_t::allocate_cu( warp_inst_t *&id_oc_reg )
{
- inst_t *fvi = m_shader->first_valid_thread(id_oc_reg);
- if( fvi ) {
- inst_t **port = NULL;
- if( fvi->op == SFU_OP )
+ 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;
@@ -3489,8 +2223,8 @@ void opndcoll_rfu_t::allocate_reads()
for( std::list<op_t>::iterator r=allocated.begin(); r!=allocated.end(); r++ ) {
const op_t &rr = *r;
unsigned reg = rr.get_reg();
- unsigned tid = rr.get_tid();
- unsigned bank = register_bank(reg,tid,m_num_banks,m_bank_warp_shift);
+ unsigned wid = rr.get_wid();
+ unsigned bank = register_bank(reg,wid,m_num_banks,m_bank_warp_shift);
m_arbiter.allocate_for_read(bank,rr);
read_ops[bank] = rr;
}
@@ -3513,7 +2247,7 @@ void gpgpu_sim::decrement_atomic_count( unsigned sid, unsigned wid )
bool opndcoll_rfu_t::collector_unit_t::ready() const
{
- return (!m_free) && m_not_ready.none() && m_rfu->shader_core()->pipeline_regster_empty(*m_port);
+ return (!m_free) && m_not_ready.none() && (*m_port)->empty();
}
void opndcoll_rfu_t::collector_unit_t::dump(FILE *fp, const shader_core_ctx *shader ) const
@@ -3532,7 +2266,7 @@ void opndcoll_rfu_t::collector_unit_t::dump(FILE *fp, const shader_core_ctx *sha
}
void opndcoll_rfu_t::collector_unit_t::init( unsigned n,
- inst_t **port,
+ warp_inst_t **port,
unsigned num_banks,
unsigned log2_warp_size,
unsigned warp_size,
@@ -3543,36 +2277,33 @@ void opndcoll_rfu_t::collector_unit_t::init( unsigned n,
m_port=port;
m_num_banks=num_banks;
assert(m_warp==NULL);
- m_warp = (inst_t*)calloc(sizeof(inst_t),warp_size);
- m_rfu->shader_core()->clear_stage(m_warp);
+ m_warp = new warp_inst_t(warp_size);
m_bank_warp_shift=log2_warp_size;
}
-void opndcoll_rfu_t::collector_unit_t::allocate( inst_t *&pipeline_reg )
+void opndcoll_rfu_t::collector_unit_t::allocate( warp_inst_t *&pipeline_reg )
{
assert(m_free);
assert(m_not_ready.none());
m_free = false;
- inst_t *fvi = m_rfu->shader_core()->first_valid_thread(pipeline_reg);
- if( fvi ) {
- m_tid = fvi->hw_thread_id;
- m_warp_id = m_tid/m_rfu->shader_core()->get_config()->warp_size;
+ if( !pipeline_reg->empty() ) {
+ m_warp_id = pipeline_reg->warp_id();
for( unsigned op=0; op < 4; op++ ) {
- int reg_num = fvi->arch_reg[4+op]; // this math needs to match that used in function_info::ptx_decode_inst
+ int reg_num = pipeline_reg->arch_reg[4+op]; // this math needs to match that used in function_info::ptx_decode_inst
if( reg_num >= 0 ) { // valid register
m_src_op[op] = op_t( this, op, reg_num, m_num_banks, m_bank_warp_shift );
m_not_ready.set(op);
} else
m_src_op[op] = op_t();
}
- m_rfu->shader_core()->move_warp(m_warp,pipeline_reg);
+ move_warp(m_warp,pipeline_reg);
}
}
void opndcoll_rfu_t::collector_unit_t::dispatch()
{
assert( m_not_ready.none() );
- m_rfu->shader_core()->move_warp(*m_port,m_warp);
+ move_warp(*m_port,m_warp);
m_free=true;
for( unsigned i=0; i<MAX_REG_OPERANDS;i++)
m_src_op[i].reset();