summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/abstract_hardware_model.cc8
-rw-r--r--src/abstract_hardware_model.h75
-rw-r--r--src/cuda-sim/cuda-sim.cc16
-rw-r--r--src/debug.cc5
-rw-r--r--src/gpgpu-sim/gpu-sim.cc21
-rw-r--r--src/gpgpu-sim/gpu-sim.h4
-rw-r--r--src/gpgpu-sim/shader.cc496
-rw-r--r--src/gpgpu-sim/shader.h170
8 files changed, 338 insertions, 457 deletions
diff --git a/src/abstract_hardware_model.cc b/src/abstract_hardware_model.cc
index a0e21f7..c52be1d 100644
--- a/src/abstract_hardware_model.cc
+++ b/src/abstract_hardware_model.cc
@@ -1,5 +1,8 @@
#include "abstract_hardware_model.h"
#include "cuda-sim/memory.h"
+#include <algorithm>
+
+unsigned mem_access_t::next_access_uid = 0;
void move_warp( warp_inst_t *&dst, warp_inst_t *&src )
{
@@ -19,3 +22,8 @@ gpgpu_t::gpgpu_t()
g_dev_malloc=GLOBAL_HEAP_START;
}
+
+void warp_inst_t::sort_accessq( unsigned qbegin )
+{
+ std::stable_sort( m_accessq.begin()+qbegin,m_accessq.end());
+}
diff --git a/src/abstract_hardware_model.h b/src/abstract_hardware_model.h
index c90d56e..7162441 100644
--- a/src/abstract_hardware_model.h
+++ b/src/abstract_hardware_model.h
@@ -223,11 +223,68 @@ public:
enum _memory_space_t get_type() const { return m_type; }
unsigned get_bank() const { return m_bank; }
void set_bank( unsigned b ) { m_bank = b; }
+ bool is_const() const { return (m_type == const_space) || (m_type == param_space_kernel); }
+ bool is_local() const { return (m_type == local_space) || (m_type == param_space_local); }
+
private:
enum _memory_space_t m_type;
unsigned m_bank; // n in ".const[n]"; note .const == .const[0] (see PTX 2.1 manual, sec. 5.1.3)
};
+class mem_access_t {
+public:
+ mem_access_t()
+ {
+ init();
+ }
+ mem_access_t(address_type address, unsigned size, unsigned quarter, unsigned idx )
+ {
+ init();
+ addr = address;
+ req_size = size;
+ quarter_count[quarter]++;
+ warp_indices.push_back(idx);
+ }
+
+ bool operator<(const mem_access_t &other) const {return (order > other.order);}//this is reverse
+
+private:
+ void init()
+ {
+ uid=++next_access_uid;
+ addr=0;
+ req_size=0;
+ order=0;
+ _quarter_count_all=0;
+ cache_hit = false;
+ cache_checked = false;
+ recheck_cache = false;
+ need_wb = false;
+ wb_addr = 0;
+ reserved_mshr = NULL;
+ }
+
+public:
+
+ unsigned uid;
+ address_type addr; //address of the segment to load.
+ unsigned req_size; //bytes
+ unsigned order; // order of accesses, based on banks.
+ union{
+ unsigned _quarter_count_all;
+ char quarter_count[4]; //access counts to each quarter of segment, for compaction;
+ };
+ std::vector<unsigned> warp_indices; // warp indicies for this request.
+ bool cache_hit;
+ bool cache_checked;
+ bool recheck_cache;
+ bool need_wb;
+ address_type wb_addr; // writeback address (if necessary).
+ class mshr_entry* reserved_mshr;
+
+private:
+ static unsigned next_access_uid;
+};
#define MAX_REG_OPERANDS 8
@@ -260,6 +317,8 @@ public:
{
fprintf(fp," [inst @ pc=0x%04x] ", pc );
}
+ bool is_load() const { return (op == LOAD_OP || memory_op == memory_load); }
+ bool is_store() const { return (op == STORE_OP || memory_op == memory_store); }
address_type pc; // program counter address of instruction
unsigned isize; // size of instruction in bytes
@@ -362,6 +421,10 @@ public:
}
}
}
+ void set_not_active( unsigned lane_id )
+ {
+ warp_active_mask.reset(lane_id);
+ }
// accessors
virtual void print_insn(FILE *fp) const
@@ -391,6 +454,16 @@ public:
bool isatomic() const { return m_isatomic; }
+ bool mem_accesses_computed() const { return m_mem_accesses_created; }
+ void set_mem_accesses_computed() { m_mem_accesses_created=true; }
+ bool accessq_empty() const { return m_accessq.empty(); }
+ unsigned get_accessq_size() const { return m_accessq.size(); }
+ mem_access_t &accessq( unsigned n ) { return m_accessq[n]; }
+ mem_access_t &accessq_back() { return m_accessq.back(); }
+ void accessq_push_back( const mem_access_t &req ) { m_accessq.push_back(req); }
+ void accessq_pop_back() { m_accessq.pop_back(); }
+ void sort_accessq( unsigned qbegin );
+
protected:
bool m_empty;
unsigned long long issue_cycle;
@@ -410,6 +483,8 @@ protected:
};
bool m_per_scalar_thread_valid;
std::vector<per_thread_info> m_per_scalar_thread;
+ bool m_mem_accesses_created;
+ std::vector<mem_access_t> m_accessq;
};
void move_warp( warp_inst_t *&dst, warp_inst_t *&src );
diff --git a/src/cuda-sim/cuda-sim.cc b/src/cuda-sim/cuda-sim.cc
index 7f4eebd..5293d7d 100644
--- a/src/cuda-sim/cuda-sim.cc
+++ b/src/cuda-sim/cuda-sim.cc
@@ -873,21 +873,20 @@ void ptx_thread_info::ptx_exec_inst( warp_inst_t &inst, unsigned lane_id )
skip = !pred_lookup(pI->get_pred_mod(), pred_value.pred & 0x000F);
}
}
- if( !skip ) {
+ if( skip ) {
+ inst.set_not_active(lane_id);
+ } else {
ptx_instruction *pJ = NULL;
if( pI->get_opcode() == VOTE_OP ) {
pJ = new ptx_instruction(*pI);
- *((warp_inst_t*)pJ) = inst;
+ *((warp_inst_t*)pJ) = inst; // copy active mask information
pI = pJ;
}
switch ( pI->get_opcode() ) {
#define OP_DEF(OP,FUNC,STR,DST,CLASSIFICATION) case OP: FUNC(pI,this); op_classification = CLASSIFICATION; break;
#include "opcodes.def"
#undef OP_DEF
-
- default:
- printf( "Execution error: Invalid opcode (0x%x)\n", pI->get_opcode() );
- break;
+ default: printf( "Execution error: Invalid opcode (0x%x)\n", pI->get_opcode() ); break;
}
delete pJ;
@@ -1024,10 +1023,7 @@ void ptx_thread_info::ptx_exec_inst( warp_inst_t &inst, unsigned lane_id )
inst.set_addr(lane_id, insn_memaddr);
inst.data_size = insn_data_size;
inst.memory_op = insn_memory_op;
- } else {
- inst.space = undefined_space;
- inst.memory_op = no_memory_op;
- }
+ }
} catch ( int x ) {
printf("GPGPU-Sim PTX: ERROR (%d) executing intruction (%s:%u)\n", x, pI->source_file(), pI->source_line() );
diff --git a/src/debug.cc b/src/debug.cc
index c1aa3c6..928c057 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -85,9 +85,8 @@ void gpgpu_sim::gpgpu_debug()
}
} else {
for( unsigned sid=0; sid < m_n_shader; sid++ ) {
- unsigned hw_thread_id = m_sc[sid]->first_valid_thread(IF_ID);
- if( hw_thread_id == (unsigned)-1 )
- continue;
+ unsigned hw_thread_id = -1;
+ abort();
ptx_thread_info *thread = m_sc[sid]->get_functional_thread(hw_thread_id);
if( thread_at_brkpt(thread, b) ) {
done = false;
diff --git a/src/gpgpu-sim/gpu-sim.cc b/src/gpgpu-sim/gpu-sim.cc
index 77c6aae..7646ee7 100644
--- a/src/gpgpu-sim/gpu-sim.cc
+++ b/src/gpgpu-sim/gpu-sim.cc
@@ -221,10 +221,6 @@ void gpgpu_sim::reg_options(option_parser_t opp)
"enable perfect memory mode (no cache miss)",
"0");
- option_parser_register(opp, "-gpgpu_sm_uarch", OPT_CSTR, &m_shader_config->pipeline_model,
- "shader core uarch model [GPGPUSIM_ORIG,GT200] (default=GPGPUSIM_ORIG)",
- "GPGPUSIM_ORIG");
-
option_parser_register(opp, "-gpgpu_shader_core_pipeline", OPT_CSTR, &gpgpu_shader_core_pipeline_opt,
"shader core pipeline config, i.e., {<nthread>:<warpsize>:<pipe_simd_width>}",
"256:32:32");
@@ -378,9 +374,6 @@ void gpgpu_sim::reg_options(option_parser_t opp)
&m_ptx_force_max_capability,
"Force maximum compute capability",
"0");
- option_parser_register(opp, "-gpgpu_operand_collector", OPT_BOOL, &m_shader_config->gpgpu_operand_collector,
- "Enable operand collector model (default = off)",
- "0");
option_parser_register(opp, "-gpgpu_operand_collector_num_units", OPT_INT32, &m_shader_config->gpgpu_operand_collector_num_units,
"number of collecture units (default = 4)",
"4");
@@ -914,12 +907,10 @@ unsigned gpgpu_sim::threads_per_core() const
return m_shader_config->n_thread_per_shader;
}
-void gpgpu_sim::mem_instruction_stats(warp_inst_t* warp)
+void gpgpu_sim::mem_instruction_stats(warp_inst_t &inst)
{
- if( warp->empty() )
- return; //bubble
//this breaks some encapsulation: the is_[space] functions, if you change those, change this.
- switch (warp->space.get_type()) {
+ switch (inst.space.get_type()) {
case undefined_space:
case reg_space:
break;
@@ -938,7 +929,7 @@ void gpgpu_sim::mem_instruction_stats(warp_inst_t* warp)
break;
case global_space:
case local_space:
- if( is_store(*warp) )
+ if( inst.is_store() )
m_shader_stats->gpgpu_n_store_insn++;
else
m_shader_stats->gpgpu_n_load_insn++;
@@ -1009,10 +1000,8 @@ void shader_core_ctx::fill_shd_L1_with_new_line(mem_fetch * mf)
void shader_core_ctx::store_ack( class mem_fetch *mf )
{
- if (!strcmp("GT200",m_config->pipeline_model) ) {
unsigned warp_id = mf->get_wid();
m_warp[warp_id].dec_store_req();
- }
}
void gpgpu_sim::fq_pop(int tpc_id)
@@ -1290,9 +1279,7 @@ void gpgpu_sim::cycle()
// L1 cache + shader core pipeline stages
for (unsigned i=0;i<m_n_shader;i++) {
if (m_sc[i]->get_not_completed() || more_thread) {
- if (!strcmp("GT200",m_shader_config->pipeline_model) )
m_sc[i]->cycle_gt200();
- else abort();
}
}
if( g_single_step && ((gpu_sim_cycle+gpu_tot_sim_cycle) >= g_single_step) ) {
@@ -1426,8 +1413,6 @@ void gpgpu_sim::dump_pipeline( int mask, int s, int m ) const
i = s;
}
if(mask&1) m_sc[i]->display_pipeline(stdout, 1, mask & 0x2E );
- if (!strcmp("GPGPUSIM_ORIG",m_shader_config->pipeline_model) )
- if(mask&0x40) m_sc[i]->dump_istream_state(stdout);
if(mask&0x100) m_sc[i]->mshr_print(stdout, mask);
if(s != -1) {
break;
diff --git a/src/gpgpu-sim/gpu-sim.h b/src/gpgpu-sim/gpu-sim.h
index a41849e..37c87f4 100644
--- a/src/gpgpu-sim/gpu-sim.h
+++ b/src/gpgpu-sim/gpu-sim.h
@@ -103,7 +103,6 @@ enum divergence_support_t {
struct shader_core_config
{
- char *pipeline_model;
unsigned warp_size;
bool gpgpu_perfect_mem;
enum divergence_support_t model;
@@ -118,7 +117,6 @@ struct shader_core_config
char *gpgpu_cache_il1_opt;
unsigned n_mshr_per_shader;
bool gpgpu_dwf_reg_bankconflict;
- bool gpgpu_operand_collector;
int gpgpu_operand_collector_num_units;
int gpgpu_operand_collector_num_units_sfu;
bool gpgpu_stall_on_use;
@@ -205,7 +203,7 @@ public:
unsigned num_shader() const { return m_n_shader; }
unsigned threads_per_core() const;
- void mem_instruction_stats( class warp_inst_t* warp);
+ void mem_instruction_stats( class warp_inst_t &inst);
int issue_mf_from_fq(class mem_fetch *mf);
void gpu_print_stat() const;
diff --git a/src/gpgpu-sim/shader.cc b/src/gpgpu-sim/shader.cc
index 1d51004..9ffb3e7 100644
--- a/src/gpgpu-sim/shader.cc
+++ b/src/gpgpu-sim/shader.cc
@@ -1,5 +1,5 @@
/*
- * shader.c
+ * shader.cc
*
* Copyright (c) 2009 by Tor M. Aamodt, Wilson W. L. Fung, Ali Bakhoda,
* George L. Yuan, Ivan Sham, Henry Wong, Dan O'Connor, Henry Tran and the
@@ -86,8 +86,6 @@
#define MAX(a,b) (((a)>(b))?(a):(b))
-unsigned mem_access_t::next_access_uid = 0;
-
/////////////////////////////////////////////////////////////////////////////
/*-------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
@@ -306,12 +304,6 @@ unsigned char shader_core_ctx::fq_push(unsigned long long int addr,
return(m_gpu->issue_mf_from_fq(mf));
}
-unsigned shader_core_ctx::first_valid_thread( unsigned stage )
-{
- abort();
-}
-
-
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);
@@ -401,24 +393,16 @@ 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);
- m_shader_memory_new_instruction_processed = false;
m_mem_rc = NO_RC_FAIL,
// Initialize scoreboard
m_scoreboard = new Scoreboard(m_sid, m_config->max_warps_per_shader);
- if( m_config->gpgpu_operand_collector ) {
- 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[ID_EX],
- &m_pipeline_reg[OC_EX_SFU] );
- }
-
- m_memory_queue.shared.reserve(warp_size);
- m_memory_queue.constant.reserve(warp_size);
- m_memory_queue.texture.reserve(warp_size);
- m_memory_queue.local_global.reserve(warp_size);
+ 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] );
// fetch
m_last_warp_fetched = 0;
@@ -701,27 +685,6 @@ void shader_core_ctx::fetch_new()
}
}
-int is_load ( const inst_t &inst )
-{
- return (inst.op == LOAD_OP || inst.memory_op == memory_load);
-}
-
-int is_store ( const inst_t &inst )
-{
- return (inst.op == STORE_OP || inst.memory_op == memory_store);
-}
-
-int is_const ( memory_space_t space )
-{
- return((space.get_type() == const_space) || (space == param_space_kernel));
-}
-
-int is_local ( memory_space_t space )
-{
- return (space == local_space) || (space == param_space_local);
-}
-
-
void shader_core_ctx::func_exec_inst( warp_inst_t &inst )
{
for ( unsigned t=0; t < m_config->warp_size; t++ ) {
@@ -730,7 +693,7 @@ void shader_core_ctx::func_exec_inst( warp_inst_t &inst )
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)))
+ if (inst.space.is_local() && (inst.is_load() || inst.is_store()))
inst.set_addr(t, translate_local_memaddr(inst.get_addr(t), tid, m_gpu->num_shader()) );
if ( ptx_thread_done(tid) ) {
m_warp[inst.warp_id()].inc_n_completed();
@@ -763,7 +726,6 @@ void shader_core_ctx::decode_new()
unsigned checked=0;
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 warp_inst_t *pI = m_warp[warp_id].ibuffer_next_inst();
bool valid = m_warp[warp_id].ibuffer_next_valid();
unsigned pc,rpc;
@@ -775,9 +737,10 @@ void shader_core_ctx::decode_new()
m_warp[warp_id].set_next_pc(pc);
m_warp[warp_id].ibuffer_flush();
} 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]->empty() ) {
- issue_warp(m_pipeline_reg[ID_OC],pI,active_mask,warp_id);
+ 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);
@@ -832,30 +795,30 @@ address_type shader_core_ctx::translate_local_memaddr(address_type localaddr, in
/////////////////////////////////////////////////////////////////////////////////////////
-void shader_core_ctx::execute_pipe( unsigned pipeline, unsigned next_stage )
+void shader_core_ctx::execute_pipe( unsigned current_stage, unsigned next_stage )
{
- if( !m_pipeline_reg[next_stage]->empty() )
- return;
- if( m_pipeline_reg[pipeline]->cycles > 1 ) {
- m_pipeline_reg[pipeline]->cycles--;
- return;
+ if( !m_pipeline_reg[current_stage]->empty() ) {
+ if( m_pipeline_reg[current_stage]->cycles > 1 ) {
+ m_pipeline_reg[current_stage]->cycles--;
+ return;
+ }
}
- move_warp(m_pipeline_reg[next_stage],m_pipeline_reg[pipeline]);
- m_shader_memory_new_instruction_processed = false;
+ 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(ID_EX, EX_MM);
+ 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* warp)
+mshr_entry* mshr_shader_unit::add_mshr(mem_access_t &access, warp_inst_t* pinst)
{
// 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->warp_id());
- warp_inst_t inst = *warp;
+ mshr_entry* mshr = alloc_free_mshr(pinst->space == tex_space);
+ mshr->init(access.addr,pinst->is_store(),pinst->space,pinst->warp_id());
+ warp_inst_t inst = *pinst;
inst.set_active(access.warp_indices);
mshr->add_inst(inst);
if( m_shader_config->gpgpu_interwarp_mshr_merge ) {
@@ -878,7 +841,7 @@ address_type line_size_based_tag_func(address_type address, unsigned line_size)
address_type null_tag_func(address_type address, unsigned line_size)
{
- return address; //no modification: each address is its own tag. Equivalent to line_size_based_tag_func(address,1), but line_size ignored.
+ return address; //no modification: each address is its own tag.
}
// only 1 bank
@@ -906,172 +869,155 @@ 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,
- memory_pipe_t mem_pipe,
unsigned warp_parts,
unsigned line_size,
bool limit_broadcast,
- std::vector<mem_access_t> &accessq )
+ warp_inst_t &inst )
{
- 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".
+ // This is called once per warp_inst_t when the warp_inst_t enters the memory stage.
+ // 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.
- // This is called once per warp when it enters the memory stage.
- // It takes the warp and produces a queue of accesses that can be peformed.
- // These are then performed over multiple cycles (stalling the pipeline) if the accessses cannot be
- // performed all at once.
- // It is a convenience for simulation; in hardware the warp would be processed each cycle
- // until it was done. Each cycle would do the first accesses available to it and mark off the
- // those threads served by those accesses.
-
- // Because it calculates all the accesses at once, what follows is largely not as the hw would do it.
- // Accesses are assigned an order number based on when that access may be issued.
+ // 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.
- // Later when the queue is processed it will evaluate accesses of
- // as many orders as ports on that cache/shmem.
- // These accesses are placed into a queue and sorted so that accesses of the same order are next to each other.
-
+ // Later, when the queue is processed it will evaluate accesses of as many orders as
+ // ports on that cache/shmem.
+ //
+ // Accesses are placed in accessq sorted so that accesses of the same order are adjacent.
- // tracks bank accesses for sorting into generations;
+ // 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
// its number of ports in one cycle.
std::map<unsigned,unsigned> bank_accs;
- //keep track of broadcasts with unique orders if limit_broadcast
- //the normally calculated orders will never be greater than warp_size
+ // 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 = accessq.size();
+ unsigned qbegin = inst.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) {
for (unsigned i = part; i < part + mem_pipe_size; i++) {
- if ( !insns->active(i) )
+ if ( !inst.active(i) )
continue;
- if( insns->space == undefined_space )
- continue; // this happens when thread predicated off
- new_addr_type addr = insns->get_addr(i);
+ assert( inst.space != undefined_space );
+ new_addr_type addr = inst.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( !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( !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 (limit_broadcast) // two threads access this address, so its a broadcast.
- accessq[j].order = ++broadcast_order; //do broadcast in its own cycle.
+ inst.accessq(j).order = ++broadcast_order; //do broadcast in its own cycle.
match = true;
break;
}
}
}
- if (!match) { // does not match an previous request by another thread, so need a new request
- assert( insns->space != undefined_space );
- accessq.push_back( mem_access_t( lane_segment_address,
- insns->space,
- mem_pipe,
- insns->isatomic(),
- is_store(*insns),
- line_size, quarter, i) );
+ 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) );
// Determine Bank Conflicts:
- unsigned bank = (this->*bank_func)(insns->get_addr(i), line_size);
+ unsigned bank = (this->*bank_func)(inst.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;
- accessq.back().order = bank_accs[bank];
+ inst.accessq_back().order = bank_accs[bank];
bank_accs[bank]++;
}
}
- qpartbegin = accessq.size(); //don't coalesce accross warp parts
+ qpartbegin = inst.get_accessq_size(); //don't coalesce accross warp parts
}
- //sort requests into order according to order (orders will not necessarily be consequtive if multiple parts)
- std::stable_sort(accessq.begin()+qbegin,accessq.end());
+ //sort requests by order they will be processed in
+ inst.sort_accessq(qbegin);
}
-void shader_core_ctx::memory_shared_process_warp()
+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,
- SHARED_MEM_PATH,
m_config->gpgpu_shmem_pipe_speedup,
1, //shared memory doesn't care about line_size, needs to be at least 1;
- true, // limit broadcasts to single cycle.
- m_memory_queue.shared);
+ true,
+ inst); // limit broadcasts to single cycle.
}
-void shader_core_ctx::memory_const_process_warp()
+void shader_core_ctx::memory_const_process_warp(warp_inst_t &inst)
{
// initial processing of const memory warps
- std::vector<mem_access_t> &accessq = m_memory_queue.constant;
- unsigned qbegin = accessq.size();
+ unsigned qbegin = inst.get_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);
+ 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 < accessq.size(); i++) {
- if ( accessq[i].space == param_space_kernel ) {
- accessq[i].cache_hit = true;
+ for (unsigned i = qbegin; i < inst.get_accessq_size(); i++) {
+ mem_access_t &req = inst.accessq(i);
+ if ( inst.space == param_space_kernel ) {
+ req.cache_hit = true;
} else {
- cache_request_status status = m_L1C->access( accessq[i].addr,
+ cache_request_status status = m_L1C->access( req.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++;
+ req.cache_hit = (status == HIT);
+ if (m_config->gpgpu_perfect_mem) req.cache_hit = true;
+ if (req.cache_hit) m_stats->L1_const_miss++;
}
- accessq[i].cache_checked = true;
+ req.cache_checked = true;
}
}
-void shader_core_ctx::memory_texture_process_warp()
+void shader_core_ctx::memory_texture_process_warp(warp_inst_t &inst)
{
// initial processing of shared texture warps
- std::vector<mem_access_t> &accessq = m_memory_queue.texture;
- unsigned qbegin = accessq.size();
+ unsigned qbegin = inst.get_accessq_size();
get_memory_access_list(&shader_core_ctx::null_bank_func,
&line_size_based_tag_func,
- TEXTURE_MEM_PATH,
1, //warp parts
- m_L1T->get_line_sz(),
- false, //no broadcast limit.
- accessq);
+ 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 < accessq.size(); i++) {
- cache_request_status status = m_L1T->access( accessq[i].addr,
+ for (unsigned i = qbegin; 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
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_texture_miss++;
- accessq[i].cache_checked = true;
+ req.cache_hit = (status == HIT);
+ if (m_config->gpgpu_perfect_mem) req.cache_hit = true;
+ if (req.cache_hit) m_stats->L1_texture_miss++;
+ req.cache_checked = true;
}
}
-void shader_core_ctx::memory_global_process_warp()
+void shader_core_ctx::memory_global_process_warp( warp_inst_t &inst )
{
- std::vector<mem_access_t> &accessq = m_memory_queue.local_global;
- unsigned qbegin = accessq.size();
+ 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 = m_pipeline_reg[EX_MM]->data_size;
+ unsigned data_size = inst.data_size;
// line size is dependant on instruction;
switch (data_size) {
case 1: line_size = 32; break;
@@ -1083,43 +1029,41 @@ void shader_core_ctx::memory_global_process_warp()
}
get_memory_access_list( &shader_core_ctx::dcache_bank_func,
&line_size_based_tag_func,
- GLOBAL_MEM_PATH,
warp_parts,
line_size,
false,
- accessq);
+ 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 < accessq.size(); i++) {
+ 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 = accessq[i].quarter_count;
+ 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 (accessq[i].req_size == 128) {
+ if (inst.accessq(i).req_size == 128) {
if (low xor high) { //can reduce size
- accessq[i].req_size = 64;
- if (high) accessq[i].addr += 64;
+ 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 (accessq[i].req_size == 64) {
+ if (inst.accessq(i).req_size == 64) {
if (low xor high) { //can reduce size
- accessq[i].req_size = 32;
- if (high) accessq[i].addr += 32;
+ inst.accessq(i).req_size = 32;
+ if (high) inst.accessq(i).addr += 32;
}
}
}
}
}
-mem_stage_stall_type shader_core_ctx::send_mem_request(mem_access_t &access)
+mem_stage_stall_type shader_core_ctx::send_mem_request(warp_inst_t &inst, mem_access_t &access)
{
// 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.
@@ -1130,63 +1074,64 @@ mem_stage_stall_type shader_core_ctx::send_mem_request(mem_access_t &access)
return WB_ICNT_RC_FAIL;
}
fq_push( access.wb_addr, req_size, true, NO_PARTIAL_WRITE, -1, NULL,
- is_local(access.space)?LOCAL_ACC_W:GLOBAL_ACC_W, //space of cache line is same as new request
+ inst.space.is_local()?LOCAL_ACC_W:GLOBAL_ACC_W, //space of cache line is same as new request
-1);
m_stats->L1_writeback++;
access.need_wb = false;
}
+
+ bool is_write = inst.is_store();
mem_access_type access_type;
- switch(access.space.get_type()) {
+ switch(inst.space.get_type()) {
case const_space:
case param_space_kernel: access_type = CONST_ACC_R; break;
case tex_space: access_type = TEXTURE_ACC_R; break;
- case global_space: access_type = (access.iswrite)? GLOBAL_ACC_W: GLOBAL_ACC_R; break;
+ case global_space: access_type = is_write? GLOBAL_ACC_W: GLOBAL_ACC_R; break;
case local_space:
- case param_space_local: access_type = (access.iswrite)? LOCAL_ACC_W: LOCAL_ACC_R; break;
+ case param_space_local: access_type = is_write? LOCAL_ACC_W: LOCAL_ACC_R; break;
default: assert(0); break;
}
//reserve mshr
- bool requires_mshr = (not access.iswrite);
- if (requires_mshr and not access.reserved_mshr) {
+ bool requires_mshr = (!is_write);
+ if (requires_mshr && !access.reserved_mshr) {
if (not m_mshr_unit->has_mshr(1))
return MSHR_RC_FAIL;
- access.reserved_mshr = m_mshr_unit->add_mshr(access, warp);
+ 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.
}
//require inct if access is this far without reserved mshr, or has and mshr but not merged with another request
- bool requires_icnt = (not access.reserved_mshr) or (not access.reserved_mshr->ismerged() );
+ bool requires_icnt = (!access.reserved_mshr) || (!access.reserved_mshr->ismerged());
if (requires_icnt) {
//calculate request size for icnt check (and later send);
unsigned request_size = access.req_size;
- if (access.iswrite) {
+ if (is_write) {
if (requires_mshr)
request_size += READ_PACKET_SIZE + WRITE_MASK_SIZE; // needs information for a load back into cache.
else
request_size += WRITE_PACKET_SIZE + WRITE_MASK_SIZE; //plain write
}
- if ( !m_gpu->fq_has_buffer(access.addr, request_size, access.iswrite, m_sid) ) {
+ if ( !m_gpu->fq_has_buffer(access.addr, request_size, is_write, m_sid) ) {
// can't allocate icnt
m_stats->gpu_stall_sh2icnt++;
return ICNT_RC_FAIL;
}
//send over interconnect
partial_write_mask_t write_mask = NO_PARTIAL_WRITE;
- unsigned warp_id = warp->warp_id();
- if (access.iswrite) {
- if (!strcmp("GT200",m_config->pipeline_model) )
- m_warp[warp_id].inc_store_req();
+ unsigned warp_id = inst.warp_id();
+ if (is_write) {
+ 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->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);
+ int data_offset = inst.get_addr(w) & ((unsigned long long int)access.req_size - 1);
+ for (unsigned b = data_offset; b < data_offset + inst.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, warp->pc );
+ is_write, write_mask, warp_id , access.reserved_mshr,
+ access_type, inst.pc );
}
return NO_RC_FAIL;
}
@@ -1206,32 +1151,33 @@ void shader_core_ctx::writeback()
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)
+bool shader_core_ctx::memory_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 )
+ return true;
- std::vector<mem_access_t> &accessq = m_memory_queue.shared;
//consume port number orders from the top of the queue;
- for (int i = 0; i < m_config->gpgpu_shmem_port_per_bank; i++) {
- if (accessq.empty())
+ for( int i = 0; i < m_config->gpgpu_shmem_port_per_bank; i++ ) {
+ if (inst.accessq_empty())
break;
- unsigned current_order = accessq.back().order;
+ unsigned current_order = inst.accessq_back().order;
//consume all requests of the same order (concurrent bank requests)
- while ((not accessq.empty()) and accessq.back().order == current_order)
- accessq.pop_back();
+ while ((!inst.accessq_empty()) && inst.accessq_back().order == current_order)
+ inst.accessq_pop_back();
}
- if (not accessq.empty()) {
+ if( !inst.accessq_empty() ) {
rc_fail = BK_CONF;
fail_type = S_MEM;
m_stats->gpgpu_n_shmem_bkconflict++;
}
- return accessq.empty(); //done if empty.
+ 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,
- std::vector<mem_access_t> &accessq )
+ warp_inst_t &inst )
{
// Generic algorithm for processing a single cycle of accesses for the memory space types that go to L2 or DRAM.
@@ -1239,42 +1185,42 @@ mem_stage_stall_type shader_core_ctx::process_memory_access_queue( shader_core_c
mem_stage_stall_type hazard_cond = NO_RC_FAIL;
unsigned mem_req_count = 0; // number of requests to sent to memory this cycle
for (unsigned i = 0; i < ports_per_bank; i++) {
- if (accessq.empty())
+ if (inst.accessq_empty())
break;
- unsigned current_order = accessq.back().order;
+ unsigned current_order = inst.accessq_back().order;
// consume all requests of the same "order" but stop if we hit a structural hazard
- while ((not accessq.empty()) and accessq.back().order == current_order and hazard_cond == NO_RC_FAIL) {
- hazard_cond = (this->*cache_check)(accessq.back());
+ while ((!inst.accessq_empty()) && inst.accessq_back().order == current_order && hazard_cond == NO_RC_FAIL) {
+ hazard_cond = (this->*cache_check)(inst,inst.accessq_back());
if (hazard_cond != NO_RC_FAIL)
break; // can't complete this request this cycle.
- if (not accessq.back().cache_hit){
+ if (! inst.accessq_back().cache_hit){
if (mem_req_count < memory_send_max) {
mem_req_count++;
- hazard_cond = send_mem_request(accessq.back()); // attemp to get mshr, icnt, send;
+ hazard_cond = send_mem_request(inst,inst.accessq_back()); // attemp to get mshr, icnt, send;
}
else hazard_cond = COAL_STALL; // not really a coal stall, its a too many memory request stall;
if ( hazard_cond != NO_RC_FAIL) break; //can't complete this request this cycle.
}
- accessq.pop_back();
+ inst.accessq_pop_back();
}
}
- if (not accessq.empty() and hazard_cond == NO_RC_FAIL) {
+ if (!inst.accessq_empty() && hazard_cond == NO_RC_FAIL) {
//no resource failed so must be a bank comflict.
hazard_cond = BK_CONF;
}
return hazard_cond;
}
-bool shader_core_ctx::memory_constant_cycle( mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type)
+bool shader_core_ctx::memory_constant_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 the constant memory queue.
-
- std::vector<mem_access_t> &accessq = m_memory_queue.constant;
+ 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,
m_config->gpgpu_const_port_per_bank,
1, //memory send max per cycle
- accessq );
+ inst );
if (fail != NO_RC_FAIL){
rc_fail = fail; //keep other fails if this didn't fail.
fail_type = C_MEM;
@@ -1282,37 +1228,39 @@ bool shader_core_ctx::memory_constant_cycle( mem_stage_stall_type &rc_fail, mem_
m_stats->gpgpu_n_cmem_portconflict++; //coal stalls aren't really a bank conflict, but this maintains previous behavior.
}
}
- return accessq.empty(); //done if empty.
+ return inst.accessq_empty(); //done if empty.
}
-bool shader_core_ctx::memory_texture_cycle( mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type)
+bool shader_core_ctx::memory_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.
- std::vector<mem_access_t> &accessq = m_memory_queue.texture;
mem_stage_stall_type fail = process_memory_access_queue(&shader_core_ctx::tcache_check,
1, //how is tex memory banked?
1, //memory send max per cycle
- accessq );
+ inst );
if (fail != NO_RC_FAIL){
rc_fail = fail; //keep other fails if this didn't fail.
fail_type = T_MEM;
}
- return accessq.empty(); //done if empty.
+ return inst.accessq_empty(); //done if empty.
}
-mem_stage_stall_type shader_core_ctx::dcache_check(mem_access_t& access)
+mem_stage_stall_type shader_core_ctx::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.
- if (access.cache_checked and not access.recheck_cache)
+ if (access.cache_checked && !access.recheck_cache)
return NO_RC_FAIL;
if (!m_config->gpgpu_no_dl1 && !m_config->gpgpu_perfect_mem) {
//check cache
cache_request_status status = m_L1D->access( access.addr,
- access.iswrite,
+ inst.is_store(),
gpu_sim_cycle+gpu_tot_sim_cycle,
&access.wb_addr );
if (status == RESERVATION_FAIL) {
@@ -1321,7 +1269,7 @@ mem_stage_stall_type shader_core_ctx::dcache_check(mem_access_t& access)
}
access.cache_hit = (status == HIT); //if HIT_W_WT then still send to memory so "MISS"
if (status == MISS_W_WB) access.need_wb = true;
- if (status == WB_HIT_ON_MISS and access.iswrite)
+ if (status == WB_HIT_ON_MISS && inst.is_store())
{
//write has hit a reserved cache line
//it has writen its data into the cache line, so no need to go to memory
@@ -1333,7 +1281,7 @@ mem_stage_stall_type shader_core_ctx::dcache_check(mem_access_t& access)
// MSHR will still forward the unmasked value to its dependant reads.
// if doing stall on use, must stall this thread after this write (otherwise, inproper values may be forwarded to future reads).
}
- if (status == WB_HIT_ON_MISS and not access.iswrite) {
+ if (status == WB_HIT_ON_MISS && !inst.is_store() ) {
//read has hit on a reserved cache line,
//we need to make sure cache check happens on same cycle as a mshr merge happens, otherwise we might miss it coming back
access.recheck_cache = true;
@@ -1343,12 +1291,13 @@ mem_stage_stall_type shader_core_ctx::dcache_check(mem_access_t& access)
access.cache_hit = false;
}
- if (m_config->gpgpu_perfect_mem) access.cache_hit = true;
+ if (m_config->gpgpu_perfect_mem)
+ access.cache_hit = true;
- if (access.isatomic) {
+ if (inst.isatomic()) {
if (m_config->gpgpu_perfect_mem) {
// complete functional execution of atomic here
- m_pipeline_reg[EX_MM]->do_atomic();
+ inst.do_atomic();
} else {
// atomics always go to memory
access.cache_hit = false;
@@ -1356,63 +1305,65 @@ mem_stage_stall_type shader_core_ctx::dcache_check(mem_access_t& access)
}
if (!access.cache_hit) {
- if (access.iswrite) m_stats->L1_write_miss++;
+ if (inst.is_store()) m_stats->L1_write_miss++;
else m_stats->L1_read_miss++;
}
return NO_RC_FAIL;
}
-bool shader_core_ctx::memory_cycle( mem_stage_stall_type &stall_reason, mem_stage_access_type &access_type)
+bool shader_core_ctx::memory_cycle( warp_inst_t &inst, mem_stage_stall_type &stall_reason, mem_stage_access_type &access_type )
{
- // Process a single cycle of activity from the the global/local memory queue.
-
- std::vector<mem_access_t> &accessq = m_memory_queue.local_global;
- mem_stage_stall_type stall_cond = process_memory_access_queue(&shader_core_ctx::dcache_check, m_config->gpgpu_cache_port_per_bank, 1, accessq);
+ if( (inst.space.get_type() != global_space) &&
+ (inst.space.get_type() != local_space) &&
+ (inst.space.get_type() != param_space_local) )
+ 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);
if (stall_cond != NO_RC_FAIL) {
stall_reason = stall_cond;
- bool iswrite = accessq.back().iswrite;
- if (is_local(accessq.back().space))
+ bool iswrite = inst.is_store();
+ if (inst.space.is_local())
access_type = (iswrite)?L_MEM_ST:L_MEM_LD;
else
access_type = (iswrite)?G_MEM_ST:G_MEM_LD;
- if (stall_cond == BK_CONF or stall_cond == COAL_STALL)
+ if (stall_cond == BK_CONF || stall_cond == COAL_STALL)
m_stats->gpgpu_n_cache_bkconflict++;
}
- return accessq.empty(); //done if empty.
+ return inst.accessq_empty(); //done if empty.
}
-void shader_core_ctx::memory_queue()
+void shader_core_ctx::memory_queue( warp_inst_t &pipe_reg )
{
// Called once per warp when warp enters memory stage.
// Generates a list of memory accesses, but does not perform the memory access.
-
- if( m_pipeline_reg[EX_MM]->empty() )
+ if( pipe_reg.empty() )
return;
- m_gpu->mem_instruction_stats(m_pipeline_reg[EX_MM]);
- 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;
- case global_space: case local_space: case param_space_local: memory_global_process_warp(); break;
+ if( pipe_reg.mem_accesses_computed() )
+ 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;
case param_space_unclassified: abort(); break;
default: break; // non-memory operations
}
+ pipe_reg.set_mem_accesses_computed();
}
void shader_core_ctx::memory()
{
- if (!m_shader_memory_new_instruction_processed) {
- m_shader_memory_new_instruction_processed = true; // do once per warp instruction
- memory_queue();
- }
+ warp_inst_t &pipe_reg = *m_pipeline_reg[EX_MM];
+ memory_queue(pipe_reg);
bool done = true;
enum mem_stage_stall_type rc_fail = NO_RC_FAIL;
mem_stage_access_type type;
- done &= memory_shared_cycle(rc_fail, type);
- done &= memory_constant_cycle(rc_fail, type);
- done &= memory_texture_cycle(rc_fail, type);
- done &= memory_cycle(rc_fail, 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);
+ done &= memory_cycle(pipe_reg, rc_fail, type);
m_mem_rc = rc_fail;
if (!done) { // log stall types and return
assert(rc_fail != NO_RC_FAIL);
@@ -1420,7 +1371,7 @@ void shader_core_ctx::memory()
m_stats->gpu_stall_shd_mem_breakdown[type][rc_fail]++;
return;
}
- if( not m_pipeline_reg[MM_WB]->empty() )
+ if( !m_pipeline_reg[MM_WB]->empty() )
return; // writeback stalled
move_warp(m_pipeline_reg[MM_WB],m_pipeline_reg[EX_MM]);
}
@@ -1579,52 +1530,37 @@ 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("GT200",m_config->pipeline_model) ) {
- dump_istream_state(fout);
- fprintf(fout,"\n");
+ dump_istream_state(fout);
+ fprintf(fout,"\n");
- fprintf(fout, "IF/ID = ");
- if( !m_inst_fetch_buffer.m_valid )
- fprintf(fout,"bubble\n");
- else {
- fprintf(fout,"w%2u : pc = 0x%x, nbytes = %u\n",
- m_inst_fetch_buffer.m_warp_id,
- m_inst_fetch_buffer.m_pc,
- m_inst_fetch_buffer.m_nbytes );
- }
- fprintf(fout,"\nibuffer status:\n");
- for( unsigned i=0; i<m_config->max_warps_per_shader; i++) {
- if( !m_warp[i].ibuffer_empty() )
- m_warp[i].print_ibuffer(fout);
- }
- fprintf(fout,"\n");
- display_pdom_state(fout,mask);
+ fprintf(fout, "IF/ID = ");
+ if( !m_inst_fetch_buffer.m_valid )
+ fprintf(fout,"bubble\n");
+ else {
+ fprintf(fout,"w%2u : pc = 0x%x, nbytes = %u\n",
+ m_inst_fetch_buffer.m_warp_id,
+ m_inst_fetch_buffer.m_pc,
+ m_inst_fetch_buffer.m_nbytes );
}
+ fprintf(fout,"\nibuffer status:\n");
+ for( unsigned i=0; i<m_config->max_warps_per_shader; i++) {
+ if( !m_warp[i].ibuffer_empty() )
+ m_warp[i].print_ibuffer(fout);
+ }
+ fprintf(fout,"\n");
+ display_pdom_state(fout,mask);
m_scoreboard->printContents();
- if (!strcmp("GPGPUSIM_ORIG",m_config->pipeline_model) ) {
- if ( mask & 0x20 ) {
- fprintf(fout, "TS/IF = ");
- print_stage(TS_IF, fout, print_mem, mask);
- }
- fprintf(fout, "IF/ID = ");
- print_stage(IF_ID, fout, print_mem, mask );
- }
- if (m_config->gpgpu_operand_collector) {
- fprintf(fout,"ID/OC (SP) = ");
- print_stage(ID_OC, fout, print_mem, mask);
- fprintf(fout,"ID/OC (SFU) = ");
- print_stage(ID_OC_SFU, fout, print_mem, mask);
- m_operand_collector.dump(fout);
- }
- if (!strcmp("GT200",m_config->pipeline_model) )
- fprintf(fout, "ID/EX (SP) = ");
- 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);
- }
+ fprintf(fout,"ID/OC (SP) = ");
+ print_stage(ID_OC_SP, fout, print_mem, mask);
+ fprintf(fout,"ID/OC (SFU) = ");
+ print_stage(ID_OC_SFU, fout, print_mem, mask);
+ 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 ) {
@@ -1702,7 +1638,7 @@ void shader_core_ctx::cycle_gt200()
writeback();
memory();
execute();
- m_operand_collector.step(m_pipeline_reg[ID_OC],m_pipeline_reg[ID_OC_SFU]);
+ m_operand_collector.step(m_pipeline_reg[ID_OC_SP],m_pipeline_reg[ID_OC_SFU]);
decode_new();
fetch_new();
}
@@ -2101,8 +2037,8 @@ void mshr_entry::init( new_addr_type address, bool wr, memory_space_t space, uns
m_merged_requests =NULL;
m_iswrite = wr;
m_isinst = space==instruction_space;
- m_islocal = is_local(space);
- m_isconst = is_const(space);
+ m_islocal = space.is_local();
+ m_isconst = space.is_const();
m_istexture = space==tex_space;
m_insts.clear();
m_warp_id = warp_id;
diff --git a/src/gpgpu-sim/shader.h b/src/gpgpu-sim/shader.h
index a9e27b8..8e98749 100644
--- a/src/gpgpu-sim/shader.h
+++ b/src/gpgpu-sim/shader.h
@@ -792,84 +792,6 @@ private:
warp_set_t m_warp_at_barrier;
};
-class warp_tracker;
-class warp_tracker_pool;
-
-enum memory_pipe_t {
- NO_MEM_PATH = 0,
- SHARED_MEM_PATH,
- GLOBAL_MEM_PATH,
- TEXTURE_MEM_PATH,
- CONSTANT_MEM_PATH,
- NUM_MEM_PATHS //not a mem path
-};
-
-class mem_access_t {
-public:
- mem_access_t() : space(undefined_space)
- {
- init();
- }
- mem_access_t(address_type a, memory_space_t s, memory_pipe_t p, bool atomic, bool w, unsigned r, unsigned quarter, unsigned idx )
- {
- init();
- addr = a;
- space = s;
- mem_pipe = p;
- isatomic = atomic;
- iswrite = w;
- req_size = r;
- quarter_count[quarter]++;
- warp_indices.push_back(idx);
- }
-
- bool operator<(const mem_access_t &other) const {return (order > other.order);}//this is reverse
-
-private:
- void init()
- {
- uid=++next_access_uid;
- addr=0;
- req_size=0;
- order=0;
- _quarter_count_all=0;
- mem_pipe = NO_MEM_PATH;
- isatomic = false;
- cache_hit = false;
- cache_checked = false;
- recheck_cache = false;
- iswrite = false;
- need_wb = false;
- wb_addr = 0;
- reserved_mshr = NULL;
- }
-
-public:
-
- unsigned uid;
- address_type addr; //address of the segment to load.
- unsigned req_size; //bytes
- unsigned order; // order of accesses, based on banks.
- union{
- unsigned _quarter_count_all;
- char quarter_count[4]; //access counts to each quarter of segment, for compaction;
- };
- std::vector<unsigned> warp_indices; // warp indicies for this request.
- memory_space_t space;
- memory_pipe_t mem_pipe;
- bool isatomic;
- bool cache_hit;
- bool cache_checked;
- bool recheck_cache;
- bool iswrite;
- bool need_wb;
- address_type wb_addr; // writeback address (if necessary).
- mshr_entry* reserved_mshr;
-
-private:
- static unsigned next_access_uid;
-};
-
class mshr_lookup {
public:
mshr_lookup( const struct shader_core_config *config ) { m_shader_config = config; }
@@ -900,7 +822,7 @@ public:
//return queue pop; (includes texture pipeline return)
void pop_return_head();
- mshr_entry* add_mshr(mem_access_t &access, warp_inst_t* warp);
+ mshr_entry* add_mshr(mem_access_t &access, warp_inst_t* inst);
void mshr_return_from_mem(mshr_entry *mshr);
unsigned get_max_mshr_used() const {return m_max_mshr_used;}
void print(FILE* fp, class shader_core_ctx* shader,unsigned mask);
@@ -927,13 +849,6 @@ private:
mshr_lookup m_mshr_lookup;
};
-struct shader_queues_t {
- std::vector<mem_access_t> shared;
- std::vector<mem_access_t> constant;
- std::vector<mem_access_t> texture;
- std::vector<mem_access_t> local_global;
-};
-
struct insn_latency_info {
unsigned pc;
unsigned long latency;
@@ -956,20 +871,6 @@ struct ifetch_buffer_t {
unsigned m_warp_id;
};
-// Struct for storing warp information in fixeddelay_queue
-struct fixeddelay_queue_warp_t {
- unsigned long long ready_cycle;
- std::vector<int> tids; // list of tid's in this warp (to unlock)
- inst_t inst;
-};
-
-struct fixeddelay_queue_warp_comp {
- inline bool operator()(const fixeddelay_queue_warp_t& left,const fixeddelay_queue_warp_t& right) const
- {
- return left.ready_cycle < right.ready_cycle;
- }
-};
-
typedef address_type (*tag_func_t)(address_type add, unsigned line_size);
class shader_core_ctx : public core_t
@@ -1050,27 +951,27 @@ private:
void execute_pipe( unsigned pipeline, unsigned next_stage );
void memory(); // advance memory pipeline stage
- void memory_queue();
- void memory_shared_process_warp();
- void memory_const_process_warp();
- void memory_texture_process_warp();
- void memory_global_process_warp();
- bool memory_shared_cycle( mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type);
- bool memory_constant_cycle( mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type);
- bool memory_texture_cycle( mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type);
- bool memory_cycle( mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type);
+ void memory_queue(warp_inst_t &pipe_reg);
+ void memory_shared_process_warp(warp_inst_t &inst);
+ void memory_const_process_warp(warp_inst_t &inst);
+ void memory_texture_process_warp(warp_inst_t &inst);
+ void memory_global_process_warp(warp_inst_t &inst);
+ bool memory_shared_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type);
+ bool memory_constant_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type);
+ bool memory_texture_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type);
+ bool memory_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type);
address_type translate_local_memaddr(address_type localaddr, int tid, unsigned num_shader );
- mem_stage_stall_type ccache_check(mem_access_t& access){ return NO_RC_FAIL;}
- mem_stage_stall_type tcache_check(mem_access_t& access){ return NO_RC_FAIL;}
- mem_stage_stall_type dcache_check(mem_access_t& access);
+ mem_stage_stall_type ccache_check(warp_inst_t &inst, mem_access_t& access){ return NO_RC_FAIL;}
+ mem_stage_stall_type tcache_check(warp_inst_t &inst, mem_access_t& access){ return NO_RC_FAIL;}
+ mem_stage_stall_type dcache_check(warp_inst_t &inst, mem_access_t& access);
- typedef mem_stage_stall_type (shader_core_ctx::*cache_check_t)(mem_access_t&);
+ typedef mem_stage_stall_type (shader_core_ctx::*cache_check_t)(warp_inst_t &,mem_access_t&);
mem_stage_stall_type process_memory_access_queue( shader_core_ctx::cache_check_t cache_check,
unsigned ports_per_bank,
unsigned memory_send_max,
- std::vector<mem_access_t> &accessq );
+ warp_inst_t &inst );
typedef int (shader_core_ctx::*bank_func_t)(address_type add, unsigned line_size);
@@ -1080,12 +981,11 @@ private:
void get_memory_access_list( bank_func_t bank_func,
tag_func_t tag_func,
- memory_pipe_t mem_pipe,
unsigned warp_parts,
unsigned line_size,
bool limit_broadcast,
- std::vector<mem_access_t> &accessq );
- mem_stage_stall_type send_mem_request(mem_access_t &access);
+ warp_inst_t &inst );
+ mem_stage_stall_type send_mem_request(warp_inst_t &inst, mem_access_t &access);
void writeback();
@@ -1129,7 +1029,6 @@ private:
Scoreboard *m_scoreboard;
opndcoll_rfu_t m_operand_collector;
mshr_shader_unit *m_mshr_unit;
- shader_queues_t m_memory_queue;
// fetch
int m_last_warp_fetched;
@@ -1140,33 +1039,18 @@ private:
cache_t *m_L1T; // texture cache
cache_t *m_L1C; // constant cache
- bool m_shader_memory_new_instruction_processed;
enum mem_stage_stall_type m_mem_rc;
};
-void init_mshr_pool();
-mshr_entry* alloc_mshr_entry();
-void free_mshr_entry( mshr_entry * );
-
-// print out the accumulative statistics for shaders (those that are not local to one shader)
-void shader_print_runtime_stat( FILE *fout );
-void shader_print_l1_miss_stat( FILE *fout );
-
-#define TS_IF 0
-#define IF_ID 1
-#define ID_RR 2
-#define ID_EX 3
-#define RR_EX 3
-#define EX_MM 4
-#define MM_WB 5
-#define WB_RT 6
-#define ID_OC 7
-#define ID_OC_SFU 8
-#define OC_EX_SFU 9
-#define N_PIPELINE_STAGES 10
-
-extern unsigned int *shader_cycle_distro;
-
-int is_store ( const inst_t &op );
+enum pipeline_stage_name_t {
+ ID_OC_SP=0,
+ ID_OC_SFU,
+ OC_EX_SP,
+ OC_EX_SFU,
+ EX_MM,
+ MM_WB,
+ WB_RT,
+ N_PIPELINE_STAGES
+};
#endif /* SHADER_H */