summaryrefslogtreecommitdiff
path: root/src/gpgpu-sim
diff options
context:
space:
mode:
Diffstat (limited to 'src/gpgpu-sim')
-rw-r--r--src/gpgpu-sim/gpu-sim.cc12
-rw-r--r--src/gpgpu-sim/shader.cc194
-rw-r--r--src/gpgpu-sim/shader.h387
3 files changed, 574 insertions, 19 deletions
diff --git a/src/gpgpu-sim/gpu-sim.cc b/src/gpgpu-sim/gpu-sim.cc
index cda7517..5615801 100644
--- a/src/gpgpu-sim/gpu-sim.cc
+++ b/src/gpgpu-sim/gpu-sim.cc
@@ -264,6 +264,10 @@ extern int gpgpu_cache_port_per_bank;
extern int gpgpu_const_port_per_bank;
extern int gpgpu_shmem_pipe_speedup;
extern int gpgpu_reg_bank_conflict_model;
+extern unsigned int gpgpu_num_reg_banks;
+extern int gpgpu_reg_bank_use_warp_id;
+extern int gpgpu_operand_collector;
+extern int gpgpu_operand_collector_num_units;
extern int gpgpu_num_reg_banks;
extern unsigned int gpu_max_cta_per_shader;
@@ -566,7 +570,13 @@ void gpu_reg_options(option_parser_t opp)
option_parser_register(opp, "-gpgpu_num_reg_banks", OPT_INT32, &gpgpu_num_reg_banks,
"Number of register banks (default = 8)",
"8");
- option_parser_register(opp, "-gpgpu_coalesce_arch", OPT_INT32, &gpgpu_coalesce_arch,
+ option_parser_register(opp, "-gpgpu_operand_collector", OPT_BOOL, &gpgpu_operand_collector,
+ "Enable operand collector model (default = off)",
+ "0");
+ option_parser_register(opp, "-gpgpu_operand_collector_num_units", OPT_INT32, &gpgpu_operand_collector_num_units,
+ "number of collecture units (default = 4)",
+ "4");
+ option_parser_register(opp, "-gpgpu_coalesce_arch", OPT_INT32, &gpgpu_coalesce_arch,
"Coalescing arch (default = 13, anything else is off for now)",
"13");
addrdec_setoption(opp);
diff --git a/src/gpgpu-sim/shader.cc b/src/gpgpu-sim/shader.cc
index 7a31d15..8ebf655 100644
--- a/src/gpgpu-sim/shader.cc
+++ b/src/gpgpu-sim/shader.cc
@@ -213,6 +213,8 @@ unsigned int gpu_padded_cta_size = 32;
int gpgpu_local_mem_map = 1;
+int gpgpu_operand_collector_num_units = 4;
+
extern int pdom_sched_type;
extern int n_pdom_sc_orig_stat;
extern int n_pdom_sc_single_stat;
@@ -518,11 +520,46 @@ inst_t create_nop_inst() // just because C++ does not have designated initialize
nop_inst.id_cycle = 0;
nop_inst.ex_cycle = 0;
nop_inst.mm_cycle = 0;
+ nop_inst.space = 0;
return nop_inst;
}
static inst_t nop_inst = create_nop_inst();
+inst_t *first_valid_thread( inst_t *warp )
+{
+ for(unsigned t=0; t < ::warp_size; t++ )
+ if( warp[t].hw_thread_id != -1 )
+ return warp+t;
+ return NULL;
+}
+
+void move_warp( inst_t *dst, inst_t *src )
+{
+ memcpy(dst,src,::warp_size * sizeof(inst_t));
+ for( unsigned t=0; t < ::warp_size; t++)
+ src[t] = nop_inst;
+}
+
+bool pipeline_regster_empty( inst_t *reg )
+{
+ return first_valid_thread(reg) == NULL;
+}
+
+std::list<unsigned> get_regs_written( inst_t *warp )
+{
+ std::list<unsigned> result;
+ inst_t *fvi = first_valid_thread(warp);
+ if( fvi == NULL )
+ return result;
+ for( unsigned op=0; op < 4; op++ ) {
+ int reg_num = fvi->arch_reg[op]; // this math needs to match that used in function_info::ptx_decode_inst
+ if( reg_num >= 0 ) // valid register
+ result.push_back(reg_num);
+ }
+ return result;
+}
+
int log2i(int n) {
int lg;
lg = -1;
@@ -597,6 +634,7 @@ shader_core_ctx_t* shader_create( const char *name, int sid,
}
}
}
+ sc->last_cta_finished = 0;
sc->n_threads = n_threads;
sc->thread = (thread_ctx_t*) calloc(sizeof(thread_ctx_t), n_threads);
sc->not_completed = 0;
@@ -1740,6 +1778,19 @@ reg_bank_access g_reg_bank_access[MAX_REG_BANKS];
static const struct reg_bank_access empty_reg_bank_access;
unsigned int gpu_reg_bank_conflict_stalls = 0;
+
+void shader_opnd_collect_read(shader_core_ctx_t* shader)
+{
+ const int prevstage = ID_OC;
+ const int nextstage = shader->using_rrstage ? ID_RR : ID_EX;
+ shader->m_opndcoll_new.step(shader->pipeline_reg[prevstage],shader->pipeline_reg[nextstage]);
+}
+
+void shader_opnd_collect_write(shader_core_ctx_t* shader)
+{
+ shader->m_opndcoll_new.writeback(shader->pipeline_reg[WB_RT]);
+}
+
/////////////////////////////////////////////////////////////////////////////////////////
void shader_decode( shader_core_ctx_t *shader,
@@ -3283,30 +3334,28 @@ void shader_print_l1_miss_stat( FILE *fout ) {
}
-void shader_print_stage(shader_core_ctx_t *shader, unsigned int stage,
- FILE *fout, int stage_width, int print_mem, int mask )
+void shader_print_warp( const shader_core_ctx_t *shader, inst_t *warp, FILE *fout, int stage_width, int print_mem, int mask )
{
int i, j, warp_id = -1;
-
for (i=0; i<stage_width; i++) {
- if (shader->pipeline_reg[stage][i].hw_thread_id > -1) {
- warp_id = shader->pipeline_reg[stage][i].hw_thread_id / warp_size;
+ if (warp[i].hw_thread_id > -1) {
+ warp_id = warp[i].hw_thread_id / warp_size;
break;
}
}
i = (i>=stage_width)? 0 : i;
- fprintf(fout,"0x%04x ", shader->pipeline_reg[stage][i].pc );
+ fprintf(fout,"0x%04x ", warp[i].pc );
if( mask & 2 ) {
fprintf(fout, "(" );
for (j=0; j<stage_width; j++)
- fprintf(fout, "%03d ", shader->pipeline_reg[stage][j].hw_thread_id);
+ fprintf(fout, "%03d ", warp[j].hw_thread_id);
fprintf(fout, "): ");
} else {
fprintf(fout, "w%02d[", warp_id);
for (j=0; j<stage_width; j++)
- fprintf(fout, "%c", ((shader->pipeline_reg[stage][j].hw_thread_id != -1)?'1':'0') );
+ fprintf(fout, "%c", ((warp[j].hw_thread_id != -1)?'1':'0') );
fprintf(fout, "]: ");
}
@@ -3319,16 +3368,23 @@ void shader_print_stage(shader_core_ctx_t *shader, unsigned int stage,
}
}
- ptx_print_insn( shader->pipeline_reg[stage][i].pc, fout );
+ ptx_print_insn( warp[i].pc, fout );
if( mask & 0x10 ) {
- if ( (shader->pipeline_reg[stage][i].op == STORE_OP ||
- shader->pipeline_reg[stage][i].op == LOAD_OP) && print_mem )
- fprintf(fout, " mem: 0x%016llx", shader->pipeline_reg[stage][i].memreqaddr);
+ if ( (warp[i].op == STORE_OP ||
+ warp[i].op == LOAD_OP) && print_mem )
+ fprintf(fout, " mem: 0x%016llx", warp[i].memreqaddr);
}
fprintf(fout, "\n");
}
+void shader_print_stage(shader_core_ctx_t *shader, unsigned int stage,
+ FILE *fout, int stage_width, int print_mem, int mask )
+{
+ inst_t *warp = shader->pipeline_reg[stage];
+ shader_print_warp(shader,warp,fout,stage_width,print_mem,mask);
+}
+
void shader_print_pre_mem_stages(shader_core_ctx_t *shader, FILE *fout, int print_mem, int mask )
{
int i, j;
@@ -3451,6 +3507,9 @@ void shader_display_pipeline(shader_core_ctx_t *shader, FILE *fout, int print_me
fprintf(fout, "IF/ID = ");
shader_print_stage(shader, IF_ID, fout, pipe_simd_width, print_mem, mask );
+ if (gpgpu_operand_collector)
+ shader->m_opndcoll_new.dump(fout);
+
if (shader->using_rrstage) {
fprintf(fout, "ID/RR = ");
shader_print_stage(shader, ID_RR, fout, pipe_simd_width, print_mem, mask);
@@ -3561,6 +3620,9 @@ void shader_cycle( shader_core_ctx_t *shader,
int grid_num )
{
+ if (gpgpu_operand_collector)
+ shader_opnd_collect_write(shader);
+
// last pipeline stage
shader_writeback(shader, shader_number, grid_num);
@@ -3580,6 +3642,9 @@ void shader_cycle( shader_core_ctx_t *shader,
shader_preexecute (shader, shader_number);
}
+ if (gpgpu_operand_collector)
+ shader_opnd_collect_read(shader);
+
shader_decode (shader, shader_number, grid_num);
shader_fetch (shader, shader_number, grid_num);
@@ -3672,6 +3737,109 @@ void shader_cache_flush(shader_core_ctx_t* sc)
}
}
+static int *_inmatch;
+static int *_outmatch;
+static int **_request;
+
+// modifiers
+std::list<opndcoll_rfu_t::op_t> opndcoll_rfu_t::arbiter_t::allocate_reads()
+{
+ std::list<op_t> result; // a list of registers that (a) are in different register banks, (b) do not go to the same operand collector
+
+ int input;
+ int output;
+ int _inputs = m_num_banks;
+ int _outputs = m_num_collectors;
+ int _square = ( _inputs > _outputs ) ? _inputs : _outputs;
+ int _pri = (int)m_last_cu;
+
+ if( _inmatch == NULL ) {
+ _inmatch = new int[ _inputs ];
+ _outmatch = new int[ _outputs ];
+ _request = new int*[ _inputs ];
+ for(int i=0; i<_outputs;i++)
+ _request[i] = new int[_outputs];
+ }
+
+ // Clear matching
+ for ( int i = 0; i < _inputs; ++i )
+ _inmatch[i] = -1;
+ for ( int j = 0; j < _outputs; ++j )
+ _outmatch[j] = -1;
+
+ for( unsigned i=0; i<m_num_banks; i++) {
+ for( unsigned j=0; j<m_num_collectors; j++)
+ _request[i][j] = 0;
+ if( !m_queue[i].empty() ) {
+ const op_t &op = m_queue[i].front();
+ int oc_id = op.get_oc_id();
+ _request[i][oc_id] = 1;
+ }
+ if( m_allocated_bank[i].is_write() )
+ _inmatch[i] = 0; // write gets priority
+ }
+
+ ///// wavefront allocator from booksim... --->
+
+ // Loop through diagonals of request matrix
+
+ for ( int p = 0; p < _square; ++p ) {
+ output = ( _pri + p ) % _square;
+
+ // Step through the current diagonal
+ for ( input = 0; input < _inputs; ++input ) {
+ if ( ( output < _outputs ) &&
+ ( _inmatch[input] == -1 ) &&
+ ( _outmatch[output] == -1 ) &&
+ ( _request[input][output]/*.label != -1*/ ) ) {
+ // Grant!
+ _inmatch[input] = output;
+ _outmatch[output] = input;
+ }
+
+ output = ( output + 1 ) % _square;
+ }
+ }
+
+ // Round-robin the priority diagonal
+ _pri = ( _pri + 1 ) % _square;
+
+ /// <--- end code from booksim
+
+ m_last_cu = _pri;
+ for( unsigned i=0; i < m_num_banks; i++ ) {
+ if( _inmatch[i] != -1 ) {
+ if( !m_allocated_bank[i].is_write() ) {
+ unsigned bank = (unsigned)i;
+ op_t &op = m_queue[bank].front();
+ result.push_back(op);
+ m_queue[bank].pop_front();
+ }
+ }
+ }
+
+
+/*
+ for( unsigned c=0; c < m_num_collectors; c++ ) {
+ unsigned cu = (m_last_cu+c+1)%m_num_collectors;
+ for( unsigned b=0; b < m_num_banks; b++ ) {
+ unsigned bank = (m_allocator_rr_head[cu]+b+1)%m_num_banks;
+ if( (!m_queue[bank].empty()) && m_allocated_bank[bank].is_free() ) {
+ op_t &op = m_queue[bank].front();
+ result.push_back(op);
+ m_allocated_bank[bank].alloc_read(op);
+ m_queue[bank].pop_front();
+ m_allocator_rr_head[cu] = bank;
+ m_last_cu = cu;
+ break; // skip to next collector unit
+ }
+ }
+ }
+*/
+ 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;
@@ -3777,7 +3945,7 @@ void barrier_set_t::dump() const
}
shader_core_ctx::shader_core_ctx( unsigned max_warps_per_cta, unsigned max_cta_per_core )
- : m_barriers( max_warps_per_cta, max_cta_per_core )
+ : m_barriers( max_warps_per_cta, max_cta_per_core ), m_opndcoll_new( gpgpu_operand_collector_num_units, gpgpu_num_reg_banks, this )
{
}
diff --git a/src/gpgpu-sim/shader.h b/src/gpgpu-sim/shader.h
index f67e8fd..702046d 100644
--- a/src/gpgpu-sim/shader.h
+++ b/src/gpgpu-sim/shader.h
@@ -70,6 +70,7 @@
#include <limits.h>
#include <assert.h>
#include <map>
+#include <list>
#include "../cuda-sim/ptx.tab.h"
#include "../cuda-sim/dram_callback.h"
@@ -133,7 +134,7 @@ typedef struct {
unsigned in[4];
unsigned char is_vectorin;
unsigned char is_vectorout;
- int arch_reg[8]; // register number for bank conflict evaluation
+ int arch_reg[MAX_REG_OPERANDS]; // register number for bank conflict evaluation
unsigned data_size; // what is the size of the word being operated on?
int reg_bank_access_pending;
@@ -312,6 +313,380 @@ typedef unsigned char (*fq_has_buffer_t)(unsigned long long int addr, int bsize,
const unsigned WARP_PER_CTA_MAX = 32;
typedef std::bitset<WARP_PER_CTA_MAX> warp_set_t;
+inst_t *first_valid_thread( inst_t *warp );
+void move_warp( inst_t *dst, inst_t *src );
+bool pipeline_regster_empty( inst_t *reg );
+std::list<unsigned> get_regs_written( inst_t *warp );
+int register_bank(int regnum, int tid);
+class shader_core_ctx;
+void shader_print_warp( const shader_core_ctx *shader, inst_t *warp, FILE *fout, int stage_width, int print_mem, int mask ) ;
+
+class opndcoll_rfu_t{ // operand collector based register file unit
+public:
+ // constructors
+ opndcoll_rfu_t( unsigned num_collectors, unsigned num_banks, const shader_core_ctx *shader )
+ : m_arbiter(num_collectors,num_banks)
+ {
+ m_num_collectors=num_collectors;
+ m_num_banks = num_banks;
+ m_cu = new collector_unit_t[num_collectors];
+ m_last_cu=0;
+ m_shader=shader;
+ for(unsigned c=0; c<num_collectors; c++) {
+ m_cu[c].set_cuid(c);
+ m_free_cu.push_back(&m_cu[c]);
+ }
+ }
+
+ // modifiers
+ void writeback( inst_t *warp )
+ {
+ // prefer not to stall writeback
+ inst_t *fvt=first_valid_thread(warp);
+ if (!fvt) return;
+ unsigned tid = fvt->hw_thread_id;
+ std::list<unsigned> regs = get_regs_written(fvt);
+ std::list<unsigned>::iterator r;
+ for( r=regs.begin(); r!=regs.end();r++ ) {
+ unsigned reg = *r;
+ unsigned bank = register_bank(reg,tid);
+ m_arbiter.allocate_bank_for_write(bank,op_t(fvt,reg));
+ }
+ }
+
+ void step( inst_t *id_oc_reg, inst_t *oc_ex_reg )
+ {
+ dispatch_ready_cu(oc_ex_reg);
+ allocate_reads();
+ allocate_cu(id_oc_reg);
+ process_banks();
+ }
+
+ void dump( FILE *fp ) const
+ {
+ fprintf(fp,"\n");
+ fprintf(fp,"Operand Collector State:\n");
+ for( unsigned n=0; n < m_num_collectors; n++ ) {
+ fprintf(fp," CU-%u: ", n);
+ m_cu[n].dump(fp,m_shader);
+ }
+ m_arbiter.dump(fp);
+ }
+
+private:
+
+ void process_banks()
+ {
+ m_arbiter.reset_alloction();
+ }
+
+ void dispatch_ready_cu( inst_t *oc_ex_reg )
+ {
+ if( !pipeline_regster_empty(oc_ex_reg) )
+ return;
+ for( unsigned n=0; n < m_num_collectors; n++ ) {
+ unsigned c=(m_last_cu+n+1)%m_num_collectors;
+ if( m_cu[c].ready() ) {
+ m_cu[c].dispatch(oc_ex_reg);
+ m_free_cu.push_back(&m_cu[c]);
+ m_last_cu=c;
+ break;
+ }
+ }
+ }
+
+ void allocate_cu( inst_t *id_oc_reg )
+ {
+ inst_t *fvi = first_valid_thread(id_oc_reg);
+ if( fvi && !m_free_cu.empty() ) {
+ collector_unit_t *cu = m_free_cu.back();
+ m_free_cu.pop_back();
+ cu->allocate(id_oc_reg);
+ m_arbiter.add_read_requests(cu);
+ }
+ }
+
+ void allocate_reads()
+ {
+ // process read requests that do not have conflicts
+ std::list<op_t> allocated = m_arbiter.allocate_reads();
+ std::map<unsigned,op_t> read_ops;
+ 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_arbiter.allocate_for_read(bank,rr);
+ read_ops[bank] = rr;
+ }
+ std::map<unsigned,op_t>::iterator r;
+ for(r=read_ops.begin();r!=read_ops.end();++r ) {
+ op_t &op = r->second;
+ unsigned cu = op.get_oc_id();
+ unsigned operand = op.get_operand();
+ m_cu[cu].collect_operand(operand);
+ }
+ }
+
+ // types
+
+ class collector_unit_t;
+
+ class op_t {
+ public:
+
+ op_t() { m_valid = false; }
+ op_t( collector_unit_t *cu, unsigned op, unsigned reg )
+ {
+ m_valid = true;
+ m_fvi=NULL;
+ m_cu = cu;
+ m_operand = op;
+ m_register = reg;
+ m_tid = cu->get_tid();
+ m_bank = register_bank(reg,m_tid);
+ }
+ op_t( inst_t *fvi, unsigned reg )
+ {
+ m_fvi=fvi;
+ m_register=reg;
+ m_cu=NULL;
+ m_operand = -1;
+ m_tid = fvi->hw_thread_id;
+ m_bank = register_bank(reg,m_tid);
+ }
+
+ // accessors
+ bool valid() const { return m_valid; }
+ unsigned get_reg() const
+ {
+ assert( m_valid );
+ return m_register;
+ }
+ unsigned get_oc_id() const { return m_cu->get_id(); }
+ unsigned get_tid() const { return m_tid; }
+ unsigned get_bank() const { return m_bank; }
+ unsigned get_operand() const { return m_operand; }
+ void dump(FILE *fp) const
+ {
+ if(m_cu)
+ fprintf(fp," <R%u, CU:%u, w:%02u> ", m_register,m_cu->get_id(),m_cu->get_warp_id());
+ else if( m_fvi )
+ fprintf(fp," <R%u, w:%02u> ", m_register,m_tid/::warp_size);
+ }
+ std::string get_reg_string() const
+ {
+ char buffer[64];
+ snprintf(buffer,64,"R%u", m_register);
+ return std::string(buffer);
+ }
+
+ // modifiers
+ void reset() { m_valid = false; }
+ private:
+ bool m_valid;
+ collector_unit_t *m_cu;
+ inst_t *m_fvi;
+ unsigned m_operand; // operand offset in instruction. e.g., add r1,r2,r3; r2 is oprd 0, r3 is 1 (r1 is dst)
+ unsigned m_register;
+ unsigned m_bank;
+ unsigned m_tid;
+ };
+
+ enum alloc_t {
+ NO_ALLOC,
+ READ_ALLOC,
+ WRITE_ALLOC,
+ };
+
+ class allocation_t {
+ public:
+ allocation_t() { m_allocation = NO_ALLOC; }
+ bool is_read() const { return m_allocation==READ_ALLOC; }
+ bool is_write() const {return m_allocation==WRITE_ALLOC; }
+ bool is_free() const {return m_allocation==NO_ALLOC; }
+ void dump(FILE *fp) const {
+ if( m_allocation == NO_ALLOC ) { fprintf(fp,"<free>"); }
+ else if( m_allocation == READ_ALLOC ) { fprintf(fp,"rd: "); m_op.dump(fp); }
+ else if( m_allocation == WRITE_ALLOC ) { fprintf(fp,"wr: "); m_op.dump(fp); }
+ fprintf(fp,"\n");
+ }
+ void alloc_read( const op_t &op ) { assert(is_free()); m_allocation=READ_ALLOC; m_op=op; }
+ void alloc_write( const op_t &op ) { assert(is_free()); m_allocation=WRITE_ALLOC; m_op=op; }
+ void reset() { m_allocation = NO_ALLOC; }
+ private:
+ enum alloc_t m_allocation;
+ op_t m_op;
+ };
+
+ class arbiter_t {
+ public:
+ // constructors
+ arbiter_t( unsigned num_cu, unsigned num_banks )
+ {
+ m_num_collectors = num_cu;
+ m_num_banks = num_banks;
+ m_queue = new std::list<op_t>[num_banks];
+ m_allocated_bank = new allocation_t[num_banks];
+ m_allocator_rr_head = new unsigned[num_cu];
+ for( unsigned n=0; n<num_cu;n++ )
+ m_allocator_rr_head[n] = n%num_banks;
+ reset_alloction();
+ }
+
+ // accessors
+ void dump(FILE *fp) const
+ {
+ fprintf(fp,"\n");
+ fprintf(fp," Arbiter State:\n");
+ fprintf(fp," requests:\n");
+ for( unsigned b=0; b<m_num_banks; b++ ) {
+ fprintf(fp," bank %u : ", b );
+ std::list<op_t>::const_iterator o = m_queue[b].begin();
+ for(; o != m_queue[b].end(); o++ ) {
+ o->dump(fp);
+ }
+ fprintf(fp,"\n");
+ }
+ fprintf(fp," grants:\n");
+ for(unsigned b=0;b<m_num_banks;b++) {
+ fprintf(fp," bank %u : ", b );
+ m_allocated_bank[b].dump(fp);
+ }
+ fprintf(fp,"\n");
+ }
+
+ // modifiers
+ std::list<op_t> allocate_reads();
+
+ void add_read_requests( collector_unit_t *cu )
+ {
+ const op_t *src = cu->get_operands();
+ for( unsigned i=0; i<MAX_REG_OPERANDS; i++) {
+ const op_t &op = src[i];
+ if( op.valid() ) {
+ unsigned bank = op.get_bank();
+ m_queue[bank].push_back(op);
+ }
+ }
+ }
+ void allocate_bank_for_write( unsigned bank, const op_t &op )
+ {
+ m_allocated_bank[bank].alloc_write(op);
+ }
+ void allocate_for_read( unsigned bank, const op_t &op )
+ {
+ m_allocated_bank[bank].alloc_read(op);
+ }
+ void reset_alloction()
+ {
+ for( unsigned b=0; b < m_num_banks; b++ )
+ m_allocated_bank[b].reset();
+ }
+
+ private:
+ unsigned m_num_banks;
+ unsigned m_num_collectors;
+
+ allocation_t *m_allocated_bank; // bank # -> register that wins
+ std::list<op_t> *m_queue;
+
+ unsigned *m_allocator_rr_head; // cu # -> next bank to check for request (rr-arb)
+ unsigned m_last_cu; // first cu to check while arb-ing banks (rr)
+ };
+
+ class collector_unit_t {
+ public:
+ // constructors
+ collector_unit_t()
+ {
+ m_free = true;
+ m_warp = (inst_t*)calloc(sizeof(inst_t),::warp_size);
+ m_src_op = new op_t[MAX_REG_OPERANDS];
+ m_not_ready.reset();
+ m_tid = -1;
+ m_warp_id = -1;
+ }
+ // accessors
+ bool ready() const { return (!m_free) && m_not_ready.none(); }
+ const op_t *get_operands() const { return m_src_op; }
+ void dump(FILE *fp, const shader_core_ctx *shader ) const
+ {
+ if( m_free ) {
+ fprintf(fp," <free>\n");
+ } else {
+ shader_print_warp(shader,m_warp,fp,::warp_size,0,0);
+ for( unsigned i=0; i < MAX_REG_OPERANDS; i++ ) {
+ if( m_not_ready.test(i) ) {
+ std::string r = m_src_op[i].get_reg_string();
+ fprintf(fp," '%s' not ready\n", r.c_str() );
+ }
+ }
+ }
+ }
+
+ unsigned get_tid() const { return m_tid; } // returns hw id of first valid instruction
+ unsigned get_warp_id() const { return m_warp_id; }
+ unsigned get_id() const { return m_cuid; } // returns CU hw id
+
+ // modifiers
+ void set_cuid(unsigned n) { m_cuid=n; }
+ void allocate( inst_t *pipeline_reg )
+ {
+ assert(m_free);
+ assert(m_not_ready.none());
+ m_free = false;
+ inst_t *fvi = first_valid_thread(pipeline_reg);
+ if( fvi ) {
+ m_tid = fvi->hw_thread_id;
+ m_warp_id = m_tid/::warp_size;
+ 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
+ if( reg_num >= 0 ) { // valid register
+ m_src_op[op] = op_t( this, op, reg_num );
+ m_not_ready.set(op);
+ } else
+ m_src_op[op] = op_t();
+ }
+ move_warp(m_warp,pipeline_reg);
+ }
+ }
+
+ void collect_operand( unsigned op )
+ {
+ m_not_ready.reset(op);
+ }
+
+ void dispatch( inst_t *pipeline_reg )
+ {
+ assert( m_not_ready.none() );
+ move_warp(pipeline_reg,m_warp);
+ m_free=true;
+ for( unsigned i=0; i<MAX_REG_OPERANDS;i++)
+ m_src_op[i].reset();
+ }
+
+ private:
+ bool m_free;
+ unsigned m_tid;
+ unsigned m_cuid; // collector unit hw id
+ unsigned m_warp_id;
+ inst_t *m_warp;
+ op_t *m_src_op;
+ std::bitset<MAX_REG_OPERANDS> m_not_ready;
+ };
+
+ // data members
+
+ unsigned m_num_collectors;
+ unsigned m_num_banks;
+ collector_unit_t *m_cu;
+ unsigned m_last_cu; // dispatch ready cu's rr
+ arbiter_t m_arbiter;
+ std::list<collector_unit_t*> m_free_cu;
+ const shader_core_ctx *m_shader;
+};
+
class barrier_set_t {
public:
barrier_set_t( unsigned max_warps_per_core, unsigned max_cta_per_core );
@@ -350,10 +725,9 @@ private:
class mshr_shader_unit;
-extern unsigned int warp_size;
-
-typedef struct shader_core_ctx : public core_t
+class shader_core_ctx : public core_t
{
+public:
shader_core_ctx( unsigned max_warps_per_cta, unsigned max_cta_per_core );
virtual void set_at_barrier( unsigned cta_id, unsigned warp_id );
@@ -390,6 +764,7 @@ typedef struct shader_core_ctx : public core_t
// see below for definition of pipeline stages
inst_t** pipeline_reg;
inst_t** pre_mem_pipeline;
+ opndcoll_rfu_t m_opndcoll_new;
int warp_part2issue; // which part of warp to issue to pipeline
int new_warp_TS; // new warp at TS pipeline register
@@ -447,7 +822,9 @@ typedef struct shader_core_ctx : public core_t
unsigned int n_cta; //Limit on number of concurrent CTAs in shader core
mshr_shader_unit *mshr_unit;
-} shader_core_ctx_t;
+};
+
+typedef shader_core_ctx shader_core_ctx_t;
shader_core_ctx_t* shader_create( const char *name, int sid, unsigned int n_threads,