aboutsummaryrefslogtreecommitdiff
path: root/src/cuda-sim/instructions.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/cuda-sim/instructions.cc')
-rw-r--r--src/cuda-sim/instructions.cc238
1 files changed, 238 insertions, 0 deletions
diff --git a/src/cuda-sim/instructions.cc b/src/cuda-sim/instructions.cc
index 011c285..159fd4c 100644
--- a/src/cuda-sim/instructions.cc
+++ b/src/cuda-sim/instructions.cc
@@ -135,6 +135,8 @@ ptx_reg_t ptx_thread_info::get_operand_value( const operand_info &op, operand_in
result.u64 = sym->get_address() + op.get_addr_offset();
} else if ( op.is_shared() ) {
result.u64 = op.get_symbol()->get_address() + op.get_addr_offset();
+ } else if ( op.is_sstarr() ) {
+ result.u64 = op.get_symbol()->get_address() + op.get_addr_offset();
} else {
const char *name = op.name().c_str();
printf("GPGPU-Sim PTX: ERROR ** get_operand_value : unknown memory operand type for %s\n", name );
@@ -147,6 +149,8 @@ ptx_reg_t ptx_thread_info::get_operand_value( const operand_info &op, operand_in
result.u64 = op.get_symbol()->get_address();
} else if ( op.is_shared() ) {
result.u64 = op.get_symbol()->get_address();
+ } else if ( op.is_sstarr() ) {
+ result.u64 = op.get_symbol()->get_address();
} else if ( op.is_const() ) {
result.u64 = op.get_symbol()->get_address();
} else if ( op.is_global() ) {
@@ -1459,6 +1463,157 @@ void breakaddr_impl( const ptx_instruction *pI, ptx_thread_info *thread )
void brev_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
void brkpt_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
+unsigned trunc(unsigned num, unsigned precision) {
+ int mask = 1, latest_one = -1;
+ unsigned data = num;
+ for (unsigned j = 0; j < sizeof(unsigned)*8; j++) {
+ int bit = data & mask;
+ if (bit == 1) latest_one = j;
+ data >>= 1;
+ }
+ if (latest_one >= precision) {
+ // round_up is 1 if the most significant truncated digit is a 1, otherwise it is 0
+ //int round_up = (num & (1 << (latest_one-precision))) >> (latest_one-precision);
+ //unsigned shifted_output = num >> (latest_one-precision+1);
+ // if shifted_output is a number like 1111, don't round up
+ //if (shifted_output == (pow(2,precision)-1)) round_up = 0;
+ //num = shifted_output + round_up;
+ num >>= (latest_one-precision+1);
+ }
+ return num;
+}
+
+void bsmad_impl( const ptx_instruction *pI, core_t *core, warp_inst_t inst )
+{
+ // operands:
+ // 0 = output
+ // 1 = input precision
+ // 2 = output precision
+ // 3 = buffer0
+ // 4 = buffer1
+ // 5 = buffer2
+ // 6 = buffer3
+ // 7 = synapse value
+ // 8 = output value
+
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+ const operand_info &src2 = pI->src2();
+ unsigned type = pI->get_type();
+ int tid = inst.warp_id() * core->get_warp_size();
+ ptx_thread_info *thread = core->get_thread_info()[tid];
+ const int ip = (thread->get_operand_value(src1, dst, type, thread, 1)).u32;
+ const int op = (thread->get_operand_value(src2, dst, type, thread, 1)).u32;
+ const int THREADS = inst.active_count();
+ const int INBUFFERS = 4;
+ const int OUTBUFFERS = (((32/ip)*INBUFFERS) / (32/op)) + ((((32/ip)*INBUFFERS) % (32/op)) != 0);
+ if (OUTBUFFERS > THREADS) {
+ printf("GPGPU-Sim PTX: BSMAD ERROR - Number of output registers required (%d) is greater than the number available (%d)\n", OUTBUFFERS, THREADS);
+ abort();
+ }
+ ptx_warp_info *warp_info = thread->m_warp_info;
+ warp_info->inc_done_threads();
+
+ // threads within the warp are executed sequentially by the simulator, store output in first four registers
+ if (warp_info->get_done_threads() <= OUTBUFFERS) {
+ unsigned buffer[THREADS][INBUFFERS];
+ unsigned synapse[THREADS];
+ unsigned output;
+
+ // loop through all threads in the warp and get all data
+ for (unsigned i = 0, j = 0; i < core->get_warp_size(); i++) {
+ if (inst.active(i)) {
+ const operand_info &src3 = pI->operand_lookup(3);
+ const operand_info &src4 = pI->operand_lookup(4);
+ const operand_info &src5 = pI->operand_lookup(5);
+ const operand_info &src6 = pI->operand_lookup(6);
+ const operand_info &src7 = pI->operand_lookup(7);
+ const operand_info &src8 = pI->operand_lookup(8);
+
+ thread = core->get_thread_info()[tid+i];
+ // get buffer data and synapse data from each thread
+ buffer[j][0] = (thread->get_operand_value(src3, dst, type, thread, 1)).u32;
+ buffer[j][1] = (thread->get_operand_value(src4, dst, type, thread, 1)).u32;
+ buffer[j][2] = (thread->get_operand_value(src5, dst, type, thread, 1)).u32;
+ buffer[j][3] = (thread->get_operand_value(src6, dst, type, thread, 1)).u32;
+ synapse[j] = (thread->get_operand_value(src7, dst, type, thread, 1)).u32;
+ j++;
+ // get output data from the first 4 threads
+ if (j == warp_info->get_done_threads()) {
+ output = (thread->get_operand_value(src8, dst, type, thread, 1)).u32;
+ }
+ }
+ }
+
+ // unpack registers, compute enough outputs to fill an output register
+ unsigned *unpacked_output = (unsigned*)calloc(32/op,sizeof(unsigned));
+ unsigned buffer_data_start = (32/op)*(warp_info->get_done_threads()-1);
+ for (unsigned i = buffer_data_start; i < (32/op + buffer_data_start) && i < (32/ip)*INBUFFERS; i++) {
+ unsigned buf = i/(32/ip);
+ unsigned pos = i%(32/ip);
+ // sum values from the buffers
+ int sum = 0;
+ unsigned mask = (unsigned)(pow(2,ip)-1) << (pos*ip);
+ for (int j = 0; j < THREADS; j++) {
+ //sum += ((mask & buffer[j][buf]) >> (pos*ip)) * synapse[j];
+ sum += trunc(((mask & buffer[j][buf]) >> (pos*ip)) * synapse[j], op);
+ }
+ // get the previous output
+ mask = (unsigned)(pow(2,op)-1) << (op*(i-buffer_data_start));
+ int past_output = (mask & output) >> (op*(i-buffer_data_start));
+ unpacked_output[i-buffer_data_start] = trunc(trunc(sum,op) + past_output,op);
+ // truncate sum, truncate (truncated sum + past_output)
+ }
+
+ // truncate output
+ /*for (unsigned i = 0; i < 32/op; i++) {
+ int mask = 1, latest_one = -1;
+ unsigned data = unpacked_output[i];
+ for (unsigned j = 0; j < sizeof(unsigned)*8; j++) {
+ int bit = data & mask;
+ if (bit == 1) latest_one = j;
+ data >>= 1;
+ }
+ if (latest_one >= op) {
+ // round_up is 1 if the most significant truncated digit is a 1, otherwise it is 0
+ int round_up = (unpacked_output[i] & (1 << (latest_one-op))) >> (latest_one-op);
+ unsigned shifted_output = unpacked_output[i] >> (latest_one-op+1);
+ // if shifted_output is a number like 1111, don't round up
+ if (shifted_output == (pow(2,op)-1)) round_up = 0;
+ unpacked_output[i] = shifted_output + round_up;
+ }
+ }*/
+
+ // pack the outputs into one register
+ unsigned mask = pow(2,op)-1;
+ unsigned output_data = 0;
+ for (int i = 0; i < 32/op; i++) {
+ output_data |= (unpacked_output[i] & mask) << (op*i);
+ }
+
+ // store the result in the correct thread's output register
+ for (unsigned i = 0, j = 0; i < core->get_warp_size(); i++) {
+ if (inst.active(i)) j++;
+ if (j == warp_info->get_done_threads()) {
+ thread = core->get_thread_info()[tid+i];
+ ptx_reg_t data;
+ data.u32 = output_data;
+ thread->set_operand_value(dst, data, type, thread, pI);
+ break;
+ }
+ }
+ }
+
+ // once the warp has finished, set the number of completed threads back to 0 for the next warp
+ if (warp_info->get_done_threads() == THREADS) {
+ warp_info->reset_done_threads();
+ }
+
+ // set the latency assuming 4 bits of each input get processed every cycle
+ // mutable latency variable???
+ //pI->latency = (ip+3)/4;
+}
+
void call_impl( const ptx_instruction *pI, ptx_thread_info *thread )
{
static unsigned call_uid_next = 1;
@@ -2370,6 +2525,7 @@ void decode_space( memory_space_t &space, ptx_thread_info *thread, const operand
case surf_space: mem = thread->get_surf_memory(); break;
case param_space_kernel: mem = thread->get_param_memory(); break;
case shared_space: mem = thread->m_shared_mem; break;
+ case sstarr_space: mem = thread->m_sstarr_mem; break;
case const_space: mem = thread->get_global_memory(); break;
case generic_space:
if( thread->get_ptx_version().ver() >= 2.0 ) {
@@ -3832,6 +3988,88 @@ void sqrt_impl( const ptx_instruction *pI, ptx_thread_info *thread )
thread->set_operand_value(dst,d, i_type, thread, pI);
}
+void sst_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_instruction * cpI = const_cast<ptx_instruction *>(pI); // constant
+ const operand_info &dst = cpI->dst();
+ const operand_info &src1 = pI->src1();
+ const operand_info &src2 = pI->src2();
+ const operand_info &src3 = pI->src3();
+ unsigned type = pI->get_type();
+ ptx_reg_t dst_data = thread->get_operand_value(dst, dst, type, thread, 1);
+ ptx_reg_t src1_data = thread->get_operand_value(src1, src1, type, thread, 1);
+ ptx_reg_t src2_data = thread->get_operand_value(src2, src1, type, thread, 1);
+ ptx_reg_t src3_data = thread->get_operand_value(src3, src1, type, thread, 1);
+ memory_space_t space = pI->get_space();
+ memory_space *mem = NULL;
+ addr_t addr = src2_data.u32 * 4; // this assumes sstarr memory starts at address 0
+ ptx_cta_info *cta_info = thread->m_cta_info;
+
+ decode_space(space,thread,src1,mem,addr);
+
+ size_t size;
+ int t;
+ type_info_key::type_decode(type,size,t);
+
+ // store data in sstarr memory
+ mem->write(addr,size/8,&src3_data.s64,thread,pI);
+
+ // sync threads
+ cpI->set_bar_id(16); // use 16 for sst because bar uses an int from 0-15
+
+ thread->m_last_effective_address = addr;
+ thread->m_last_memory_space = space;
+ thread->m_last_dram_callback.function = bar_callback;
+ thread->m_last_dram_callback.instruction = cpI;
+
+ // the last thread that executes loads all of the data back from sstarr memory
+ int NUM_THREADS = cta_info->num_threads();
+ cta_info->inc_bar_threads();
+ if (NUM_THREADS == cta_info->get_bar_threads()) {
+ unsigned offset = 0;
+ addr = 0;
+ ptx_reg_t data;
+ float sstarr_fdata[NUM_THREADS];
+ signed long long sstarr_ldata[NUM_THREADS];
+ // loop through all of the threads
+ for (int tid = 0; tid < NUM_THREADS; tid++) {
+ data.u64=0;
+ mem->read(addr+(tid*4),size/8,&data.s64);
+ sstarr_fdata[tid] = data.f32;
+ sstarr_ldata[tid] = data.s64;
+ }
+
+ // squeeze the zeros out of the array and store data back into original array
+ mem = NULL;
+ addr = src1_data.u32;
+ space.set_type(global_space);
+ decode_space(space,thread,src1,mem,addr);
+ // store nonzero entries and indices
+ for (int tid = 0; tid < NUM_THREADS; tid++) {
+ if (sstarr_fdata[tid] != 0) {
+ float ftid = (float)tid;
+ mem->write(addr+(offset*4),size/8,&sstarr_ldata[tid],thread,pI);
+ mem->write(addr+((NUM_THREADS+offset)*4),size/8,&ftid,thread,pI);
+ offset++;
+ }
+ }
+ // store the number of nonzero elements in the array
+ data = thread->get_operand_value(src1, dst, type, thread, 1);
+ data.s64 += 4*(offset-1);
+ thread->set_operand_value(dst, data, type, thread, pI);
+
+ // fill the rest of the array with zeros (dst should always have a 0 in it)
+ while (offset < NUM_THREADS) {
+ mem->write(addr+(offset*4),size/8,&dst_data.s64,thread,pI);
+ offset++;
+ }
+
+ cta_info->reset_bar_threads();
+ thread->m_last_effective_address = addr+(NUM_THREADS-1)*4;
+ thread->m_last_memory_space = space;
+ }
+}
+
void ssy_impl( const ptx_instruction *pI, ptx_thread_info *thread )
{
//printf("Execution Warning: unimplemented ssy instruction is treated as a nop\n");