diff options
| author | Davit Grigoryan <[email protected]> | 2026-04-29 00:02:46 +0000 |
|---|---|---|
| committer | Davit Grigoryan <[email protected]> | 2026-04-29 00:02:46 +0000 |
| commit | 314fb652d8a27a38599eeeec121d45327a405bb0 (patch) | |
| tree | d3fa263f05e8b40c766b68eb1771b619b847802f /src/gpgpu-sim/shader.cc | |
| parent | fbb90ef3a76cd6c469782c84668d25c5f3bfdd22 (diff) | |
impl option w/ only 2 SBs; stall so SBs are cleared before div or reconv
Diffstat (limited to 'src/gpgpu-sim/shader.cc')
| -rw-r--r-- | src/gpgpu-sim/shader.cc | 150 |
1 files changed, 131 insertions, 19 deletions
diff --git a/src/gpgpu-sim/shader.cc b/src/gpgpu-sim/shader.cc index ec764aa..9a47996 100644 --- a/src/gpgpu-sim/shader.cc +++ b/src/gpgpu-sim/shader.cc @@ -1063,6 +1063,15 @@ void shader_core_ctx::fetch() { m_simt_tables[wid]->get_active_split_id(); m_inst_fetch_buffer.m_split_mask = m_simt_tables[wid]->get_active_mask(); + // Mode 2: record half 0's owner. + if (m_config->gpgpu_scoreboard_mode == 2) { + active_mask_t mask_aw; + const simt_mask_t &m = m_simt_tables[wid]->get_active_mask(); + for (unsigned t = 0; t < MAX_WARP_SIZE; t++) + if (m.test(t)) mask_aw.set(t); + m_warp[wid]->ibuffer_assign_half(0, m_inst_fetch_buffer.m_split_id, + mask_aw); + } } m_inst_fetch_buffer.m_ibuffer_half = 0; m_warp[mf->get_wid()]->set_last_fetch(m_gpu->gpu_sim_cycle); @@ -1110,6 +1119,20 @@ void shader_core_ctx::fetch() { if (simt_conditions && !m_warp[warp_id]->functional_done() && !m_warp[warp_id]->imiss_pending() && m_warp[warp_id]->ibuffer_half_empty(0)) { + // Mode 2 (slot-pinned): if the next split to fetch from differs + // from half 0's previously assigned owner, wait for the slot's + // scoreboard to drain before reassigning. This is the "wait + // for clean at divergence/reconvergence/split-rotation" gate. + if (m_config->gpgpu_scoreboard_mode == 2 && + m_config->model == AWARE_RECONVERGENCE) { + unsigned new_split_id = + m_simt_tables[warp_id]->get_active_split_id(); + if (m_warp[warp_id]->ibuffer_half_assigned(0) && + m_warp[warp_id]->ibuffer_half_split_id(0) != new_split_id && + !m_scoreboard->slotClean(warp_id, 0)) { + continue; // drain pending — try next warp + } + } address_type pc; pc = m_warp[warp_id]->get_pc(); address_type ppc = pc + PROGRAM_MEM_START; @@ -1147,6 +1170,16 @@ void shader_core_ctx::fetch() { m_simt_tables[warp_id]->get_active_split_id(); m_inst_fetch_buffer.m_split_mask = m_simt_tables[warp_id]->get_active_mask(); + // Mode 2: record half 0's owner for the wait-for-clean gate. + if (m_config->gpgpu_scoreboard_mode == 2) { + active_mask_t mask_aw; + const simt_mask_t &m = + m_simt_tables[warp_id]->get_active_mask(); + for (unsigned t = 0; t < MAX_WARP_SIZE; t++) + if (m.test(t)) mask_aw.set(t); + m_warp[warp_id]->ibuffer_assign_half( + 0, m_inst_fetch_buffer.m_split_id, mask_aw); + } } m_inst_fetch_buffer.m_ibuffer_half = 0; m_warp[warp_id]->set_last_fetch(m_gpu->gpu_sim_cycle); @@ -1192,6 +1225,15 @@ void shader_core_ctx::fetch() { if ((sec_mask & half0_mask).any()) continue; // overlapping, skip } + // Mode 2: if half 1's previous owner differs from this candidate, + // wait for SB[1] to drain before reassigning. + if (m_config->gpgpu_scoreboard_mode == 2 && + m_warp[warp_id]->ibuffer_half_assigned(1) && + m_warp[warp_id]->ibuffer_half_split_id(1) != sec_split_id && + !m_scoreboard->slotClean(warp_id, 1)) { + continue; // drain pending — try next warp + } + // Attempt I-Cache access (HIT-only for secondary) address_type ppc = sec_pc + PROGRAM_MEM_START; unsigned nbytes = 16; @@ -1297,6 +1339,8 @@ warp_inst_t *shader_core_ctx::issue_warp(register_set &pipe_reg_set, (*pipe_reg)->set_dbg_path(0); (*pipe_reg)->set_dbg_split_id(-1); (*pipe_reg)->set_dbg_source_inst(next_inst); + // Mode 2: primary issue always comes through ibuffer half 0. + (*pipe_reg)->set_ibuffer_half_id(0); static const bool dbg_pc_enabled_pri = (getenv("MEMCO_DBG_PC") != NULL); if (dbg_pc_enabled_pri && warp_id == 0 && m_config->model == AWARE_RECONVERGENCE) { @@ -1449,6 +1493,10 @@ void shader_core_ctx::co_issue_warp(warp_inst_t *composite, temp_inst.set_dbg_path(split_id != (unsigned)-1 ? 1u : 2u); temp_inst.set_dbg_split_id(split_id != (unsigned)-1 ? (int)split_id : -1); temp_inst.set_dbg_source_inst(next_inst); + // Mode 2: stamp the source's owning ibuffer half. Intra-warp co-issue + // came from primary's slot 1 (secondary half); inter-warp from the + // donor's slot 0 (donor's own primary half). + temp_inst.set_ibuffer_half_id(split_id != (unsigned)-1 ? 1u : 0u); // Debug: for intra co-issue, compare cached active_mask (from // ibuffer slot) against current splits-table mask + warp's @@ -1529,11 +1577,13 @@ void shader_core_ctx::co_issue_warp(warp_inst_t *composite, } // Reserve scoreboard for the co-issued warp. - if (m_config->gpgpu_scoreboard_mode == 1) { - // Mode 1 (mask-aware): both inter-warp and intra-warp use the unified - // mask-aware scoreboard. The active_mask carried in temp_inst already - // differentiates the two splits' reservations — disjoint-lane writes - // get distinct (reg, mask) entries even when they share warp_id. + if (m_config->gpgpu_scoreboard_mode == 1 || + m_config->gpgpu_scoreboard_mode == 2) { + // Mode 1 (mask-aware): both inter and intra use unified mask-aware + // scoreboard; mask differentiates entries. + // Mode 2 (slot-pinned): both inter and intra reserve on their + // respective slot's scoreboard via temp_inst's set ibuffer_half_id + // (set above to 0 for inter, 1 for intra). m_scoreboard->reserveRegisters(&temp_inst); } else { // Mode 0 (legacy): @@ -1570,6 +1620,10 @@ void shader_core_ctx::co_issue_warp(warp_inst_t *composite, // release the matching mask-aware reservation. Cheap and harmless in // mode 0 (field is unused there). temp_inst.set_source_mask_on_sets(active_mask); + // Mode 2: stamp the source's owning ibuffer half (0 for inter-warp + // donor's primary half, 1 for intra-warp's secondary half) so per-set + // writeback can pick the right slot scoreboard. + temp_inst.set_source_slot_on_sets(split_id != (unsigned)-1 ? 1u : 0u); // Mixed-space MEM co-issue (v2): for SHARED coissuers, capture per-lane // memreqaddr + temp_inst.cycles into each valid set BEFORE merge. The @@ -1963,8 +2017,8 @@ void scheduler_unit::try_inter_warp_coissue( } // Scoreboard check. - // Mode 1 needs the candidate's active mask for hazard intersection; - // hoist its lookup before the legacy/mode-1 dispatch. + // Mode 1 needs the candidate's active mask for hazard intersection. + // Mode 2 checks the donor warp's slot 0 (its primary half). bool sb_collision_inter; if (m_shader->m_config->gpgpu_scoreboard_mode == 1) { const active_mask_t &cand_mask_pre = @@ -1972,6 +2026,9 @@ void scheduler_unit::try_inter_warp_coissue( sb_collision_inter = m_scoreboard->checkCollisionMask(cand_warp_id, cand_inst, cand_mask_pre); + } else if (m_shader->m_config->gpgpu_scoreboard_mode == 2) { + sb_collision_inter = m_scoreboard->checkCollisionSlot( + cand_warp_id, /*slot=*/0, cand_inst); } else { sb_collision_inter = m_scoreboard->checkCollision(cand_warp_id, cand_inst); @@ -2135,6 +2192,10 @@ void scheduler_unit::try_intra_warp_coissue( if (m_shader->m_config->gpgpu_scoreboard_mode == 1) { sb_collision = m_scoreboard->checkCollisionMask(primary_warp_id, sec_inst, sec_mask_eff); + } else if (m_shader->m_config->gpgpu_scoreboard_mode == 2) { + // Intra-warp candidates check primary warp's slot 1 (secondary half). + sb_collision = m_scoreboard->checkCollisionSlot(primary_warp_id, + /*slot=*/1, sec_inst); } else { sb_collision = m_scoreboard->checkCollisionSecondary(primary_warp_id, sec_inst); @@ -2234,6 +2295,9 @@ void scheduler_unit::try_utilization_max_coissue( sb_collision_inter2 = m_scoreboard->checkCollisionMask(cand_warp_id, cand_inst, cand_mask_pre); + } else if (m_shader->m_config->gpgpu_scoreboard_mode == 2) { + sb_collision_inter2 = m_scoreboard->checkCollisionSlot( + cand_warp_id, /*slot=*/0, cand_inst); } else { sb_collision_inter2 = m_scoreboard->checkCollision(cand_warp_id, cand_inst); @@ -2400,6 +2464,10 @@ void scheduler_unit::try_utilization_max_coissue( sb_collision = m_scoreboard->checkCollisionMask(cand_warp_id, sec_inst, sec_mask_eff); + } else if (m_shader->m_config->gpgpu_scoreboard_mode == 2) { + sb_collision = m_scoreboard->checkCollisionSlot(cand_warp_id, + /*slot=*/1, + sec_inst); } else { sb_collision = m_scoreboard->checkCollisionSecondary(cand_warp_id, sec_inst); @@ -2614,6 +2682,9 @@ void scheduler_unit::cycle() { if (m_shader->m_config->gpgpu_scoreboard_mode == 1) { sb_collision_primary = m_scoreboard->checkCollisionMask(warp_id, pI, active_mask); + } else if (m_shader->m_config->gpgpu_scoreboard_mode == 2) { + sb_collision_primary = m_scoreboard->checkCollisionSlot( + warp_id, /*slot=*/0, pI); } else { sb_collision_primary = m_scoreboard->checkCollision(warp_id, pI); } @@ -3403,12 +3474,15 @@ void shader_core_ctx::writeback() { for (unsigned s = 0; s < sets.size(); s++) { if (!sets[s].valid || sets[s].source_inst == NULL) continue; unsigned set_wid = sets[s].warp_id; + unsigned set_slot = + (sets[s].source_slot_id != (unsigned)-1) ? sets[s].source_slot_id + : 0u; for (unsigned r = 0; r < MAX_OUTPUT_VALUES; r++) { if (sets[s].source_inst->out[r] > 0) { m_scoreboard->releaseSetReg(set_wid, sets[s].source_inst->out[r], sets[s].source_mask, - /*is_intra_legacy=*/false); + /*is_intra_legacy=*/false, set_slot); } } } @@ -3433,11 +3507,15 @@ void shader_core_ctx::writeback() { // Intra-warp: release from secondary scoreboard (mode 0) or // mask-aware (mode 1) and dec once. if (!intra_warp_decremented) { + unsigned set_slot = + (sets[s].source_slot_id != (unsigned)-1) + ? sets[s].source_slot_id + : 1u; // intra defaults to slot 1 for (unsigned r = 0; r < MAX_OUTPUT_VALUES; r++) { if (sets[s].source_inst->out[r] > 0) { m_scoreboard->releaseSetReg( sets[s].warp_id, sets[s].source_inst->out[r], - sets[s].source_mask, /*is_intra_legacy=*/true); + sets[s].source_mask, /*is_intra_legacy=*/true, set_slot); } } m_warp[warp_id]->dec_inst_in_pipeline(); @@ -3774,7 +3852,8 @@ void ldst_unit::L1_latency_queue_cycle() { m_pending_writes_secondary[src.wid][src_split_mf].erase( reg); m_scoreboard->releaseSetReg(src.wid, reg, src.source_mask, - /*is_intra_legacy=*/true); + /*is_intra_legacy=*/true, + src.source_slot_id); any_completed = true; } } else { @@ -3783,7 +3862,8 @@ void ldst_unit::L1_latency_queue_cycle() { if (!still_pending) { m_pending_writes[src.wid].erase(reg); m_scoreboard->releaseSetReg(src.wid, reg, src.source_mask, - /*is_intra_legacy=*/false); + /*is_intra_legacy=*/false, + src.source_slot_id); any_completed = true; } } @@ -4370,6 +4450,7 @@ ldst_unit::mem_src_t ldst_unit::resolve_source( r.wid = (access_src_wid == (unsigned)-1) ? inst.warp_id() : access_src_wid; r.out_inst = &inst; r.source_mask.reset(); + r.source_slot_id = 0; // primary's own slot // Primary access: (wid == primary AND split_id == -1). Return early with // out_inst = composite (primary's out[]). Note: split_id is the // discriminator — a coissuer can have the same warp_id as primary when @@ -4377,6 +4458,8 @@ ldst_unit::mem_src_t ldst_unit::resolve_source( if (r.wid == inst.warp_id() && access_src_split_id == (unsigned)-1) { // Primary's own mask is on the composite itself. r.source_mask = inst.get_active_mask(); + r.source_slot_id = inst.get_ibuffer_half_id(); + if (r.source_slot_id == (unsigned)-1) r.source_slot_id = 0; return r; } if (!inst.has_simd_sets()) return r; @@ -4388,6 +4471,9 @@ ldst_unit::mem_src_t ldst_unit::resolve_source( sets[s].split_id == access_src_split_id) { r.out_inst = sets[s].source_inst; r.source_mask = sets[s].source_mask; + if (sets[s].source_slot_id != (unsigned)-1) { + r.source_slot_id = sets[s].source_slot_id; + } break; } } @@ -4769,7 +4855,8 @@ void ldst_unit::writeback() { .erase(reg); m_scoreboard->releaseSetReg(src_i.wid, reg, src_i.source_mask, - /*is_intra_legacy=*/true); + /*is_intra_legacy=*/true, + src_i.source_slot_id); insn_completed = true; } } else { @@ -4780,7 +4867,8 @@ void ldst_unit::writeback() { m_pending_writes[src_i.wid].erase(reg); m_scoreboard->releaseSetReg(src_i.wid, reg, src_i.source_mask, - /*is_intra_legacy=*/false); + /*is_intra_legacy=*/false, + src_i.source_slot_id); insn_completed = true; } } @@ -4807,7 +4895,8 @@ void ldst_unit::writeback() { if (src.out_inst->out[r] > 0) { m_scoreboard->releaseSetReg(src.wid, src.out_inst->out[r], src.source_mask, - /*is_intra_legacy=*/false); + /*is_intra_legacy=*/false, + src.source_slot_id); insn_completed = true; } } @@ -4828,11 +4917,16 @@ void ldst_unit::writeback() { released.insert(key); // Secondary slot coissuer → secondary scoreboard map (mode 0). bool coissued_intra = (sets[s].split_id != (unsigned)-1); + unsigned set_slot = + (sets[s].source_slot_id != (unsigned)-1) + ? sets[s].source_slot_id + : (coissued_intra ? 1u : 0u); for (unsigned r = 0; r < MAX_OUTPUT_VALUES; r++) { if (sets[s].source_inst->out[r] > 0) { m_scoreboard->releaseSetReg( sets[s].warp_id, sets[s].source_inst->out[r], - sets[s].source_mask, /*is_intra_legacy=*/coissued_intra); + sets[s].source_mask, /*is_intra_legacy=*/coissued_intra, + set_slot); insn_completed = true; } } @@ -5151,12 +5245,16 @@ void ldst_unit::cycle() { if (released.count(key)) continue; released.insert(key); bool is_intra = (sets[s].split_id != (unsigned)-1); + unsigned set_slot = + (sets[s].source_slot_id != (unsigned)-1) + ? sets[s].source_slot_id + : (is_intra ? 1u : 0u); for (unsigned r = 0; r < MAX_OUTPUT_VALUES; r++) { unsigned reg = sets[s].source_inst->out[r]; if (reg == 0) continue; m_scoreboard->releaseSetReg(sets[s].warp_id, reg, sets[s].source_mask, - /*is_intra_legacy=*/is_intra); + /*is_intra_legacy=*/is_intra, set_slot); } } pipe_reg.set_shared_side_released(true); @@ -5325,12 +5423,16 @@ void ldst_unit::cycle() { if (released_shared.count(key)) continue; released_shared.insert(key); bool is_intra = (sets[s].split_id != (unsigned)-1); + unsigned set_slot = + (sets[s].source_slot_id != (unsigned)-1) + ? sets[s].source_slot_id + : (is_intra ? 1u : 0u); for (unsigned r = 0; r < MAX_OUTPUT_VALUES; r++) { unsigned reg_id = sets[s].source_inst->out[r]; if (reg_id == 0) continue; m_scoreboard->releaseSetReg(sets[s].warp_id, reg_id, sets[s].source_mask, - /*is_intra_legacy=*/is_intra); + /*is_intra_legacy=*/is_intra, set_slot); } } } @@ -5472,12 +5574,17 @@ void ldst_unit::cycle() { released.insert(key); // Secondary slot → secondary scoreboard map (mode 0). bool is_intra = (sets[s].split_id != (unsigned)-1); + unsigned set_slot = + (sets[s].source_slot_id != (unsigned)-1) + ? sets[s].source_slot_id + : (is_intra ? 1u : 0u); for (unsigned r = 0; r < MAX_OUTPUT_VALUES; r++) { unsigned reg_id = sets[s].source_inst->out[r]; if (reg_id == 0) continue; m_scoreboard->releaseSetReg(sets[s].warp_id, reg_id, sets[s].source_mask, - /*is_intra_legacy=*/is_intra); + /*is_intra_legacy=*/is_intra, + set_slot); } } } @@ -5557,12 +5664,17 @@ void ldst_unit::cycle() { if (released.count(key)) continue; released.insert(key); bool is_intra = (sets[s].split_id != (unsigned)-1); + unsigned set_slot = + (sets[s].source_slot_id != (unsigned)-1) + ? sets[s].source_slot_id + : (is_intra ? 1u : 0u); for (unsigned r = 0; r < MAX_OUTPUT_VALUES; r++) { unsigned reg_id = sets[s].source_inst->out[r]; if (reg_id == 0) continue; m_scoreboard->releaseSetReg(sets[s].warp_id, reg_id, sets[s].source_mask, - /*is_intra_legacy=*/is_intra); + /*is_intra_legacy=*/is_intra, + set_slot); } } } |
