diff options
Diffstat (limited to 'src/cuda-sim/instructions.cc')
| -rw-r--r-- | src/cuda-sim/instructions.cc | 238 |
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"); |
