This repository has been archived on 2026-08-27. You can view files and clone it, but cannot push or open issues or pull requests.
gopher64-netplay/src/device/rsp_su_instructions.rs
Logan McNaughton 1bcadb3a8b
remove un-needed mut (#333)
* remove un-needed mut

* more

* more
2025-03-16 09:48:32 +01:00

1214 lines
42 KiB
Rust

#[cfg(target_arch = "aarch64")]
use device::__m128i;
#[cfg(target_arch = "aarch64")]
include!(concat!(env!("OUT_DIR"), "/simd_bindings.rs"));
#[cfg(target_arch = "aarch64")]
include!("../compat/aarch64.rs");
use crate::device;
#[cfg(target_arch = "x86_64")]
use std::arch::x86_64::*;
fn rd(opcode: u32) -> u32 {
(opcode >> 11) & 0x1F
}
fn rs(opcode: u32) -> u32 {
(opcode >> 21) & 0x1F
}
fn rt(opcode: u32) -> u32 {
(opcode >> 16) & 0x1F
}
fn sa(opcode: u32) -> u32 {
(opcode >> 6) & 0x1F
}
fn imm(opcode: u32) -> u16 {
opcode as u16
}
fn se16(value: i16) -> u32 {
value as i32 as u32
}
fn voffset(opcode: u32) -> u8 {
(opcode & 0x7F) as u8
}
fn velement(opcode: u32) -> u8 {
((opcode >> 7) & 0xF) as u8
}
fn sign_extend_7bit_offset(offset: u8, shift_amount: u32) -> u32 {
let soffset = (((offset << 1) & 0x80) | offset) as i8;
(((soffset) as i32) as u32) << shift_amount
}
fn modify_vpr8(vpr: &mut __m128i, element: u8, value: u8) {
unsafe {
*vpr = match element & 15 {
0 => _mm_insert_epi8(*vpr, value as i32, 15),
1 => _mm_insert_epi8(*vpr, value as i32, 14),
2 => _mm_insert_epi8(*vpr, value as i32, 13),
3 => _mm_insert_epi8(*vpr, value as i32, 12),
4 => _mm_insert_epi8(*vpr, value as i32, 11),
5 => _mm_insert_epi8(*vpr, value as i32, 10),
6 => _mm_insert_epi8(*vpr, value as i32, 9),
7 => _mm_insert_epi8(*vpr, value as i32, 8),
8 => _mm_insert_epi8(*vpr, value as i32, 7),
9 => _mm_insert_epi8(*vpr, value as i32, 6),
10 => _mm_insert_epi8(*vpr, value as i32, 5),
11 => _mm_insert_epi8(*vpr, value as i32, 4),
12 => _mm_insert_epi8(*vpr, value as i32, 3),
13 => _mm_insert_epi8(*vpr, value as i32, 2),
14 => _mm_insert_epi8(*vpr, value as i32, 1),
15 => _mm_insert_epi8(*vpr, value as i32, 0),
_ => unreachable!(),
};
}
}
fn get_vpr8(vpr: __m128i, element: u8) -> u8 {
unsafe {
match element & 15 {
0 => _mm_extract_epi8(vpr, 15) as u8,
1 => _mm_extract_epi8(vpr, 14) as u8,
2 => _mm_extract_epi8(vpr, 13) as u8,
3 => _mm_extract_epi8(vpr, 12) as u8,
4 => _mm_extract_epi8(vpr, 11) as u8,
5 => _mm_extract_epi8(vpr, 10) as u8,
6 => _mm_extract_epi8(vpr, 9) as u8,
7 => _mm_extract_epi8(vpr, 8) as u8,
8 => _mm_extract_epi8(vpr, 7) as u8,
9 => _mm_extract_epi8(vpr, 6) as u8,
10 => _mm_extract_epi8(vpr, 5) as u8,
11 => _mm_extract_epi8(vpr, 4) as u8,
12 => _mm_extract_epi8(vpr, 3) as u8,
13 => _mm_extract_epi8(vpr, 2) as u8,
14 => _mm_extract_epi8(vpr, 1) as u8,
15 => _mm_extract_epi8(vpr, 0) as u8,
_ => unreachable!(),
}
}
}
pub fn modify_vpr16(vpr: &mut __m128i, element: u8, value: u16) {
unsafe {
*vpr = match element & 7 {
0 => _mm_insert_epi16(*vpr, value as i32, 7),
1 => _mm_insert_epi16(*vpr, value as i32, 6),
2 => _mm_insert_epi16(*vpr, value as i32, 5),
3 => _mm_insert_epi16(*vpr, value as i32, 4),
4 => _mm_insert_epi16(*vpr, value as i32, 3),
5 => _mm_insert_epi16(*vpr, value as i32, 2),
6 => _mm_insert_epi16(*vpr, value as i32, 1),
7 => _mm_insert_epi16(*vpr, value as i32, 0),
_ => unreachable!(),
};
}
}
pub fn get_vpr16(vpr: __m128i, element: u8) -> u16 {
unsafe {
match element & 7 {
0 => _mm_extract_epi16(vpr, 7) as u16,
1 => _mm_extract_epi16(vpr, 6) as u16,
2 => _mm_extract_epi16(vpr, 5) as u16,
3 => _mm_extract_epi16(vpr, 4) as u16,
4 => _mm_extract_epi16(vpr, 3) as u16,
5 => _mm_extract_epi16(vpr, 2) as u16,
6 => _mm_extract_epi16(vpr, 1) as u16,
7 => _mm_extract_epi16(vpr, 0) as u16,
_ => unreachable!(),
}
}
}
fn modify_vpr32(vpr: &mut __m128i, element: u8, value: u32) {
unsafe {
*vpr = match element & 3 {
0 => _mm_insert_epi32(*vpr, value as i32, 3),
1 => _mm_insert_epi32(*vpr, value as i32, 2),
2 => _mm_insert_epi32(*vpr, value as i32, 1),
3 => _mm_insert_epi32(*vpr, value as i32, 0),
_ => unreachable!(),
};
}
}
fn get_vpr32(vpr: __m128i, element: u8) -> u32 {
unsafe {
match element & 3 {
0 => _mm_extract_epi32(vpr, 3) as u32,
1 => _mm_extract_epi32(vpr, 2) as u32,
2 => _mm_extract_epi32(vpr, 1) as u32,
3 => _mm_extract_epi32(vpr, 0) as u32,
_ => unreachable!(),
}
}
}
fn modify_vpr64(vpr: &mut __m128i, element: u8, value: u64) {
unsafe {
*vpr = match element & 1 {
0 => _mm_insert_epi64(*vpr, value as i64, 1),
1 => _mm_insert_epi64(*vpr, value as i64, 0),
_ => unreachable!(),
};
}
}
fn get_vpr64(vpr: __m128i, element: u8) -> u64 {
unsafe {
match element & 1 {
0 => _mm_extract_epi64(vpr, 1) as u64,
1 => _mm_extract_epi64(vpr, 0) as u64,
_ => unreachable!(),
}
}
}
fn modify_vpr128(vpr: &mut __m128i, value: u128) {
unsafe { *vpr = std::mem::transmute::<u128, __m128i>(value) }
}
fn get_vpr128(vpr: __m128i) -> u128 {
unsafe { std::mem::transmute::<__m128i, u128>(vpr) }
}
pub fn j(device: &mut device::Device, opcode: u32) {
if device::rsp_cpu::in_delay_slot_taken(device) {
return;
}
device.rsp.cpu.branch_state.state = device::cpu::State::Take;
device.rsp.cpu.branch_state.pc =
(device.rsp.regs2[device::rsp_interface::SP_PC_REG as usize] + 4) & 0xF0000000
| ((opcode & 0x3FFFFFF) << 2)
}
pub fn jal(device: &mut device::Device, opcode: u32) {
if device::rsp_cpu::in_delay_slot_taken(device) {
device.rsp.cpu.gpr[31] = (device.rsp.cpu.branch_state.pc + 4) & 0xFFF
} else {
device.rsp.cpu.gpr[31] =
(device.rsp.regs2[device::rsp_interface::SP_PC_REG as usize] + 8) & 0xFFF
}
if !device::rsp_cpu::in_delay_slot_taken(device) {
device.rsp.cpu.branch_state.state = device::cpu::State::Take;
device.rsp.cpu.branch_state.pc =
(device.rsp.regs2[device::rsp_interface::SP_PC_REG as usize] + 4) & 0xF0000000
| ((opcode & 0x3FFFFFF) << 2)
} else if !device::rsp_cpu::in_delay_slot(device) {
device.rsp.cpu.branch_state.state = device::cpu::State::NotTaken;
}
}
pub fn beq(device: &mut device::Device, opcode: u32) {
if device.rsp.cpu.gpr[rs(opcode) as usize] == device.rsp.cpu.gpr[rt(opcode) as usize] {
device.rsp.cpu.branch_state.state = device::cpu::State::Take;
device.rsp.cpu.branch_state.pc = device.rsp.regs2
[device::rsp_interface::SP_PC_REG as usize]
.wrapping_add(se16(imm(opcode) as i16) << 2)
+ 4;
} else {
device.rsp.cpu.branch_state.state = device::cpu::State::NotTaken;
}
}
pub fn bne(device: &mut device::Device, opcode: u32) {
if device.rsp.cpu.gpr[rs(opcode) as usize] != device.rsp.cpu.gpr[rt(opcode) as usize] {
device.rsp.cpu.branch_state.state = device::cpu::State::Take;
device.rsp.cpu.branch_state.pc = device.rsp.regs2
[device::rsp_interface::SP_PC_REG as usize]
.wrapping_add(se16(imm(opcode) as i16) << 2)
+ 4;
} else {
device.rsp.cpu.branch_state.state = device::cpu::State::NotTaken;
}
}
pub fn blez(device: &mut device::Device, opcode: u32) {
if device.rsp.cpu.gpr[rs(opcode) as usize] as i32 <= 0 {
device.rsp.cpu.branch_state.state = device::cpu::State::Take;
device.rsp.cpu.branch_state.pc = device.rsp.regs2
[device::rsp_interface::SP_PC_REG as usize]
.wrapping_add(se16(imm(opcode) as i16) << 2)
+ 4;
} else {
device.rsp.cpu.branch_state.state = device::cpu::State::NotTaken;
}
}
pub fn bgtz(device: &mut device::Device, opcode: u32) {
if device.rsp.cpu.gpr[rs(opcode) as usize] as i32 > 0 {
device.rsp.cpu.branch_state.state = device::cpu::State::Take;
device.rsp.cpu.branch_state.pc = device.rsp.regs2
[device::rsp_interface::SP_PC_REG as usize]
.wrapping_add(se16(imm(opcode) as i16) << 2)
+ 4;
} else {
device.rsp.cpu.branch_state.state = device::cpu::State::NotTaken;
}
}
pub fn addi(device: &mut device::Device, opcode: u32) {
device.rsp.cpu.gpr[rt(opcode) as usize] =
device.rsp.cpu.gpr[rs(opcode) as usize].wrapping_add(imm(opcode) as i16 as i32 as u32)
}
pub fn addiu(device: &mut device::Device, opcode: u32) {
device.rsp.cpu.gpr[rt(opcode) as usize] =
device.rsp.cpu.gpr[rs(opcode) as usize].wrapping_add(imm(opcode) as i16 as i32 as u32)
}
pub fn slti(device: &mut device::Device, opcode: u32) {
device.rsp.cpu.gpr[rt(opcode) as usize] =
((device.rsp.cpu.gpr[rs(opcode) as usize] as i32) < (imm(opcode) as i16 as i32)) as u32
}
pub fn sltiu(device: &mut device::Device, opcode: u32) {
device.rsp.cpu.gpr[rt(opcode) as usize] =
(device.rsp.cpu.gpr[rs(opcode) as usize] < (imm(opcode) as i16 as i32 as u32)) as u32
}
pub fn andi(device: &mut device::Device, opcode: u32) {
device.rsp.cpu.gpr[rt(opcode) as usize] =
device.rsp.cpu.gpr[rs(opcode) as usize] & (imm(opcode)) as u32
}
pub fn ori(device: &mut device::Device, opcode: u32) {
device.rsp.cpu.gpr[rt(opcode) as usize] =
device.rsp.cpu.gpr[rs(opcode) as usize] | (imm(opcode)) as u32
}
pub fn xori(device: &mut device::Device, opcode: u32) {
device.rsp.cpu.gpr[rt(opcode) as usize] =
device.rsp.cpu.gpr[rs(opcode) as usize] ^ (imm(opcode)) as u32
}
pub fn lui(device: &mut device::Device, opcode: u32) {
device.rsp.cpu.gpr[rt(opcode) as usize] = (imm(opcode) as u32) << 16
}
pub fn lb(device: &mut device::Device, opcode: u32) {
let address =
device.rsp.cpu.gpr[rs(opcode) as usize].wrapping_add(imm(opcode) as i16 as i32 as u32);
device.rsp.cpu.gpr[rt(opcode) as usize] =
device.rsp.mem[address as usize & 0xFFF] as i8 as i32 as u32
}
pub fn lh(device: &mut device::Device, opcode: u32) {
let address =
device.rsp.cpu.gpr[rs(opcode) as usize].wrapping_add(imm(opcode) as i16 as i32 as u32);
let mut w = [0; 2];
w[0] = device.rsp.mem[address as usize & 0xFFF];
w[1] = device.rsp.mem[(address as usize + 1) & 0xFFF];
device.rsp.cpu.gpr[rt(opcode) as usize] =
(((w[0] as u16) << 8) | w[1] as u16) as i16 as i32 as u32
}
pub fn lw(device: &mut device::Device, opcode: u32) {
let address =
device.rsp.cpu.gpr[rs(opcode) as usize].wrapping_add(imm(opcode) as i16 as i32 as u32);
let mut w = [0; 4];
w[0] = device.rsp.mem[address as usize & 0xFFF];
w[1] = device.rsp.mem[(address as usize + 1) & 0xFFF];
w[2] = device.rsp.mem[(address as usize + 2) & 0xFFF];
w[3] = device.rsp.mem[(address as usize + 3) & 0xFFF];
device.rsp.cpu.gpr[rt(opcode) as usize] =
((w[0] as u32) << 24) | ((w[1] as u32) << 16) | ((w[2] as u32) << 8) | (w[3] as u32)
}
pub fn lbu(device: &mut device::Device, opcode: u32) {
let address =
device.rsp.cpu.gpr[rs(opcode) as usize].wrapping_add(imm(opcode) as i16 as i32 as u32);
device.rsp.cpu.gpr[rt(opcode) as usize] = device.rsp.mem[address as usize & 0xFFF] as u32
}
pub fn lhu(device: &mut device::Device, opcode: u32) {
let address =
device.rsp.cpu.gpr[rs(opcode) as usize].wrapping_add(imm(opcode) as i16 as i32 as u32);
let mut w = [0; 2];
w[0] = device.rsp.mem[address as usize & 0xFFF];
w[1] = device.rsp.mem[(address as usize + 1) & 0xFFF];
device.rsp.cpu.gpr[rt(opcode) as usize] = (((w[0] as u16) << 8) | w[1] as u16) as u32
}
pub fn lwu(device: &mut device::Device, opcode: u32) {
let address =
device.rsp.cpu.gpr[rs(opcode) as usize].wrapping_add(imm(opcode) as i16 as i32 as u32);
let mut w = [0; 4];
w[0] = device.rsp.mem[address as usize & 0xFFF];
w[1] = device.rsp.mem[(address as usize + 1) & 0xFFF];
w[2] = device.rsp.mem[(address as usize + 2) & 0xFFF];
w[3] = device.rsp.mem[(address as usize + 3) & 0xFFF];
device.rsp.cpu.gpr[rt(opcode) as usize] =
((w[0] as u32) << 24) | ((w[1] as u32) << 16) | ((w[2] as u32) << 8) | (w[3] as u32)
}
pub fn sb(device: &mut device::Device, opcode: u32) {
let address =
device.rsp.cpu.gpr[rs(opcode) as usize].wrapping_add(imm(opcode) as i16 as i32 as u32);
device.rsp.mem[address as usize & 0xFFF] = (device.rsp.cpu.gpr[rt(opcode) as usize]) as u8;
}
pub fn sh(device: &mut device::Device, opcode: u32) {
let address =
device.rsp.cpu.gpr[rs(opcode) as usize].wrapping_add(imm(opcode) as i16 as i32 as u32);
device.rsp.mem[address as usize & 0xFFF] = (device.rsp.cpu.gpr[rt(opcode) as usize] >> 8) as u8;
device.rsp.mem[(address as usize + 1) & 0xFFF] =
(device.rsp.cpu.gpr[rt(opcode) as usize]) as u8;
}
pub fn sw(device: &mut device::Device, opcode: u32) {
let address =
device.rsp.cpu.gpr[rs(opcode) as usize].wrapping_add(imm(opcode) as i16 as i32 as u32);
device.rsp.mem[address as usize & 0xFFF] =
(device.rsp.cpu.gpr[rt(opcode) as usize] >> 24) as u8;
device.rsp.mem[(address as usize + 1) & 0xFFF] =
(device.rsp.cpu.gpr[rt(opcode) as usize] >> 16) as u8;
device.rsp.mem[(address as usize + 2) & 0xFFF] =
(device.rsp.cpu.gpr[rt(opcode) as usize] >> 8) as u8;
device.rsp.mem[(address as usize + 3) & 0xFFF] =
(device.rsp.cpu.gpr[rt(opcode) as usize]) as u8;
}
pub fn sll(device: &mut device::Device, opcode: u32) {
device.rsp.cpu.gpr[rd(opcode) as usize] = device.rsp.cpu.gpr[rt(opcode) as usize] << sa(opcode)
}
pub fn srl(device: &mut device::Device, opcode: u32) {
device.rsp.cpu.gpr[rd(opcode) as usize] = device.rsp.cpu.gpr[rt(opcode) as usize] >> sa(opcode)
}
pub fn sra(device: &mut device::Device, opcode: u32) {
device.rsp.cpu.gpr[rd(opcode) as usize] =
((device.rsp.cpu.gpr[rt(opcode) as usize] as i32) >> sa(opcode)) as u32
}
pub fn sllv(device: &mut device::Device, opcode: u32) {
device.rsp.cpu.gpr[rd(opcode) as usize] =
device.rsp.cpu.gpr[rt(opcode) as usize] << (device.rsp.cpu.gpr[rs(opcode) as usize] & 31)
}
pub fn srlv(device: &mut device::Device, opcode: u32) {
device.rsp.cpu.gpr[rd(opcode) as usize] =
device.rsp.cpu.gpr[rt(opcode) as usize] >> (device.rsp.cpu.gpr[rs(opcode) as usize] & 31)
}
pub fn srav(device: &mut device::Device, opcode: u32) {
device.rsp.cpu.gpr[rd(opcode) as usize] = ((device.rsp.cpu.gpr[rt(opcode) as usize] as i32)
>> (device.rsp.cpu.gpr[rs(opcode) as usize] & 31))
as u32
}
pub fn jr(device: &mut device::Device, opcode: u32) {
if !device::rsp_cpu::in_delay_slot_taken(device) {
device.rsp.cpu.branch_state.state = device::cpu::State::Take;
device.rsp.cpu.branch_state.pc = device.rsp.cpu.gpr[rs(opcode) as usize]
} else if !device::rsp_cpu::in_delay_slot(device) {
device.rsp.cpu.branch_state.state = device::cpu::State::NotTaken;
}
}
pub fn jalr(device: &mut device::Device, opcode: u32) {
let in_delay_slot_taken = device::rsp_cpu::in_delay_slot_taken(device);
if !in_delay_slot_taken {
device.rsp.cpu.branch_state.state = device::cpu::State::Take;
device.rsp.cpu.branch_state.pc = device.rsp.cpu.gpr[rs(opcode) as usize]
} else if !device::rsp_cpu::in_delay_slot(device) {
device.rsp.cpu.branch_state.state = device::cpu::State::NotTaken;
}
if in_delay_slot_taken {
device.rsp.cpu.gpr[rd(opcode) as usize] = (device.rsp.cpu.branch_state.pc + 4) & 0xFFF
} else {
device.rsp.cpu.gpr[rd(opcode) as usize] =
(device.rsp.regs2[device::rsp_interface::SP_PC_REG as usize] + 8) & 0xFFF
}
}
pub fn break_(device: &mut device::Device, _opcode: u32) {
device.rsp.cpu.broken = true;
}
pub fn add(device: &mut device::Device, opcode: u32) {
device.rsp.cpu.gpr[rd(opcode) as usize] = device.rsp.cpu.gpr[rs(opcode) as usize]
.wrapping_add(device.rsp.cpu.gpr[rt(opcode) as usize])
}
pub fn addu(device: &mut device::Device, opcode: u32) {
device.rsp.cpu.gpr[rd(opcode) as usize] = device.rsp.cpu.gpr[rs(opcode) as usize]
.wrapping_add(device.rsp.cpu.gpr[rt(opcode) as usize])
}
pub fn sub(device: &mut device::Device, opcode: u32) {
device.rsp.cpu.gpr[rd(opcode) as usize] = device.rsp.cpu.gpr[rs(opcode) as usize]
.wrapping_sub(device.rsp.cpu.gpr[rt(opcode) as usize])
}
pub fn subu(device: &mut device::Device, opcode: u32) {
device.rsp.cpu.gpr[rd(opcode) as usize] = device.rsp.cpu.gpr[rs(opcode) as usize]
.wrapping_sub(device.rsp.cpu.gpr[rt(opcode) as usize])
}
pub fn and(device: &mut device::Device, opcode: u32) {
device.rsp.cpu.gpr[rd(opcode) as usize] =
device.rsp.cpu.gpr[rs(opcode) as usize] & device.rsp.cpu.gpr[rt(opcode) as usize]
}
pub fn or(device: &mut device::Device, opcode: u32) {
device.rsp.cpu.gpr[rd(opcode) as usize] =
device.rsp.cpu.gpr[rs(opcode) as usize] | device.rsp.cpu.gpr[rt(opcode) as usize]
}
pub fn xor(device: &mut device::Device, opcode: u32) {
device.rsp.cpu.gpr[rd(opcode) as usize] =
device.rsp.cpu.gpr[rs(opcode) as usize] ^ device.rsp.cpu.gpr[rt(opcode) as usize]
}
pub fn nor(device: &mut device::Device, opcode: u32) {
device.rsp.cpu.gpr[rd(opcode) as usize] =
!(device.rsp.cpu.gpr[rs(opcode) as usize] | device.rsp.cpu.gpr[rt(opcode) as usize])
}
pub fn slt(device: &mut device::Device, opcode: u32) {
device.rsp.cpu.gpr[rd(opcode) as usize] = ((device.rsp.cpu.gpr[rs(opcode) as usize] as i32)
< (device.rsp.cpu.gpr[rt(opcode) as usize] as i32))
as u32
}
pub fn sltu(device: &mut device::Device, opcode: u32) {
device.rsp.cpu.gpr[rd(opcode) as usize] =
(device.rsp.cpu.gpr[rs(opcode) as usize] < device.rsp.cpu.gpr[rt(opcode) as usize]) as u32
}
pub fn bltz(device: &mut device::Device, opcode: u32) {
if (device.rsp.cpu.gpr[rs(opcode) as usize] as i32) < 0 {
device.rsp.cpu.branch_state.state = device::cpu::State::Take;
device.rsp.cpu.branch_state.pc = device.rsp.regs2
[device::rsp_interface::SP_PC_REG as usize]
.wrapping_add(se16(imm(opcode) as i16) << 2)
+ 4;
} else {
device.rsp.cpu.branch_state.state = device::cpu::State::NotTaken;
}
}
pub fn bgez(device: &mut device::Device, opcode: u32) {
if device.rsp.cpu.gpr[rs(opcode) as usize] as i32 >= 0 {
device.rsp.cpu.branch_state.state = device::cpu::State::Take;
device.rsp.cpu.branch_state.pc = device.rsp.regs2
[device::rsp_interface::SP_PC_REG as usize]
.wrapping_add(se16(imm(opcode) as i16) << 2)
+ 4;
} else {
device.rsp.cpu.branch_state.state = device::cpu::State::NotTaken;
}
}
pub fn bltzal(device: &mut device::Device, opcode: u32) {
if (device.rsp.cpu.gpr[rs(opcode) as usize] as i32) < 0 {
device.rsp.cpu.branch_state.state = device::cpu::State::Take;
device.rsp.cpu.branch_state.pc = device.rsp.regs2
[device::rsp_interface::SP_PC_REG as usize]
.wrapping_add(se16(imm(opcode) as i16) << 2)
+ 4;
} else {
device.rsp.cpu.branch_state.state = device::cpu::State::NotTaken;
}
device.rsp.cpu.gpr[31] =
(device.rsp.regs2[device::rsp_interface::SP_PC_REG as usize] + 8) & 0xFFF
}
pub fn bgezal(device: &mut device::Device, opcode: u32) {
if (device.rsp.cpu.gpr[rs(opcode) as usize] as i32) >= 0 {
device.rsp.cpu.branch_state.state = device::cpu::State::Take;
device.rsp.cpu.branch_state.pc = device.rsp.regs2
[device::rsp_interface::SP_PC_REG as usize]
.wrapping_add(se16(imm(opcode) as i16) << 2)
+ 4;
} else {
device.rsp.cpu.branch_state.state = device::cpu::State::NotTaken;
}
device.rsp.cpu.gpr[31] =
(device.rsp.regs2[device::rsp_interface::SP_PC_REG as usize] + 8) & 0xFFF
}
pub fn mfc0(device: &mut device::Device, opcode: u32) {
device.rsp.cpu.cycle_counter += 2;
if rd(opcode) < device::rsp_interface::SP_REGS_COUNT {
device.rsp.cpu.gpr[rt(opcode) as usize] = device::rsp_interface::read_regs(
device,
(rd(opcode) << 2) as u64,
device::memory::AccessSize::Word,
)
} else {
device.rsp.cpu.gpr[rt(opcode) as usize] = device::rdp::read_regs_dpc(
device,
((rd(opcode) - device::rsp_interface::SP_REGS_COUNT) << 2) as u64,
device::memory::AccessSize::Word,
)
}
}
pub fn mtc0(device: &mut device::Device, opcode: u32) {
if rd(opcode) < device::rsp_interface::SP_REGS_COUNT {
device::rsp_interface::write_regs(
device,
(rd(opcode) << 2) as u64,
device.rsp.cpu.gpr[rt(opcode) as usize],
0xFFFFFFFF,
)
} else {
device::rdp::write_regs_dpc(
device,
((rd(opcode) - device::rsp_interface::SP_REGS_COUNT) << 2) as u64,
device.rsp.cpu.gpr[rt(opcode) as usize],
0xFFFFFFFF,
)
}
if rd(opcode) == device::rsp_interface::SP_STATUS_REG
&& device.rsp.cpu.gpr[rt(opcode) as usize] & device::rsp_interface::SP_SET_HALT != 0
{
device.rsp.regs[device::rsp_interface::SP_STATUS_REG as usize] &=
!device::rsp_interface::SP_STATUS_HALT; // set halt when event happens
device.rsp.cpu.halted = true // the RSP can halt itself by setting SP_SET_HALT
}
}
pub fn mfc2(device: &mut device::Device, opcode: u32) {
let hi = get_vpr8(device.rsp.cpu.vpr[rd(opcode) as usize], velement(opcode));
let lo = get_vpr8(
device.rsp.cpu.vpr[rd(opcode) as usize],
velement(opcode) + 1,
);
device.rsp.cpu.gpr[rt(opcode) as usize] =
(((hi as u16) << 8) | (lo as u16)) as i16 as i32 as u32
}
pub fn cfc2(device: &mut device::Device, opcode: u32) {
let hi;
let lo;
let zero = unsafe { _mm_setzero_si128() };
match rd(opcode) & 3 {
0x00 => {
hi = &device.rsp.cpu.vcoh;
lo = &device.rsp.cpu.vcol;
}
0x01 => {
hi = &device.rsp.cpu.vcch;
lo = &device.rsp.cpu.vccl;
}
0x02 | 0x03 => {
hi = &zero;
lo = &device.rsp.cpu.vce;
}
_ => {
panic!("unknown cfc2")
}
}
unsafe {
let reverse = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
device.rsp.cpu.gpr[rt(opcode) as usize] =
(_mm_movemask_epi8(_mm_shuffle_epi8(_mm_packs_epi16(*hi, *lo), reverse))) as i16 as u32;
}
}
pub fn mtc2(device: &mut device::Device, opcode: u32) {
modify_vpr8(
&mut device.rsp.cpu.vpr[rd(opcode) as usize],
velement(opcode),
(device.rsp.cpu.gpr[rt(opcode) as usize] >> 8) as u8,
);
if velement(opcode) != 15 {
modify_vpr8(
&mut device.rsp.cpu.vpr[rd(opcode) as usize],
velement(opcode) + 1,
device.rsp.cpu.gpr[rt(opcode) as usize] as u8,
);
}
}
pub fn ctc2(device: &mut device::Device, opcode: u32) {
let hi;
let lo;
let mut zero = unsafe { _mm_setzero_si128() };
match rd(opcode) & 3 {
0x00 => {
hi = &mut device.rsp.cpu.vcoh;
lo = &mut device.rsp.cpu.vcol;
}
0x01 => {
hi = &mut device.rsp.cpu.vcch;
lo = &mut device.rsp.cpu.vccl;
}
0x02 | 0x03 => {
hi = &mut zero;
lo = &mut device.rsp.cpu.vce;
}
_ => {
panic!("unknown ctc2")
}
}
unsafe {
let mask = _mm_set_epi16(
0x0101,
0x0202,
0x0404,
0x0808,
0x1010,
0x2020,
0x4040,
0x8080u16 as i16,
);
*lo = _mm_cmpeq_epi8(
_mm_and_si128(
_mm_set1_epi8(!device.rsp.cpu.gpr[rt(opcode) as usize] as i8),
mask,
),
_mm_setzero_si128(),
);
*hi = _mm_cmpeq_epi8(
_mm_and_si128(
_mm_set1_epi8(!(device.rsp.cpu.gpr[rt(opcode) as usize] >> 8) as i8),
mask,
),
_mm_setzero_si128(),
);
}
}
pub fn lbv(device: &mut device::Device, opcode: u32) {
let address = device.rsp.cpu.gpr[rs(opcode) as usize]
.wrapping_add(sign_extend_7bit_offset(voffset(opcode), 0));
let element = velement(opcode);
modify_vpr8(
&mut device.rsp.cpu.vpr[rt(opcode) as usize],
element,
device.rsp.mem[(address & 0xFFF) as usize],
);
}
pub fn lsv(device: &mut device::Device, opcode: u32) {
let mut address = device.rsp.cpu.gpr[rs(opcode) as usize]
.wrapping_add(sign_extend_7bit_offset(voffset(opcode), 1));
let mut element = velement(opcode);
if element % 2 == 0 {
modify_vpr16(
&mut device.rsp.cpu.vpr[rt(opcode) as usize],
element / 2,
((device.rsp.mem[(address & 0xFFF) as usize] as u16) << 8)
| (device.rsp.mem[((address + 1) & 0xFFF) as usize] as u16),
);
} else {
let end = std::cmp::min(element + 2, 16);
while element < end {
modify_vpr8(
&mut device.rsp.cpu.vpr[rt(opcode) as usize],
element,
device.rsp.mem[(address & 0xFFF) as usize],
);
address += 1;
element += 1;
}
}
}
pub fn llv(device: &mut device::Device, opcode: u32) {
let mut address = device.rsp.cpu.gpr[rs(opcode) as usize]
.wrapping_add(sign_extend_7bit_offset(voffset(opcode), 2));
let mut element = velement(opcode);
if element % 4 == 0 {
let mut value = 0;
for i in 0..4 {
value |= (device.rsp.mem[((address + i) & 0xFFF) as usize] as u32) << (8 * (3 - i));
}
modify_vpr32(
&mut device.rsp.cpu.vpr[rt(opcode) as usize],
element / 4,
value,
);
} else {
let end = std::cmp::min(element + 4, 16);
while element < end {
modify_vpr8(
&mut device.rsp.cpu.vpr[rt(opcode) as usize],
element,
device.rsp.mem[(address & 0xFFF) as usize],
);
address += 1;
element += 1;
}
}
}
pub fn ldv(device: &mut device::Device, opcode: u32) {
let mut address = device.rsp.cpu.gpr[rs(opcode) as usize]
.wrapping_add(sign_extend_7bit_offset(voffset(opcode), 3));
let mut element = velement(opcode);
if element % 8 == 0 {
let mut value = 0;
for i in 0..8 {
value |= (device.rsp.mem[((address + i) & 0xFFF) as usize] as u64) << (8 * (7 - i));
}
modify_vpr64(
&mut device.rsp.cpu.vpr[rt(opcode) as usize],
element / 8,
value,
);
} else {
let end = std::cmp::min(element + 8, 16);
while element < end {
modify_vpr8(
&mut device.rsp.cpu.vpr[rt(opcode) as usize],
element,
device.rsp.mem[(address & 0xFFF) as usize],
);
address += 1;
element += 1;
}
}
}
pub fn lqv(device: &mut device::Device, opcode: u32) {
let mut address = device.rsp.cpu.gpr[rs(opcode) as usize]
.wrapping_add(sign_extend_7bit_offset(voffset(opcode), 4));
let mut element = velement(opcode);
if element == 0 && address % 16 == 0 {
let mut value = 0;
for i in 0..16 {
value |= (device.rsp.mem[((address + i) & 0xFFF) as usize] as u128) << (8 * (15 - i));
}
modify_vpr128(&mut device.rsp.cpu.vpr[rt(opcode) as usize], value);
} else {
let end = std::cmp::min(16 + element - ((address & 15) as u8), 16);
while element < end {
modify_vpr8(
&mut device.rsp.cpu.vpr[rt(opcode) as usize],
element,
device.rsp.mem[(address & 0xFFF) as usize],
);
address += 1;
element += 1;
}
}
}
pub fn lrv(device: &mut device::Device, opcode: u32) {
let mut address = device.rsp.cpu.gpr[rs(opcode) as usize]
.wrapping_add(sign_extend_7bit_offset(voffset(opcode), 4));
let mut element = 16u8.wrapping_sub(((address & 15) as u8).wrapping_sub(velement(opcode)));
address &= !15;
if element == 0 {
let mut value = 0;
for i in 0..16 {
value |= (device.rsp.mem[((address + i) & 0xFFF) as usize] as u128) << (8 * (15 - i));
}
modify_vpr128(&mut device.rsp.cpu.vpr[rt(opcode) as usize], value);
} else {
while element < 16 {
modify_vpr8(
&mut device.rsp.cpu.vpr[rt(opcode) as usize],
element,
device.rsp.mem[(address & 0xFFF) as usize],
);
address += 1;
element += 1;
}
}
}
pub fn lpv(device: &mut device::Device, opcode: u32) {
let mut address = device.rsp.cpu.gpr[rs(opcode) as usize]
.wrapping_add(sign_extend_7bit_offset(voffset(opcode), 3));
let index = ((address & 7) as u8).wrapping_sub(velement(opcode));
address &= !7;
let mut value = 0;
for i in 0..8 {
value |= (((device.rsp.mem
[((address.wrapping_add(((index.wrapping_add(i)) & 15) as u32)) & 0xFFF) as usize]
as u16)
<< 8) as u128)
<< (16 * (7 - i));
}
modify_vpr128(&mut device.rsp.cpu.vpr[rt(opcode) as usize], value);
}
pub fn luv(device: &mut device::Device, opcode: u32) {
let mut address = device.rsp.cpu.gpr[rs(opcode) as usize]
.wrapping_add(sign_extend_7bit_offset(voffset(opcode), 3));
let index = ((address & 7) as u8).wrapping_sub(velement(opcode));
address &= !7;
let mut value = 0;
for i in 0..8 {
value |= (((device.rsp.mem
[((address.wrapping_add(((index.wrapping_add(i)) & 15) as u32)) & 0xFFF) as usize]
as u16)
<< 7) as u128)
<< (16 * (7 - i));
}
modify_vpr128(&mut device.rsp.cpu.vpr[rt(opcode) as usize], value);
}
pub fn lhv(device: &mut device::Device, opcode: u32) {
let mut address = device.rsp.cpu.gpr[rs(opcode) as usize]
.wrapping_add(sign_extend_7bit_offset(voffset(opcode), 4));
let index = ((address & 7) as u8).wrapping_sub(velement(opcode));
address &= !7;
let mut value = 0;
for i in 0..8 {
value |= (((device.rsp.mem
[((address.wrapping_add(((index.wrapping_add(i * 2)) & 15) as u32)) & 0xFFF) as usize]
as u16)
<< 7) as u128)
<< (16 * (7 - i));
}
modify_vpr128(&mut device.rsp.cpu.vpr[rt(opcode) as usize], value);
}
pub fn lfv(device: &mut device::Device, opcode: u32) {
let mut address = device.rsp.cpu.gpr[rs(opcode) as usize]
.wrapping_add(sign_extend_7bit_offset(voffset(opcode), 4));
let index = ((address & 7) as u8).wrapping_sub(velement(opcode));
address &= !7;
let start = velement(opcode);
let end = std::cmp::min(start + 8, 16);
let mut tmp: __m128i = unsafe { _mm_setzero_si128() };
let mut offset: u8 = 0;
while offset < 4 {
modify_vpr16(
&mut tmp,
offset,
(device.rsp.mem[((address.wrapping_add(((index.wrapping_add(offset * 4)) & 15) as u32))
& 0xFFF) as usize] as u16)
<< 7,
);
modify_vpr16(
&mut tmp,
offset + 4,
(device.rsp.mem[((address
.wrapping_add(((index.wrapping_add(offset * 4).wrapping_add(8)) & 15) as u32))
& 0xFFF) as usize] as u16)
<< 7,
);
offset += 1;
}
offset = start;
while offset < end {
let value = get_vpr8(tmp, offset);
modify_vpr8(&mut device.rsp.cpu.vpr[rt(opcode) as usize], offset, value);
offset += 1;
}
}
pub fn lwv(_device: &mut device::Device, _opcode: u32) {}
pub fn ltv(device: &mut device::Device, opcode: u32) {
let mut address = device.rsp.cpu.gpr[rs(opcode) as usize]
.wrapping_add(sign_extend_7bit_offset(voffset(opcode), 4));
let begin = address & !7;
address = begin + (((velement(opcode)) as u32 + (address & 8)) & 15);
let vtbase = rt(opcode) & !7;
let mut vtoff = (velement(opcode)) as u32 >> 1;
for i in 0..8 {
modify_vpr8(
&mut device.rsp.cpu.vpr[(vtbase + vtoff) as usize],
i * 2,
device.rsp.mem[(address & 0xFFF) as usize],
);
address += 1;
if address == begin + 16 {
address = begin
}
modify_vpr8(
&mut device.rsp.cpu.vpr[(vtbase + vtoff) as usize],
i * 2 + 1,
device.rsp.mem[(address & 0xFFF) as usize],
);
address += 1;
if address == begin + 16 {
address = begin
}
vtoff = (vtoff + 1) & 7;
}
}
pub fn sbv(device: &mut device::Device, opcode: u32) {
let address = device.rsp.cpu.gpr[rs(opcode) as usize]
.wrapping_add(sign_extend_7bit_offset(voffset(opcode), 0));
device.rsp.mem[(address & 0xFFF) as usize] =
get_vpr8(device.rsp.cpu.vpr[rt(opcode) as usize], velement(opcode))
}
pub fn ssv(device: &mut device::Device, opcode: u32) {
let mut address = device.rsp.cpu.gpr[rs(opcode) as usize]
.wrapping_add(sign_extend_7bit_offset(voffset(opcode), 1));
let mut element = velement(opcode);
if element % 2 == 0 {
let start = (address & 0xFFF) as usize;
device.rsp.mem[start..start + 2].copy_from_slice(
&get_vpr16(device.rsp.cpu.vpr[rt(opcode) as usize], element / 2).to_be_bytes(),
);
} else {
let end = element + 2;
while element < end {
device.rsp.mem[(address & 0xFFF) as usize] =
get_vpr8(device.rsp.cpu.vpr[rt(opcode) as usize], element);
address += 1;
element += 1;
}
}
}
pub fn slv(device: &mut device::Device, opcode: u32) {
let mut address = device.rsp.cpu.gpr[rs(opcode) as usize]
.wrapping_add(sign_extend_7bit_offset(voffset(opcode), 2));
let mut element = velement(opcode);
if element % 4 == 0 {
let start = (address & 0xFFF) as usize;
device.rsp.mem[start..start + 4].copy_from_slice(
&get_vpr32(device.rsp.cpu.vpr[rt(opcode) as usize], element / 4).to_be_bytes(),
);
} else {
let end = element + 4;
while element < end {
device.rsp.mem[(address & 0xFFF) as usize] =
get_vpr8(device.rsp.cpu.vpr[rt(opcode) as usize], element);
address += 1;
element += 1;
}
}
}
pub fn sdv(device: &mut device::Device, opcode: u32) {
let mut address = device.rsp.cpu.gpr[rs(opcode) as usize]
.wrapping_add(sign_extend_7bit_offset(voffset(opcode), 3));
let mut element = velement(opcode);
if element % 8 == 0 {
let start = (address & 0xFFF) as usize;
device.rsp.mem[start..start + 8].copy_from_slice(
&get_vpr64(device.rsp.cpu.vpr[rt(opcode) as usize], element / 8).to_be_bytes(),
);
} else {
let end = element + 8;
while element < end {
device.rsp.mem[(address & 0xFFF) as usize] =
get_vpr8(device.rsp.cpu.vpr[rt(opcode) as usize], element);
address += 1;
element += 1;
}
}
}
pub fn sqv(device: &mut device::Device, opcode: u32) {
let mut address = device.rsp.cpu.gpr[rs(opcode) as usize]
.wrapping_add(sign_extend_7bit_offset(voffset(opcode), 4));
let mut element = velement(opcode);
if element == 0 && address % 16 == 0 {
let start = (address & 0xFFF) as usize;
device.rsp.mem[start..start + 16]
.copy_from_slice(&get_vpr128(device.rsp.cpu.vpr[rt(opcode) as usize]).to_be_bytes());
} else {
let end = element + (16 - (address & 15)) as u8;
while element < end {
device.rsp.mem[(address & 0xFFF) as usize] =
get_vpr8(device.rsp.cpu.vpr[rt(opcode) as usize], element);
address += 1;
element += 1;
}
}
}
pub fn srv(device: &mut device::Device, opcode: u32) {
let mut address = device.rsp.cpu.gpr[rs(opcode) as usize]
.wrapping_add(sign_extend_7bit_offset(voffset(opcode), 4));
let mut element = velement(opcode);
let end = element + (address & 15) as u8;
let base = (16 - (address & 15)) as u8;
address &= !15;
if element == 0 && base == 0 {
let start = (address & 0xFFF) as usize;
device.rsp.mem[start..start + 16]
.copy_from_slice(&get_vpr128(device.rsp.cpu.vpr[rt(opcode) as usize]).to_be_bytes());
} else {
while element < end {
device.rsp.mem[(address & 0xFFF) as usize] =
get_vpr8(device.rsp.cpu.vpr[rt(opcode) as usize], element + base);
address += 1;
element += 1;
}
}
}
pub fn spv(device: &mut device::Device, opcode: u32) {
let mut address = device.rsp.cpu.gpr[rs(opcode) as usize]
.wrapping_add(sign_extend_7bit_offset(voffset(opcode), 3));
let mut element = velement(opcode);
let end = element + 8;
while element < end {
if (element & 15) < 8 {
device.rsp.mem[(address & 0xFFF) as usize] =
get_vpr8(device.rsp.cpu.vpr[rt(opcode) as usize], (element & 7) << 1);
} else {
device.rsp.mem[(address & 0xFFF) as usize] =
(get_vpr16(device.rsp.cpu.vpr[rt(opcode) as usize], element) >> 7) as u8;
}
address += 1;
element += 1;
}
}
pub fn suv(device: &mut device::Device, opcode: u32) {
let mut address = device.rsp.cpu.gpr[rs(opcode) as usize]
.wrapping_add(sign_extend_7bit_offset(voffset(opcode), 3));
let mut element = velement(opcode);
let end = element + 8;
while element < end {
if (element & 15) < 8 {
device.rsp.mem[(address & 0xFFF) as usize] =
(get_vpr16(device.rsp.cpu.vpr[rt(opcode) as usize], element) >> 7) as u8;
} else {
device.rsp.mem[(address & 0xFFF) as usize] =
get_vpr8(device.rsp.cpu.vpr[rt(opcode) as usize], (element & 7) << 1);
}
address += 1;
element += 1;
}
}
pub fn shv(device: &mut device::Device, opcode: u32) {
let mut address = device.rsp.cpu.gpr[rs(opcode) as usize]
.wrapping_add(sign_extend_7bit_offset(voffset(opcode), 4));
let element = velement(opcode);
let index = (address & 7) as u8;
address &= !7;
for offset in 0..8 {
let byte_val = element + offset * 2;
let value = (get_vpr8(device.rsp.cpu.vpr[rt(opcode) as usize], byte_val) << 1)
| (get_vpr8(device.rsp.cpu.vpr[rt(opcode) as usize], byte_val + 1) >> 7);
device.rsp.mem[((address + ((index + offset * 2) & 15) as u32) & 0xFFF) as usize] = value;
}
}
pub fn sfv(device: &mut device::Device, opcode: u32) {
let mut address = device.rsp.cpu.gpr[rs(opcode) as usize]
.wrapping_add(sign_extend_7bit_offset(voffset(opcode), 4));
let base = address & 7;
address &= !7;
let elements = match velement(opcode) {
0 | 15 => [0, 1, 2, 3],
1 => [6, 7, 4, 5],
4 => [1, 2, 3, 0],
5 => [7, 4, 5, 6],
8 => [4, 5, 6, 7],
11 => [3, 0, 1, 2],
12 => [5, 6, 7, 4],
_ => {
device.rsp.mem[((address + (base & 15)) & 0xFFF) as usize] = 0;
device.rsp.mem[((address + ((base + 4) & 15)) & 0xFFF) as usize] = 0;
device.rsp.mem[((address + ((base + 8) & 15)) & 0xFFF) as usize] = 0;
device.rsp.mem[((address + ((base + 12) & 15)) & 0xFFF) as usize] = 0;
return;
}
};
let mut offset = 0;
for element in elements {
device.rsp.mem[((address + ((base + offset) & 15)) & 0xFFF) as usize] =
(get_vpr16(device.rsp.cpu.vpr[rt(opcode) as usize], element) >> 7) as u8;
offset += 4;
}
}
pub fn swv(device: &mut device::Device, opcode: u32) {
let mut address = device.rsp.cpu.gpr[rs(opcode) as usize]
.wrapping_add(sign_extend_7bit_offset(voffset(opcode), 4));
let mut element = velement(opcode);
let end = element + 16;
let mut base = address & 7;
address &= !7;
while element < end {
device.rsp.mem[((address + (base & 15)) & 0xFFF) as usize] =
get_vpr8(device.rsp.cpu.vpr[rt(opcode) as usize], element);
base += 1;
element += 1;
}
}
pub fn stv(device: &mut device::Device, opcode: u32) {
let mut address = device.rsp.cpu.gpr[rs(opcode) as usize]
.wrapping_add(sign_extend_7bit_offset(voffset(opcode), 4));
let start = rt(opcode) & !7;
let end = start + 8;
let mut element = 16 - (velement(opcode) & !1);
let mut base = (address & 7).wrapping_sub((velement(opcode) & !1) as u32);
address &= !7;
let mut offset = start;
while offset < end {
device.rsp.mem[((address + (base & 15)) & 0xFFF) as usize] =
get_vpr8(device.rsp.cpu.vpr[offset as usize], element);
base = base.wrapping_add(1);
element += 1;
device.rsp.mem[((address + (base & 15)) & 0xFFF) as usize] =
get_vpr8(device.rsp.cpu.vpr[offset as usize], element);
base = base.wrapping_add(1);
element += 1;
offset += 1;
}
}
pub fn special_reserved(device: &mut device::Device, opcode: u32) {
device.rsp.cpu.gpr[rd(opcode) as usize] =
device.rsp.cpu.gpr[rs(opcode) as usize] >> (device.rsp.cpu.gpr[rs(opcode) as usize] & 31)
}
pub fn reserved(_device: &mut device::Device, _opcode: u32) {}