mirror of
https://github.com/gopher64/gopher64.git
synced 2026-07-11 01:25:20 +02:00
1254 lines
47 KiB
Rust
1254 lines
47 KiB
Rust
use crate::device;
|
|
use std::arch::x86_64::*;
|
|
|
|
pub fn vt(opcode: u32) -> u32 {
|
|
return (opcode >> 16) & 0x1F;
|
|
}
|
|
|
|
pub fn ve(opcode: u32) -> u32 {
|
|
return (opcode >> 21) & 0xF;
|
|
}
|
|
|
|
pub fn vs(opcode: u32) -> u32 {
|
|
return (opcode >> 11) & 0x1F;
|
|
}
|
|
|
|
pub fn vd(opcode: u32) -> u32 {
|
|
return (opcode >> 6) & 0x1F;
|
|
}
|
|
|
|
pub fn de(opcode: u32) -> u32 {
|
|
return (opcode >> 11) & 0x7;
|
|
}
|
|
|
|
pub fn clamp_signed_32(value: i32) -> i16 {
|
|
if value < -32768 {
|
|
return -32768;
|
|
}
|
|
if value > 32767 {
|
|
return 32767;
|
|
}
|
|
return value as i16;
|
|
}
|
|
|
|
pub fn clamp_signed_64(value: i64) -> i16 {
|
|
if value < -32768 {
|
|
return -32768;
|
|
}
|
|
if value > 32767 {
|
|
return 32767;
|
|
}
|
|
return value as i16;
|
|
}
|
|
|
|
pub fn count_leading_zeros(value: u32) -> u32 {
|
|
let mut index = 31;
|
|
while index >= 0 {
|
|
if (value >> index) & 1 != 0 {
|
|
break;
|
|
}
|
|
index -= 1;
|
|
}
|
|
return (31 - index) as u32;
|
|
}
|
|
|
|
pub fn s_clip(x: i64, bits: u32) -> i64 {
|
|
let b = (1 as u64) << (bits - 1);
|
|
let m = b * 2 - 1;
|
|
return ((((x as u64) & m) ^ b).wrapping_sub(b)) as i64;
|
|
}
|
|
|
|
pub fn modify_vpr_element(vpr: &mut u128, value: u16, element: u8) {
|
|
let pos = 7 - (element & 7);
|
|
let mask = 0xFFFF << (pos * 16);
|
|
*vpr &= !mask;
|
|
*vpr |= (value as u128) << (pos * 16);
|
|
}
|
|
|
|
pub fn get_vpr_element(vpr: u128, element: u8) -> u16 {
|
|
let pos = 7 - (element & 7);
|
|
return (vpr >> (pos * 16)) as u16;
|
|
}
|
|
|
|
pub fn vte(vt: u128, index: usize) -> __m128i {
|
|
unsafe {
|
|
let shuffle = [
|
|
//vector
|
|
_mm_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), //01234567
|
|
_mm_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), //01234567
|
|
//scalar quarter
|
|
_mm_set_epi8(15, 14, 15, 14, 11, 10, 11, 10, 7, 6, 7, 6, 3, 2, 3, 2), //00224466
|
|
_mm_set_epi8(13, 12, 13, 12, 9, 8, 9, 8, 5, 4, 5, 4, 1, 0, 1, 0), //11335577
|
|
//scalar half
|
|
_mm_set_epi8(15, 14, 15, 14, 15, 14, 15, 14, 7, 6, 7, 6, 7, 6, 7, 6), //00004444
|
|
_mm_set_epi8(13, 12, 13, 12, 13, 12, 13, 12, 5, 4, 5, 4, 5, 4, 5, 4), //11115555
|
|
_mm_set_epi8(11, 10, 11, 10, 11, 10, 11, 10, 3, 2, 3, 2, 3, 2, 3, 2), //22226666
|
|
_mm_set_epi8(9, 8, 9, 8, 9, 8, 9, 8, 1, 0, 1, 0, 1, 0, 1, 0), //33337777
|
|
//scalar whole
|
|
_mm_set_epi8(
|
|
15, 14, 15, 14, 15, 14, 15, 14, 15, 14, 15, 14, 15, 14, 15, 14,
|
|
), //00000000
|
|
_mm_set_epi8(
|
|
13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12,
|
|
), //11111111
|
|
_mm_set_epi8(
|
|
11, 10, 11, 10, 11, 10, 11, 10, 11, 10, 11, 10, 11, 10, 11, 10,
|
|
), //22222222
|
|
_mm_set_epi8(9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8), //33333333
|
|
_mm_set_epi8(7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6), //44444444
|
|
_mm_set_epi8(5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4), //55555555
|
|
_mm_set_epi8(3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2), //66666666
|
|
_mm_set_epi8(1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0), //77777777
|
|
];
|
|
return _mm_shuffle_epi8(std::mem::transmute(vt), shuffle[index]);
|
|
}
|
|
}
|
|
|
|
pub fn vmulf(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
let (mut lo, mut hi, mut round, mut sign1, sign2, neq, eq, neg);
|
|
unsafe {
|
|
lo = _mm_mullo_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
round = _mm_cmpeq_epi16(_mm_setzero_si128(), _mm_setzero_si128());
|
|
sign1 = _mm_srli_epi16(lo, 15);
|
|
lo = _mm_add_epi16(lo, lo);
|
|
round = _mm_slli_epi16(round, 15);
|
|
hi = _mm_mulhi_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
sign2 = _mm_srli_epi16(lo, 15);
|
|
device.rsp.cpu.accl = _mm_add_epi16(round, lo);
|
|
sign1 = _mm_add_epi16(sign1, sign2);
|
|
hi = _mm_slli_epi16(hi, 1);
|
|
neq = _mm_cmpeq_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
device.rsp.cpu.accm = _mm_add_epi16(hi, sign1);
|
|
neg = _mm_srai_epi16(device.rsp.cpu.accm, 15);
|
|
|
|
eq = _mm_and_si128(neq, neg);
|
|
device.rsp.cpu.acch = _mm_andnot_si128(neq, neg);
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] =
|
|
std::mem::transmute(_mm_add_epi16(device.rsp.cpu.accm, eq));
|
|
}
|
|
}
|
|
|
|
pub fn vmulu(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
let (mut lo, mut hi, mut round, mut sign1, sign2, neq, neg);
|
|
unsafe {
|
|
lo = _mm_mullo_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
round = _mm_cmpeq_epi16(_mm_setzero_si128(), _mm_setzero_si128());
|
|
sign1 = _mm_srli_epi16(lo, 15);
|
|
lo = _mm_add_epi16(lo, lo);
|
|
round = _mm_slli_epi16(round, 15);
|
|
hi = _mm_mulhi_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
sign2 = _mm_srli_epi16(lo, 15);
|
|
device.rsp.cpu.accl = _mm_add_epi16(round, lo);
|
|
sign1 = _mm_add_epi16(sign1, sign2);
|
|
hi = _mm_slli_epi16(hi, 1);
|
|
neq = _mm_cmpeq_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
device.rsp.cpu.accm = _mm_add_epi16(hi, sign1);
|
|
neg = _mm_srai_epi16(device.rsp.cpu.accm, 15);
|
|
|
|
device.rsp.cpu.acch = _mm_andnot_si128(neq, neg);
|
|
hi = _mm_or_si128(device.rsp.cpu.accm, neg);
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] =
|
|
std::mem::transmute(_mm_andnot_si128(device.rsp.cpu.acch, hi));
|
|
}
|
|
}
|
|
|
|
pub fn vrndp(device: &mut device::Device, opcode: u32) {
|
|
let vte = unsafe {
|
|
std::mem::transmute(vte(
|
|
device.rsp.cpu.vpr[vt(opcode) as usize],
|
|
ve(opcode) as usize,
|
|
))
|
|
};
|
|
let acch: &mut u128 = unsafe { std::mem::transmute(&mut device.rsp.cpu.acch) };
|
|
let accm: &mut u128 = unsafe { std::mem::transmute(&mut device.rsp.cpu.accm) };
|
|
let accl: &mut u128 = unsafe { std::mem::transmute(&mut device.rsp.cpu.accl) };
|
|
|
|
let mut n = 0;
|
|
while n < 8 {
|
|
let mut product = get_vpr_element(vte, n) as i16 as i32;
|
|
if vs(opcode) & 1 != 0 {
|
|
product <<= 16
|
|
}
|
|
let mut acc = 0;
|
|
acc |= get_vpr_element(*acch, n) as i64;
|
|
acc <<= 16;
|
|
acc |= get_vpr_element(*accm, n) as i64;
|
|
acc <<= 16;
|
|
acc |= get_vpr_element(*accl, n) as i64;
|
|
acc <<= 16;
|
|
acc >>= 16;
|
|
if acc >= 0 {
|
|
acc = s_clip(acc + (product as i64), 48)
|
|
}
|
|
modify_vpr_element(acch, (acc >> 32) as u16, n);
|
|
modify_vpr_element(accm, (acc >> 16) as u16, n);
|
|
modify_vpr_element(accl, acc as u16, n);
|
|
modify_vpr_element(
|
|
&mut device.rsp.cpu.vpr[vd(opcode) as usize],
|
|
clamp_signed_64(acc >> 16) as u16,
|
|
n,
|
|
);
|
|
|
|
n += 1;
|
|
}
|
|
}
|
|
|
|
pub fn vmulq(device: &mut device::Device, opcode: u32) {
|
|
let vte = unsafe {
|
|
std::mem::transmute(vte(
|
|
device.rsp.cpu.vpr[vt(opcode) as usize],
|
|
ve(opcode) as usize,
|
|
))
|
|
};
|
|
let acch: &mut u128 = unsafe { std::mem::transmute(&mut device.rsp.cpu.acch) };
|
|
let accm: &mut u128 = unsafe { std::mem::transmute(&mut device.rsp.cpu.accm) };
|
|
let accl: &mut u128 = unsafe { std::mem::transmute(&mut device.rsp.cpu.accl) };
|
|
|
|
let mut n = 0;
|
|
while n < 8 {
|
|
let mut product = (get_vpr_element(device.rsp.cpu.vpr[vs(opcode) as usize], n) as i16
|
|
as i32)
|
|
.wrapping_mul(get_vpr_element(vte, n) as i16 as i32);
|
|
if product < 0 {
|
|
product += 31;
|
|
}
|
|
modify_vpr_element(acch, (product >> 16) as u16, n);
|
|
modify_vpr_element(accm, (product) as u16, n);
|
|
modify_vpr_element(accl, 0, n);
|
|
modify_vpr_element(
|
|
&mut device.rsp.cpu.vpr[vd(opcode) as usize],
|
|
(clamp_signed_32(product >> 1) & !15) as u16,
|
|
n,
|
|
);
|
|
n += 1;
|
|
}
|
|
}
|
|
|
|
pub fn vmudl(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
unsafe {
|
|
device.rsp.cpu.accl = _mm_mulhi_epu16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
device.rsp.cpu.accm = _mm_setzero_si128();
|
|
device.rsp.cpu.acch = _mm_setzero_si128();
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] = std::mem::transmute(device.rsp.cpu.accl);
|
|
}
|
|
}
|
|
|
|
pub fn vmudm(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
let (sign, vta);
|
|
unsafe {
|
|
device.rsp.cpu.accl = _mm_mullo_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
device.rsp.cpu.accm = _mm_mulhi_epu16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
sign = _mm_srai_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
15,
|
|
);
|
|
vta = _mm_and_si128(vte, sign);
|
|
device.rsp.cpu.accm = _mm_sub_epi16(device.rsp.cpu.accm, vta);
|
|
device.rsp.cpu.acch = _mm_srai_epi16(device.rsp.cpu.accm, 15);
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] = std::mem::transmute(device.rsp.cpu.accm);
|
|
}
|
|
}
|
|
|
|
pub fn vmudn(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
let (sign, vsa);
|
|
unsafe {
|
|
device.rsp.cpu.accl = _mm_mullo_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
device.rsp.cpu.accm = _mm_mulhi_epu16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
sign = _mm_srai_epi16(vte, 15);
|
|
vsa = _mm_and_si128(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
sign,
|
|
);
|
|
device.rsp.cpu.accm = _mm_sub_epi16(device.rsp.cpu.accm, vsa);
|
|
device.rsp.cpu.acch = _mm_srai_epi16(device.rsp.cpu.accm, 15);
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] = std::mem::transmute(device.rsp.cpu.accl);
|
|
}
|
|
}
|
|
|
|
pub fn vmudh(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
let (lo, hi);
|
|
unsafe {
|
|
device.rsp.cpu.accl = _mm_setzero_si128();
|
|
device.rsp.cpu.accm = _mm_mullo_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
device.rsp.cpu.acch = _mm_mulhi_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
lo = _mm_unpacklo_epi16(device.rsp.cpu.accm, device.rsp.cpu.acch);
|
|
hi = _mm_unpackhi_epi16(device.rsp.cpu.accm, device.rsp.cpu.acch);
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] = std::mem::transmute(_mm_packs_epi32(lo, hi));
|
|
}
|
|
}
|
|
|
|
pub fn vmacf(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
let (mut lo, mut md, mut hi, mut carry, mut omask);
|
|
unsafe {
|
|
lo = _mm_mullo_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
hi = _mm_mulhi_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
md = _mm_slli_epi16(hi, 1);
|
|
carry = _mm_srli_epi16(lo, 15);
|
|
hi = _mm_srai_epi16(hi, 15);
|
|
md = _mm_or_si128(md, carry);
|
|
lo = _mm_slli_epi16(lo, 1);
|
|
omask = _mm_adds_epu16(device.rsp.cpu.accl, lo);
|
|
device.rsp.cpu.accl = _mm_add_epi16(device.rsp.cpu.accl, lo);
|
|
omask = _mm_cmpeq_epi16(device.rsp.cpu.accl, omask);
|
|
omask = _mm_cmpeq_epi16(omask, _mm_setzero_si128());
|
|
md = _mm_sub_epi16(md, omask);
|
|
carry = _mm_cmpeq_epi16(md, _mm_setzero_si128());
|
|
carry = _mm_and_si128(carry, omask);
|
|
hi = _mm_sub_epi16(hi, carry);
|
|
omask = _mm_adds_epu16(device.rsp.cpu.accm, md);
|
|
device.rsp.cpu.accm = _mm_add_epi16(device.rsp.cpu.accm, md);
|
|
omask = _mm_cmpeq_epi16(device.rsp.cpu.accm, omask);
|
|
omask = _mm_cmpeq_epi16(omask, _mm_setzero_si128());
|
|
device.rsp.cpu.acch = _mm_add_epi16(device.rsp.cpu.acch, hi);
|
|
device.rsp.cpu.acch = _mm_sub_epi16(device.rsp.cpu.acch, omask);
|
|
|
|
lo = _mm_unpacklo_epi16(device.rsp.cpu.accm, device.rsp.cpu.acch);
|
|
hi = _mm_unpackhi_epi16(device.rsp.cpu.accm, device.rsp.cpu.acch);
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] = std::mem::transmute(_mm_packs_epi32(lo, hi));
|
|
}
|
|
}
|
|
|
|
pub fn vmacu(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
let (mut lo, mut md, mut hi, mut carry, mut omask, mmask, hmask);
|
|
unsafe {
|
|
lo = _mm_mullo_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
hi = _mm_mulhi_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
md = _mm_slli_epi16(hi, 1);
|
|
carry = _mm_srli_epi16(lo, 15);
|
|
hi = _mm_srai_epi16(hi, 15);
|
|
md = _mm_or_si128(md, carry);
|
|
lo = _mm_slli_epi16(lo, 1);
|
|
omask = _mm_adds_epu16(device.rsp.cpu.accl, lo);
|
|
device.rsp.cpu.accl = _mm_add_epi16(device.rsp.cpu.accl, lo);
|
|
omask = _mm_cmpeq_epi16(device.rsp.cpu.accl, omask);
|
|
omask = _mm_cmpeq_epi16(omask, _mm_setzero_si128());
|
|
md = _mm_sub_epi16(md, omask);
|
|
carry = _mm_cmpeq_epi16(md, _mm_setzero_si128());
|
|
carry = _mm_and_si128(carry, omask);
|
|
hi = _mm_sub_epi16(hi, carry);
|
|
omask = _mm_adds_epu16(device.rsp.cpu.accm, md);
|
|
device.rsp.cpu.accm = _mm_add_epi16(device.rsp.cpu.accm, md);
|
|
omask = _mm_cmpeq_epi16(device.rsp.cpu.accm, omask);
|
|
omask = _mm_cmpeq_epi16(omask, _mm_setzero_si128());
|
|
device.rsp.cpu.acch = _mm_add_epi16(device.rsp.cpu.acch, hi);
|
|
device.rsp.cpu.acch = _mm_sub_epi16(device.rsp.cpu.acch, omask);
|
|
|
|
mmask = _mm_srai_epi16(device.rsp.cpu.accm, 15);
|
|
hmask = _mm_srai_epi16(device.rsp.cpu.acch, 15);
|
|
md = _mm_or_si128(mmask, device.rsp.cpu.accm);
|
|
omask = _mm_cmpgt_epi16(device.rsp.cpu.acch, _mm_setzero_si128());
|
|
md = _mm_andnot_si128(hmask, md);
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] = std::mem::transmute(_mm_or_si128(omask, md));
|
|
}
|
|
}
|
|
|
|
pub fn vrndn(device: &mut device::Device, opcode: u32) {
|
|
let vte = unsafe {
|
|
std::mem::transmute(vte(
|
|
device.rsp.cpu.vpr[vt(opcode) as usize],
|
|
ve(opcode) as usize,
|
|
))
|
|
};
|
|
let acch: &mut u128 = unsafe { std::mem::transmute(&mut device.rsp.cpu.acch) };
|
|
let accm: &mut u128 = unsafe { std::mem::transmute(&mut device.rsp.cpu.accm) };
|
|
let accl: &mut u128 = unsafe { std::mem::transmute(&mut device.rsp.cpu.accl) };
|
|
|
|
let mut n = 0;
|
|
while n < 8 {
|
|
let mut product = get_vpr_element(vte, n) as i16 as i32;
|
|
if vs(opcode) & 1 != 0 {
|
|
product <<= 16
|
|
}
|
|
let mut acc = 0;
|
|
acc |= get_vpr_element(*acch, n) as i64;
|
|
acc <<= 16;
|
|
acc |= get_vpr_element(*accm, n) as i64;
|
|
acc <<= 16;
|
|
acc |= get_vpr_element(*accl, n) as i64;
|
|
acc <<= 16;
|
|
acc >>= 16;
|
|
if acc < 0 {
|
|
acc = s_clip(acc + (product as i64), 48)
|
|
}
|
|
modify_vpr_element(acch, (acc >> 32) as u16, n);
|
|
modify_vpr_element(accm, (acc >> 16) as u16, n);
|
|
modify_vpr_element(accl, acc as u16, n);
|
|
modify_vpr_element(
|
|
&mut device.rsp.cpu.vpr[vd(opcode) as usize],
|
|
clamp_signed_64(acc >> 16) as u16,
|
|
n,
|
|
);
|
|
|
|
n += 1;
|
|
}
|
|
}
|
|
|
|
pub fn vmacq(device: &mut device::Device, opcode: u32) {
|
|
let acch: &mut u128 = unsafe { std::mem::transmute(&mut device.rsp.cpu.acch) };
|
|
let accm: &mut u128 = unsafe { std::mem::transmute(&mut device.rsp.cpu.accm) };
|
|
|
|
let mut n = 0;
|
|
while n < 8 {
|
|
let mut product =
|
|
(get_vpr_element(*acch, n) as i32) << 16 | (get_vpr_element(*accm, n) as i32);
|
|
if product < 0 && (product & (1 << 5)) == 0 {
|
|
product += 32
|
|
} else if product >= 32 && (product & (1 << 5)) == 0 {
|
|
product -= 32
|
|
}
|
|
modify_vpr_element(acch, (product >> 16) as u16, n);
|
|
modify_vpr_element(accm, (product) as u16, n);
|
|
modify_vpr_element(
|
|
&mut device.rsp.cpu.vpr[vd(opcode) as usize],
|
|
(clamp_signed_32(product >> 1) & !15) as u16,
|
|
n,
|
|
);
|
|
n += 1;
|
|
}
|
|
}
|
|
|
|
pub fn vmadl(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
let (mut hi, mut omask, nhi, nmd, shi, smd, cmask, cval);
|
|
unsafe {
|
|
hi = _mm_mulhi_epu16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
omask = _mm_adds_epu16(device.rsp.cpu.accl, hi);
|
|
device.rsp.cpu.accl = _mm_add_epi16(device.rsp.cpu.accl, hi);
|
|
omask = _mm_cmpeq_epi16(device.rsp.cpu.accl, omask);
|
|
omask = _mm_cmpeq_epi16(omask, _mm_setzero_si128());
|
|
hi = _mm_sub_epi16(_mm_setzero_si128(), omask);
|
|
omask = _mm_adds_epu16(device.rsp.cpu.accm, hi);
|
|
device.rsp.cpu.accm = _mm_add_epi16(device.rsp.cpu.accm, hi);
|
|
omask = _mm_cmpeq_epi16(device.rsp.cpu.accm, omask);
|
|
omask = _mm_cmpeq_epi16(omask, _mm_setzero_si128());
|
|
device.rsp.cpu.acch = _mm_sub_epi16(device.rsp.cpu.acch, omask);
|
|
nhi = _mm_srai_epi16(device.rsp.cpu.acch, 15);
|
|
nmd = _mm_srai_epi16(device.rsp.cpu.accm, 15);
|
|
shi = _mm_cmpeq_epi16(nhi, device.rsp.cpu.acch);
|
|
smd = _mm_cmpeq_epi16(nhi, nmd);
|
|
cmask = _mm_and_si128(smd, shi);
|
|
cval = _mm_cmpeq_epi16(nhi, _mm_setzero_si128());
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] =
|
|
std::mem::transmute(_mm_blendv_epi8(cval, device.rsp.cpu.accl, cmask));
|
|
}
|
|
}
|
|
|
|
pub fn vmadm(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
let (mut lo, mut hi, sign, vta, mut omask);
|
|
unsafe {
|
|
lo = _mm_mullo_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
hi = _mm_mulhi_epu16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
sign = _mm_srai_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
15,
|
|
);
|
|
vta = _mm_and_si128(vte, sign);
|
|
hi = _mm_sub_epi16(hi, vta);
|
|
omask = _mm_adds_epu16(device.rsp.cpu.accl, lo);
|
|
device.rsp.cpu.accl = _mm_add_epi16(device.rsp.cpu.accl, lo);
|
|
omask = _mm_cmpeq_epi16(device.rsp.cpu.accl, omask);
|
|
omask = _mm_cmpeq_epi16(omask, _mm_setzero_si128());
|
|
hi = _mm_sub_epi16(hi, omask);
|
|
omask = _mm_adds_epu16(device.rsp.cpu.accm, hi);
|
|
device.rsp.cpu.accm = _mm_add_epi16(device.rsp.cpu.accm, hi);
|
|
omask = _mm_cmpeq_epi16(device.rsp.cpu.accm, omask);
|
|
omask = _mm_cmpeq_epi16(omask, _mm_setzero_si128());
|
|
hi = _mm_srai_epi16(hi, 15);
|
|
device.rsp.cpu.acch = _mm_add_epi16(device.rsp.cpu.acch, hi);
|
|
device.rsp.cpu.acch = _mm_sub_epi16(device.rsp.cpu.acch, omask);
|
|
lo = _mm_unpacklo_epi16(device.rsp.cpu.accm, device.rsp.cpu.acch);
|
|
hi = _mm_unpackhi_epi16(device.rsp.cpu.accm, device.rsp.cpu.acch);
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] = std::mem::transmute(_mm_packs_epi32(lo, hi));
|
|
}
|
|
}
|
|
|
|
pub fn vmadn(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
let (lo, mut hi, sign, vsa, mut omask, nhi, nmd, shi, smd, cmask, cval);
|
|
unsafe {
|
|
lo = _mm_mullo_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
hi = _mm_mulhi_epu16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
sign = _mm_srai_epi16(vte, 15);
|
|
vsa = _mm_and_si128(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
sign,
|
|
);
|
|
hi = _mm_sub_epi16(hi, vsa);
|
|
omask = _mm_adds_epu16(device.rsp.cpu.accl, lo);
|
|
device.rsp.cpu.accl = _mm_add_epi16(device.rsp.cpu.accl, lo);
|
|
omask = _mm_cmpeq_epi16(device.rsp.cpu.accl, omask);
|
|
omask = _mm_cmpeq_epi16(omask, _mm_setzero_si128());
|
|
hi = _mm_sub_epi16(hi, omask);
|
|
omask = _mm_adds_epu16(device.rsp.cpu.accm, hi);
|
|
device.rsp.cpu.accm = _mm_add_epi16(device.rsp.cpu.accm, hi);
|
|
omask = _mm_cmpeq_epi16(device.rsp.cpu.accm, omask);
|
|
omask = _mm_cmpeq_epi16(omask, _mm_setzero_si128());
|
|
hi = _mm_srai_epi16(hi, 15);
|
|
device.rsp.cpu.acch = _mm_add_epi16(device.rsp.cpu.acch, hi);
|
|
device.rsp.cpu.acch = _mm_sub_epi16(device.rsp.cpu.acch, omask);
|
|
nhi = _mm_srai_epi16(device.rsp.cpu.acch, 15);
|
|
nmd = _mm_srai_epi16(device.rsp.cpu.accm, 15);
|
|
shi = _mm_cmpeq_epi16(nhi, device.rsp.cpu.acch);
|
|
smd = _mm_cmpeq_epi16(nhi, nmd);
|
|
cmask = _mm_and_si128(smd, shi);
|
|
cval = _mm_cmpeq_epi16(nhi, _mm_setzero_si128());
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] =
|
|
std::mem::transmute(_mm_blendv_epi8(cval, device.rsp.cpu.accl, cmask));
|
|
}
|
|
}
|
|
|
|
pub fn vmadh(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
let (mut lo, mut hi, mut omask);
|
|
unsafe {
|
|
lo = _mm_mullo_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
hi = _mm_mulhi_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
omask = _mm_adds_epu16(device.rsp.cpu.accm, lo);
|
|
device.rsp.cpu.accm = _mm_add_epi16(device.rsp.cpu.accm, lo);
|
|
omask = _mm_cmpeq_epi16(device.rsp.cpu.accm, omask);
|
|
omask = _mm_cmpeq_epi16(omask, _mm_setzero_si128());
|
|
hi = _mm_sub_epi16(hi, omask);
|
|
device.rsp.cpu.acch = _mm_add_epi16(device.rsp.cpu.acch, hi);
|
|
lo = _mm_unpacklo_epi16(device.rsp.cpu.accm, device.rsp.cpu.acch);
|
|
hi = _mm_unpackhi_epi16(device.rsp.cpu.accm, device.rsp.cpu.acch);
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] = std::mem::transmute(_mm_packs_epi32(lo, hi));
|
|
}
|
|
}
|
|
|
|
pub fn vadd(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
let (sum, mut min, max);
|
|
unsafe {
|
|
sum = _mm_add_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
device.rsp.cpu.accl = _mm_sub_epi16(sum, device.rsp.cpu.vcol);
|
|
min = _mm_min_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
max = _mm_max_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
min = _mm_subs_epi16(min, device.rsp.cpu.vcol);
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] = std::mem::transmute(_mm_adds_epi16(min, max));
|
|
device.rsp.cpu.vcol = _mm_setzero_si128();
|
|
device.rsp.cpu.vcoh = _mm_setzero_si128();
|
|
}
|
|
}
|
|
|
|
pub fn vsub(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
let (udiff, sdiff, ov);
|
|
unsafe {
|
|
udiff = _mm_sub_epi16(vte, device.rsp.cpu.vcol);
|
|
sdiff = _mm_subs_epi16(vte, device.rsp.cpu.vcol);
|
|
device.rsp.cpu.accl = _mm_sub_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
udiff,
|
|
);
|
|
ov = _mm_cmpgt_epi16(sdiff, udiff);
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] = std::mem::transmute(_mm_subs_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
sdiff,
|
|
));
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] = std::mem::transmute(_mm_adds_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vd(opcode) as usize]),
|
|
ov,
|
|
));
|
|
device.rsp.cpu.vcol = _mm_setzero_si128();
|
|
device.rsp.cpu.vcoh = _mm_setzero_si128();
|
|
}
|
|
}
|
|
|
|
pub fn vzero(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
unsafe {
|
|
device.rsp.cpu.accl = _mm_add_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] = std::mem::transmute(_mm_xor_si128(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vd(opcode) as usize]),
|
|
std::mem::transmute(device.rsp.cpu.vpr[vd(opcode) as usize]),
|
|
));
|
|
}
|
|
}
|
|
|
|
pub fn vabs(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
let (vs0, slt);
|
|
unsafe {
|
|
vs0 = _mm_cmpeq_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
_mm_setzero_si128(),
|
|
);
|
|
slt = _mm_srai_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
15,
|
|
);
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] = std::mem::transmute(_mm_andnot_si128(vs0, vte));
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] = std::mem::transmute(_mm_xor_si128(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vd(opcode) as usize]),
|
|
slt,
|
|
));
|
|
device.rsp.cpu.accl = _mm_sub_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vd(opcode) as usize]),
|
|
slt,
|
|
);
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] = std::mem::transmute(_mm_subs_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vd(opcode) as usize]),
|
|
slt,
|
|
));
|
|
}
|
|
}
|
|
|
|
pub fn vaddc(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
let sum;
|
|
unsafe {
|
|
sum = _mm_adds_epu16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
device.rsp.cpu.accl = _mm_add_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
device.rsp.cpu.vcol = _mm_cmpeq_epi16(sum, device.rsp.cpu.accl);
|
|
device.rsp.cpu.vcol = _mm_cmpeq_epi16(device.rsp.cpu.vcol, _mm_setzero_si128());
|
|
device.rsp.cpu.vcoh = _mm_setzero_si128();
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] = std::mem::transmute(device.rsp.cpu.accl);
|
|
}
|
|
}
|
|
|
|
pub fn vsubc(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
let (equal, udiff, diff0);
|
|
unsafe {
|
|
udiff = _mm_subs_epu16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
equal = _mm_cmpeq_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
diff0 = _mm_cmpeq_epi16(udiff, _mm_setzero_si128());
|
|
device.rsp.cpu.vcoh = _mm_cmpeq_epi16(equal, _mm_setzero_si128());
|
|
device.rsp.cpu.vcol = _mm_andnot_si128(equal, diff0);
|
|
device.rsp.cpu.accl = _mm_sub_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] = std::mem::transmute(device.rsp.cpu.accl);
|
|
}
|
|
}
|
|
|
|
pub fn vsar(device: &mut device::Device, opcode: u32) {
|
|
match ve(opcode) {
|
|
0x8 => {
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] =
|
|
unsafe { std::mem::transmute(device.rsp.cpu.acch) };
|
|
}
|
|
0x9 => {
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] =
|
|
unsafe { std::mem::transmute(device.rsp.cpu.accm) };
|
|
}
|
|
0xa => {
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] =
|
|
unsafe { std::mem::transmute(device.rsp.cpu.accl) };
|
|
}
|
|
_ => {
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn vlt(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
let (mut eq, lt);
|
|
unsafe {
|
|
eq = _mm_cmpeq_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
lt = _mm_cmplt_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
eq = _mm_and_si128(device.rsp.cpu.vcoh, eq);
|
|
eq = _mm_and_si128(device.rsp.cpu.vcol, eq);
|
|
device.rsp.cpu.vccl = _mm_or_si128(lt, eq);
|
|
device.rsp.cpu.accl = _mm_blendv_epi8(
|
|
vte,
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
device.rsp.cpu.vccl,
|
|
);
|
|
device.rsp.cpu.vcch = _mm_setzero_si128();
|
|
device.rsp.cpu.vcoh = _mm_setzero_si128();
|
|
device.rsp.cpu.vcol = _mm_setzero_si128();
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] = std::mem::transmute(device.rsp.cpu.accl);
|
|
}
|
|
}
|
|
|
|
pub fn veq(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
let eq;
|
|
unsafe {
|
|
eq = _mm_cmpeq_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
device.rsp.cpu.vccl = _mm_andnot_si128(device.rsp.cpu.vcoh, eq);
|
|
device.rsp.cpu.accl = _mm_blendv_epi8(
|
|
vte,
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
device.rsp.cpu.vccl,
|
|
);
|
|
device.rsp.cpu.vcch = _mm_setzero_si128(); //unverified
|
|
device.rsp.cpu.vcoh = _mm_setzero_si128();
|
|
device.rsp.cpu.vcol = _mm_setzero_si128();
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] = std::mem::transmute(device.rsp.cpu.accl);
|
|
}
|
|
}
|
|
|
|
pub fn vne(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
let (eq, ne);
|
|
unsafe {
|
|
eq = _mm_cmpeq_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
ne = _mm_cmpeq_epi16(eq, _mm_setzero_si128());
|
|
device.rsp.cpu.vccl = _mm_and_si128(device.rsp.cpu.vcoh, eq);
|
|
device.rsp.cpu.vccl = _mm_or_si128(device.rsp.cpu.vccl, ne);
|
|
device.rsp.cpu.accl = _mm_blendv_epi8(
|
|
vte,
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
device.rsp.cpu.vccl,
|
|
);
|
|
device.rsp.cpu.vcch = _mm_setzero_si128();
|
|
device.rsp.cpu.vcoh = _mm_setzero_si128();
|
|
device.rsp.cpu.vcol = _mm_setzero_si128();
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] = std::mem::transmute(device.rsp.cpu.accl);
|
|
}
|
|
}
|
|
|
|
pub fn vge(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
let (mut eq, gt, es);
|
|
unsafe {
|
|
eq = _mm_cmpeq_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
gt = _mm_cmpgt_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
es = _mm_and_si128(device.rsp.cpu.vcoh, device.rsp.cpu.vcol);
|
|
eq = _mm_andnot_si128(es, eq);
|
|
device.rsp.cpu.vccl = _mm_or_si128(gt, eq);
|
|
device.rsp.cpu.accl = _mm_blendv_epi8(
|
|
vte,
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
device.rsp.cpu.vccl,
|
|
);
|
|
device.rsp.cpu.vcch = _mm_setzero_si128();
|
|
device.rsp.cpu.vcoh = _mm_setzero_si128();
|
|
device.rsp.cpu.vcol = _mm_setzero_si128();
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] = std::mem::transmute(device.rsp.cpu.accl);
|
|
}
|
|
}
|
|
|
|
pub fn vcl(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
let (
|
|
mut nvt,
|
|
diff,
|
|
mut ncarry,
|
|
nvce,
|
|
diff0,
|
|
mut lec1,
|
|
mut lec2,
|
|
leeq,
|
|
mut geeq,
|
|
mut le,
|
|
mut ge,
|
|
mask,
|
|
);
|
|
unsafe {
|
|
nvt = _mm_xor_si128(vte, device.rsp.cpu.vcol);
|
|
nvt = _mm_sub_epi16(nvt, device.rsp.cpu.vcol);
|
|
diff = _mm_sub_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
nvt,
|
|
);
|
|
ncarry = _mm_adds_epu16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
ncarry = _mm_cmpeq_epi16(diff, ncarry);
|
|
nvce = _mm_cmpeq_epi16(device.rsp.cpu.vce, _mm_setzero_si128());
|
|
diff0 = _mm_cmpeq_epi16(diff, _mm_setzero_si128());
|
|
lec1 = _mm_and_si128(diff0, ncarry);
|
|
lec1 = _mm_and_si128(nvce, lec1);
|
|
lec2 = _mm_or_si128(diff0, ncarry);
|
|
lec2 = _mm_and_si128(device.rsp.cpu.vce, lec2);
|
|
leeq = _mm_or_si128(lec1, lec2);
|
|
geeq = _mm_subs_epu16(
|
|
vte,
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
);
|
|
geeq = _mm_cmpeq_epi16(geeq, _mm_setzero_si128());
|
|
le = _mm_andnot_si128(device.rsp.cpu.vcoh, device.rsp.cpu.vcol);
|
|
le = _mm_blendv_epi8(device.rsp.cpu.vccl, leeq, le);
|
|
ge = _mm_or_si128(device.rsp.cpu.vcol, device.rsp.cpu.vcoh);
|
|
ge = _mm_blendv_epi8(geeq, device.rsp.cpu.vcch, ge);
|
|
mask = _mm_blendv_epi8(ge, le, device.rsp.cpu.vcol);
|
|
device.rsp.cpu.accl = _mm_blendv_epi8(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
nvt,
|
|
mask,
|
|
);
|
|
device.rsp.cpu.vcch = ge;
|
|
device.rsp.cpu.vccl = le;
|
|
device.rsp.cpu.vcoh = _mm_setzero_si128();
|
|
device.rsp.cpu.vcol = _mm_setzero_si128();
|
|
device.rsp.cpu.vce = _mm_setzero_si128();
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] = std::mem::transmute(device.rsp.cpu.accl);
|
|
}
|
|
}
|
|
|
|
pub fn vch(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
let (mut nvt, diff, diff0, vtn, mut dlez, dgez, mask);
|
|
unsafe {
|
|
device.rsp.cpu.vcol = _mm_xor_si128(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
device.rsp.cpu.vcol = _mm_cmplt_epi16(device.rsp.cpu.vcol, _mm_setzero_si128());
|
|
nvt = _mm_xor_si128(vte, device.rsp.cpu.vcol);
|
|
nvt = _mm_sub_epi16(nvt, device.rsp.cpu.vcol);
|
|
diff = _mm_sub_epi16(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
nvt,
|
|
);
|
|
diff0 = _mm_cmpeq_epi16(diff, _mm_setzero_si128());
|
|
vtn = _mm_cmplt_epi16(vte, _mm_setzero_si128());
|
|
dlez = _mm_cmpgt_epi16(diff, _mm_setzero_si128());
|
|
dgez = _mm_or_si128(dlez, diff0);
|
|
dlez = _mm_cmpeq_epi16(_mm_setzero_si128(), dlez);
|
|
device.rsp.cpu.vcch = _mm_blendv_epi8(dgez, vtn, device.rsp.cpu.vcol);
|
|
device.rsp.cpu.vccl = _mm_blendv_epi8(vtn, dlez, device.rsp.cpu.vcol);
|
|
device.rsp.cpu.vce = _mm_cmpeq_epi16(diff, device.rsp.cpu.vcol);
|
|
device.rsp.cpu.vce = _mm_and_si128(device.rsp.cpu.vce, device.rsp.cpu.vcol);
|
|
device.rsp.cpu.vcoh = _mm_or_si128(diff0, device.rsp.cpu.vce);
|
|
device.rsp.cpu.vcoh = _mm_cmpeq_epi16(device.rsp.cpu.vcoh, _mm_setzero_si128());
|
|
mask = _mm_blendv_epi8(
|
|
device.rsp.cpu.vcch,
|
|
device.rsp.cpu.vccl,
|
|
device.rsp.cpu.vcol,
|
|
);
|
|
device.rsp.cpu.accl = _mm_blendv_epi8(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
nvt,
|
|
mask,
|
|
);
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] = std::mem::transmute(device.rsp.cpu.accl);
|
|
}
|
|
}
|
|
|
|
pub fn vcr(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
let (mut sign, mut dlez, mut dgez, nvt, mask);
|
|
unsafe {
|
|
sign = _mm_xor_si128(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
sign = _mm_srai_epi16(sign, 15);
|
|
dlez = _mm_and_si128(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
sign,
|
|
);
|
|
dlez = _mm_add_epi16(dlez, vte);
|
|
device.rsp.cpu.vccl = _mm_srai_epi16(dlez, 15);
|
|
dgez = _mm_or_si128(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
sign,
|
|
);
|
|
dgez = _mm_min_epi16(dgez, vte);
|
|
device.rsp.cpu.vcch = _mm_cmpeq_epi16(dgez, vte);
|
|
nvt = _mm_xor_si128(vte, sign);
|
|
mask = _mm_blendv_epi8(device.rsp.cpu.vcch, device.rsp.cpu.vccl, sign);
|
|
device.rsp.cpu.accl = _mm_blendv_epi8(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
nvt,
|
|
mask,
|
|
);
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] = std::mem::transmute(device.rsp.cpu.accl);
|
|
device.rsp.cpu.vcol = _mm_setzero_si128();
|
|
device.rsp.cpu.vcoh = _mm_setzero_si128();
|
|
device.rsp.cpu.vce = _mm_setzero_si128();
|
|
}
|
|
}
|
|
|
|
pub fn vmrg(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
unsafe {
|
|
device.rsp.cpu.accl = _mm_blendv_epi8(
|
|
vte,
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
device.rsp.cpu.vccl,
|
|
);
|
|
device.rsp.cpu.vcoh = _mm_setzero_si128();
|
|
device.rsp.cpu.vcol = _mm_setzero_si128();
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] = std::mem::transmute(device.rsp.cpu.accl);
|
|
}
|
|
}
|
|
|
|
pub fn vand(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
unsafe {
|
|
device.rsp.cpu.accl = _mm_and_si128(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] = std::mem::transmute(device.rsp.cpu.accl);
|
|
}
|
|
}
|
|
|
|
pub fn vnand(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
unsafe {
|
|
device.rsp.cpu.accl = _mm_and_si128(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
device.rsp.cpu.accl = _mm_xor_si128(device.rsp.cpu.accl, _mm_set1_epi32(-1));
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] = std::mem::transmute(device.rsp.cpu.accl);
|
|
}
|
|
}
|
|
|
|
pub fn vor(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
unsafe {
|
|
device.rsp.cpu.accl = _mm_or_si128(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] = std::mem::transmute(device.rsp.cpu.accl);
|
|
}
|
|
}
|
|
|
|
pub fn vnor(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
unsafe {
|
|
device.rsp.cpu.accl = _mm_or_si128(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
device.rsp.cpu.accl = _mm_xor_si128(device.rsp.cpu.accl, _mm_set1_epi32(-1));
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] = std::mem::transmute(device.rsp.cpu.accl);
|
|
}
|
|
}
|
|
|
|
pub fn vxor(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
unsafe {
|
|
device.rsp.cpu.accl = _mm_xor_si128(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] = std::mem::transmute(device.rsp.cpu.accl);
|
|
}
|
|
}
|
|
|
|
pub fn vnxor(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
unsafe {
|
|
device.rsp.cpu.accl = _mm_xor_si128(
|
|
std::mem::transmute(device.rsp.cpu.vpr[vs(opcode) as usize]),
|
|
vte,
|
|
);
|
|
device.rsp.cpu.accl = _mm_xor_si128(device.rsp.cpu.accl, _mm_set1_epi32(-1));
|
|
device.rsp.cpu.vpr[vd(opcode) as usize] = std::mem::transmute(device.rsp.cpu.accl);
|
|
}
|
|
}
|
|
|
|
pub fn vrcp(device: &mut device::Device, opcode: u32) {
|
|
let mut result;
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
let input =
|
|
get_vpr_element(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as u8) as i16 as i32;
|
|
let mask = input >> 31;
|
|
let mut data = input ^ mask;
|
|
if input > -32768 {
|
|
data -= mask
|
|
}
|
|
if data == 0 {
|
|
result = 0x7fffffff
|
|
} else if input == -32768 {
|
|
result = 0xffff0000
|
|
} else {
|
|
let shift = count_leading_zeros(data as u32);
|
|
let index = (((data as u64) << shift) & 0x7fc00000) >> 22;
|
|
result = device.rsp.cpu.reciprocals[index as usize] as u32;
|
|
result = (0x10000 | result) << 14;
|
|
result = (result >> (31 - shift)) ^ mask as u32
|
|
}
|
|
device.rsp.cpu.divdp = false;
|
|
device.rsp.cpu.divout = (result >> 16) as i16;
|
|
device.rsp.cpu.accl = vte;
|
|
modify_vpr_element(
|
|
&mut device.rsp.cpu.vpr[vd(opcode) as usize],
|
|
result as u16,
|
|
de(opcode) as u8,
|
|
);
|
|
}
|
|
|
|
pub fn vrcpl(device: &mut device::Device, opcode: u32) {
|
|
let mut result;
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
let input;
|
|
if device.rsp.cpu.divdp {
|
|
input = (device.rsp.cpu.divin as i32) << 16
|
|
| get_vpr_element(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as u8) as u16
|
|
as i32
|
|
} else {
|
|
input = get_vpr_element(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as u8) as i16
|
|
as i32;
|
|
}
|
|
let mask = input >> 31;
|
|
let mut data = input ^ mask;
|
|
if input > -32768 {
|
|
data -= mask
|
|
}
|
|
if data == 0 {
|
|
result = 0x7fffffff
|
|
} else if input == -32768 {
|
|
result = 0xffff0000
|
|
} else {
|
|
let shift = count_leading_zeros(data as u32);
|
|
let index = (((data as u64) << shift) & 0x7fc00000) >> 22;
|
|
result = device.rsp.cpu.reciprocals[index as usize] as u32;
|
|
result = (0x10000 | result) << 14;
|
|
result = (result >> (31 - shift)) ^ mask as u32
|
|
}
|
|
device.rsp.cpu.divdp = false;
|
|
device.rsp.cpu.divout = (result >> 16) as i16;
|
|
device.rsp.cpu.accl = vte;
|
|
modify_vpr_element(
|
|
&mut device.rsp.cpu.vpr[vd(opcode) as usize],
|
|
result as u16,
|
|
de(opcode) as u8,
|
|
);
|
|
}
|
|
|
|
pub fn vrcph(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
device.rsp.cpu.accl = vte;
|
|
device.rsp.cpu.divdp = true;
|
|
|
|
device.rsp.cpu.divin =
|
|
get_vpr_element(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as u8) as i16;
|
|
modify_vpr_element(
|
|
&mut device.rsp.cpu.vpr[vd(opcode) as usize],
|
|
device.rsp.cpu.divout as u16,
|
|
de(opcode) as u8,
|
|
);
|
|
}
|
|
|
|
pub fn vmov(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
let value = get_vpr_element(unsafe { std::mem::transmute(vte) }, de(opcode) as u8);
|
|
modify_vpr_element(
|
|
&mut device.rsp.cpu.vpr[vd(opcode) as usize],
|
|
value,
|
|
de(opcode) as u8,
|
|
);
|
|
device.rsp.cpu.accl = vte;
|
|
}
|
|
|
|
pub fn vrsq(device: &mut device::Device, opcode: u32) {
|
|
let mut result;
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
let input =
|
|
get_vpr_element(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as u8) as i16 as i32;
|
|
let mask = input >> 31;
|
|
let mut data = input ^ mask;
|
|
if input > -32768 {
|
|
data -= mask
|
|
}
|
|
if data == 0 {
|
|
result = 0x7fffffff
|
|
} else if input == -32768 {
|
|
result = 0xffff0000
|
|
} else {
|
|
let shift = count_leading_zeros(data as u32);
|
|
let index = (((data as u64) << shift) & 0x7fc00000) as u32 >> 22;
|
|
result =
|
|
(device.rsp.cpu.inverse_square_roots[((index & 0x1fe) | (shift & 1)) as usize]) as u32;
|
|
result = (0x10000 | result) << 14;
|
|
result = (result >> ((31 - shift) >> 1)) ^ mask as u32
|
|
}
|
|
device.rsp.cpu.divdp = false;
|
|
device.rsp.cpu.divout = (result >> 16) as i16;
|
|
device.rsp.cpu.accl = vte;
|
|
modify_vpr_element(
|
|
&mut device.rsp.cpu.vpr[vd(opcode) as usize],
|
|
result as u16,
|
|
de(opcode) as u8,
|
|
);
|
|
}
|
|
|
|
pub fn vrsql(device: &mut device::Device, opcode: u32) {
|
|
let mut result;
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
let input;
|
|
if device.rsp.cpu.divdp {
|
|
input = (device.rsp.cpu.divin as i32) << 16
|
|
| get_vpr_element(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as u8) as u16
|
|
as i32;
|
|
} else {
|
|
input = get_vpr_element(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as u8) as i16
|
|
as i32;
|
|
}
|
|
let mask = input >> 31;
|
|
let mut data = input ^ mask;
|
|
if input > -32768 {
|
|
data -= mask
|
|
}
|
|
if data == 0 {
|
|
result = 0x7fffffff
|
|
} else if input == -32768 {
|
|
result = 0xffff0000
|
|
} else {
|
|
let shift = count_leading_zeros(data as u32);
|
|
let index = (((data as u64) << shift) & 0x7fc00000) as u32 >> 22;
|
|
result =
|
|
(device.rsp.cpu.inverse_square_roots[((index & 0x1fe) | (shift & 1)) as usize]) as u32;
|
|
result = (0x10000 | result) << 14;
|
|
result = (result >> ((31 - shift) >> 1)) ^ mask as u32
|
|
}
|
|
device.rsp.cpu.divdp = false;
|
|
device.rsp.cpu.divout = (result >> 16) as i16;
|
|
device.rsp.cpu.accl = vte;
|
|
modify_vpr_element(
|
|
&mut device.rsp.cpu.vpr[vd(opcode) as usize],
|
|
result as u16,
|
|
de(opcode) as u8,
|
|
);
|
|
}
|
|
|
|
pub fn vrsqh(device: &mut device::Device, opcode: u32) {
|
|
let vte = vte(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as usize);
|
|
device.rsp.cpu.accl = vte;
|
|
device.rsp.cpu.divdp = true;
|
|
|
|
device.rsp.cpu.divin =
|
|
get_vpr_element(device.rsp.cpu.vpr[vt(opcode) as usize], ve(opcode) as u8) as i16;
|
|
modify_vpr_element(
|
|
&mut device.rsp.cpu.vpr[vd(opcode) as usize],
|
|
device.rsp.cpu.divout as u16,
|
|
de(opcode) as u8,
|
|
);
|
|
}
|
|
|
|
pub fn vnop(_device: &mut device::Device, _opcode: u32) {}
|
|
|
|
pub fn execute_vec(device: &mut device::Device, opcode: u32) {
|
|
device.rsp.cpu.vec_instrs[(opcode & 0x3F) as usize](device, opcode)
|
|
}
|
|
|
|
pub fn reserved(_device: &mut device::Device, _opcode: u32) {
|
|
panic!("rsp vu reserved")
|
|
}
|