diff options
Diffstat (limited to 'src/emu/cpu/rsp/vmull.h')
-rw-r--r-- | src/emu/cpu/rsp/vmull.h | 44 |
1 files changed, 44 insertions, 0 deletions
diff --git a/src/emu/cpu/rsp/vmull.h b/src/emu/cpu/rsp/vmull.h new file mode 100644 index 00000000000..2052d537aa8 --- /dev/null +++ b/src/emu/cpu/rsp/vmull.h @@ -0,0 +1,44 @@ +// license:BSD-3-Clause +// copyright-holders:Tyler J. Stachecki,Ryan Holtz + +inline rsp_vec_t vec_vmadl_vmudl(UINT32 iw, rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t zero, rsp_vec_t *acc_lo, rsp_vec_t *acc_md, rsp_vec_t *acc_hi) +{ + rsp_vec_t hi = _mm_mulhi_epu16(vs, vt); + + if (iw & 0x8) // VMADL + { + // Tricky part: start accumulating everything. + // Get/keep the carry as we'll add it in later. + rsp_vec_t overflow_mask = _mm_adds_epu16(*acc_lo, hi); + *acc_lo = _mm_add_epi16(*acc_lo, hi); + + overflow_mask = _mm_cmpeq_epi16(*acc_lo, overflow_mask); + overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero); + hi = _mm_sub_epi16(zero, overflow_mask); + + // Check for overflow of the upper sum. + // + // TODO: Since hi can only be {0,1}, we should + // be able to generalize this for performance. + overflow_mask = _mm_adds_epu16(*acc_md, hi); + *acc_md = _mm_add_epi16(*acc_md, hi); + + overflow_mask = _mm_cmpeq_epi16(*acc_md, overflow_mask); + overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero); + + // Finish up the accumulation of the... accumulator. + // Since the product was unsigned, only worry about + // positive overflow (i.e.: borrowing not possible). + *acc_hi = _mm_sub_epi16(*acc_hi, overflow_mask); + + return uclamp_acc(*acc_lo, *acc_md, *acc_hi, zero); + } + else // VMUDL + { + *acc_lo = hi; + *acc_md = zero; + *acc_hi = zero; + + return hi; + } +} |