Compare commits

...

18 Commits

Author SHA1 Message Date
Logan McNaughton 366162e6fe cargo update 2025-09-19 12:56:07 +02:00
Logan McNaughton 2b93fb8aa1 re-add framebuffer tracking (#573) 2025-09-19 11:32:48 +02:00
Logan McNaughton a191701610 update to rust 1.90 (#574)
* update to rust 1.90

* more
2025-09-18 22:46:22 +02:00
Logan McNaughton 0605967c28 modify rsp sync points 2025-09-16 11:39:23 +02:00
Logan McNaughton d6e6a16814 reset device.rdp.last_status_value 2025-09-16 10:02:07 +02:00
Logan McNaughton e374825d5e add release-with-debug profile 2025-09-15 19:23:21 +02:00
Logan McNaughton f6d6746207 use addr_masked 2025-09-15 18:32:25 +02:00
Logan McNaughton 100238f198 optimize some reads/writes (#571) 2025-09-15 18:26:45 +02:00
Logan McNaughton daee53a626 Optimize VU instructions (#570) 2025-09-15 15:50:28 +02:00
Logan McNaughton 018d8ca3e3 fix parallel-rdp build 2025-09-15 12:28:54 +02:00
Logan McNaughton 24d26d864e update parallel-rdp 2025-09-15 12:21:26 +02:00
Logan McNaughton 7b8c549e8e remove rdp sync speed hack (#567) 2025-09-15 09:50:23 +02:00
Logan McNaughton f6c7e3d3c0 use wgpu for gui 2025-09-12 14:16:46 +02:00
Logan McNaughton 374b01dccf cargo update 2025-09-12 13:58:21 +02:00
Logan McNaughton 569b26a067 panic on attempted use of mi repeat mode 2025-09-10 13:16:57 +02:00
Logan McNaughton 380d196ae7 cargo update 2025-09-05 10:54:03 +02:00
Logan McNaughton 4fa1a8ad39 remove redundant get_rooms netplay call (#563)
* remove redundant get_rooms netplay call

* unwrap
2025-09-05 09:32:17 +02:00
Logan McNaughton 8acf3b9de8 bump to 1.1.6 2025-08-24 10:58:58 +02:00
19 changed files with 1748 additions and 1186 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
[target.'cfg(target_os = "linux")']
[target.'cfg(all(target_arch = "aarch64", target_os = "linux"))']
rustflags = ["-C", "link-arg=-fuse-ld=lld"]
[target.'cfg(target_os = "windows")']
Generated
+982 -611
View File
File diff suppressed because it is too large Load Diff
+9 -5
View File
@@ -1,21 +1,21 @@
[package]
name = "gopher64"
version = "1.1.5"
version = "1.1.6"
edition = "2024"
rust-version = "1.89"
rust-version = "1.90"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
dirs = "6.0"
zip = "4.3"
zip = "5.1"
governor = "0.10"
sevenz-rust2 = { version = "0.17", default-features = false }
sevenz-rust2 = { version = "0.18", default-features = false }
chrono = "0.4"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
serde-big-array = "0.5"
slint = { version = "1.12", default-features = false, features = ["compat-1-2", "std", "backend-winit", "renderer-femtovg"] }
slint = { version = "1.12", default-features = false, features = ["compat-1-2", "std", "backend-winit", "renderer-femtovg-wgpu"] }
open = "5.3"
sha2 = "0.10"
sdl3-sys = { version = "0.5", features = ["build-from-source-static"] }
@@ -45,3 +45,7 @@ cc = { version = "1.2", features = ["parallel"] }
[profile.release]
panic = "abort"
lto = "thin"
[profile.release-with-debug]
inherits = "release"
debug = true
+3
View File
@@ -54,6 +54,7 @@ fn main() {
.file("parallel-rdp/parallel-rdp-standalone/util/timeline_trace_file.cpp")
.file("parallel-rdp/parallel-rdp-standalone/util/environment.cpp")
.file("parallel-rdp/parallel-rdp-standalone/util/thread_name.cpp")
.file("parallel-rdp/parallel-rdp-standalone/util/slab_allocator.cpp")
.file("parallel-rdp/interface.cpp")
.file("parallel-rdp/wsi_platform.cpp")
.include("parallel-rdp/parallel-rdp-standalone/parallel-rdp")
@@ -116,6 +117,7 @@ fn main() {
.allowlist_function("rdp_onscreen_message")
.allowlist_function("rdp_check_callback")
.allowlist_function("rdp_new_processor")
.allowlist_function("rdp_check_framebuffers")
.allowlist_function("rdp_state_size")
.allowlist_function("rdp_save_state")
.allowlist_function("rdp_load_state")
@@ -163,6 +165,7 @@ fn main() {
.allowlist_function("_mm_cmplt_epi16")
.allowlist_function("_mm_subs_epu16")
.allowlist_function("_mm_set1_epi32")
.allowlist_function("_mm_set1_epi16")
.blocklist_type("__m128i")
.blocklist_type("int64x2_t")
.wrap_static_fns(true)
+129 -9
View File
@@ -53,14 +53,26 @@ enum vi_registers
VI_REGS_COUNT
};
typedef struct
{
uint32_t depthbuffer_address;
uint32_t framebuffer_address;
uint32_t framebuffer_y_offset;
uint32_t texture_address;
uint32_t framebuffer_pixel_size;
uint32_t framebuffer_width;
uint32_t texture_pixel_size;
uint32_t texture_width;
uint32_t framebuffer_height;
} FrameBufferInfo;
typedef struct
{
uint32_t cmd_data[0x00040000 >> 2];
int cmd_cur;
int cmd_ptr;
uint32_t region;
uint64_t vi_counter;
uint64_t last_sync;
FrameBufferInfo frame_buffer_info;
} RDP_DEVICE;
static SDL_Window *window;
@@ -75,6 +87,9 @@ static GFX_INFO gfx_info;
static const uint32_t *fragment_spirv;
static size_t fragment_size;
std::vector<bool> rdram_dirty;
uint64_t sync_signal;
static TTF_Font *message_font;
static std::queue<std::string> messages;
static uint64_t message_timer;
@@ -240,6 +255,9 @@ void rdp_new_processor(GFX_INFO _gfx_info)
{
gfx_info = _gfx_info;
sync_signal = 0;
rdram_dirty.assign(gfx_info.RDRAM_SIZE >> 3, false);
if (processor)
{
delete processor;
@@ -527,7 +545,6 @@ void rdp_render_frame()
{
auto &device = wsi->get_device();
render_frame(device);
rdp_device.vi_counter += 1;
}
void rdp_update_screen()
@@ -547,6 +564,27 @@ CALL_BACK rdp_check_callback()
return return_value;
}
void rdp_check_framebuffers(uint32_t address, uint32_t length)
{
if (sync_signal)
{
address >>= 3;
length = (length + 7) >> 3;
for (uint32_t i = 0; i < length; i++)
{
if (address + i >= rdram_dirty.size())
return;
if (rdram_dirty[address + i])
{
processor->wait_for_timeline(sync_signal);
rdram_dirty.assign(gfx_info.RDRAM_SIZE >> 3, false);
sync_signal = 0;
return;
}
}
}
}
size_t rdp_state_size()
{
return sizeof(RDP_DEVICE);
@@ -554,6 +592,7 @@ size_t rdp_state_size()
void rdp_save_state(uint8_t *state)
{
processor->wait_for_timeline(processor->signal_timeline());
memcpy(state, &rdp_device, sizeof(RDP_DEVICE));
}
@@ -569,6 +608,24 @@ void rdp_onscreen_message(const char *_message)
messages.push(_message);
}
uint32_t pixel_size(uint32_t pixel_type, uint32_t area)
{
switch (pixel_type)
{
case 0:
return area / 2;
case 1:
return area;
case 2:
return area * 2;
case 3:
return area * 4;
default:
printf("Invalid pixel size: %u\n", pixel_type);
return 0;
}
}
uint64_t rdp_process_commands()
{
uint64_t interrupt_timer = 0;
@@ -632,6 +689,69 @@ uint64_t rdp_process_commands()
switch (RDP::Op(command))
{
case RDP::Op::FillZBufferTriangle:
case RDP::Op::TextureZBufferTriangle:
case RDP::Op::ShadeZBufferTriangle:
case RDP::Op::ShadeTextureZBufferTriangle:
{
uint32_t offset_address = (rdp_device.frame_buffer_info.depthbuffer_address + pixel_size(2, rdp_device.frame_buffer_info.framebuffer_y_offset * rdp_device.frame_buffer_info.framebuffer_width)) >> 3;
if (offset_address < rdram_dirty.size() && !rdram_dirty[offset_address])
{
std::fill_n(rdram_dirty.begin() + offset_address, (pixel_size(2, rdp_device.frame_buffer_info.framebuffer_width * rdp_device.frame_buffer_info.framebuffer_height) + 7) >> 3, true);
}
}
case RDP::Op::FillTriangle:
case RDP::Op::TextureTriangle:
case RDP::Op::ShadeTriangle:
case RDP::Op::ShadeTextureTriangle:
case RDP::Op::TextureRectangle:
case RDP::Op::TextureRectangleFlip:
case RDP::Op::FillRectangle:
{
uint32_t offset_address = (rdp_device.frame_buffer_info.framebuffer_address + pixel_size(rdp_device.frame_buffer_info.framebuffer_pixel_size, rdp_device.frame_buffer_info.framebuffer_y_offset * rdp_device.frame_buffer_info.framebuffer_width)) >> 3;
if (offset_address < rdram_dirty.size() && !rdram_dirty[offset_address])
{
std::fill_n(rdram_dirty.begin() + offset_address, (pixel_size(rdp_device.frame_buffer_info.framebuffer_pixel_size, rdp_device.frame_buffer_info.framebuffer_width * rdp_device.frame_buffer_info.framebuffer_height) + 7) >> 3, true);
}
}
break;
case RDP::Op::LoadTLut:
case RDP::Op::LoadTile:
{
uint32_t upper_left_t = (w1 & 0xFFF) >> 2;
uint32_t offset_address = (rdp_device.frame_buffer_info.texture_address + pixel_size(rdp_device.frame_buffer_info.texture_pixel_size, upper_left_t * rdp_device.frame_buffer_info.texture_width)) >> 3;
if (offset_address < rdram_dirty.size() && !rdram_dirty[offset_address])
{
uint32_t lower_right_t = (w2 & 0xFFF) >> 2;
std::fill_n(rdram_dirty.begin() + offset_address, (pixel_size(rdp_device.frame_buffer_info.texture_pixel_size, (lower_right_t - upper_left_t) * rdp_device.frame_buffer_info.texture_width) + 7) >> 3, true);
}
}
break;
case RDP::Op::LoadBlock:
{
uint32_t upper_left_s = ((w1 >> 12) & 0xFFF) >> 2;
uint32_t upper_left_t = (w1 & 0xFFF) >> 2;
uint32_t offset_address = (rdp_device.frame_buffer_info.texture_address + pixel_size(rdp_device.frame_buffer_info.texture_pixel_size, upper_left_s + upper_left_t * rdp_device.frame_buffer_info.texture_width)) >> 3;
if (offset_address < rdram_dirty.size() && !rdram_dirty[offset_address])
{
uint32_t lower_right_s = ((w2 >> 12) & 0xFFF) >> 2;
std::fill_n(rdram_dirty.begin() + offset_address, (pixel_size(rdp_device.frame_buffer_info.texture_pixel_size, lower_right_s - upper_left_s) + 7) >> 3, true);
}
}
break;
case RDP::Op::SetColorImage:
rdp_device.frame_buffer_info.framebuffer_address = (w2 & 0x00FFFFFF);
rdp_device.frame_buffer_info.framebuffer_pixel_size = (w1 >> 19) & 0x3;
rdp_device.frame_buffer_info.framebuffer_width = (w1 & 0x3FF) + 1;
break;
case RDP::Op::SetMaskImage:
rdp_device.frame_buffer_info.depthbuffer_address = (w2 & 0x00FFFFFF);
break;
case RDP::Op::SetTextureImage:
rdp_device.frame_buffer_info.texture_address = (w2 & 0x00FFFFFF);
rdp_device.frame_buffer_info.texture_pixel_size = (w1 >> 19) & 0x3;
rdp_device.frame_buffer_info.texture_width = (w1 & 0x3FF) + 1;
break;
case RDP::Op::SetScissor:
{
uint32_t upper_left_x = ((w1 >> 12) & 0xFFF) >> 2;
@@ -646,14 +766,14 @@ uint64_t rdp_process_commands()
{
rdp_device.region = 0;
}
break;
rdp_device.frame_buffer_info.framebuffer_y_offset = upper_left_y;
rdp_device.frame_buffer_info.framebuffer_height = lower_right_y - upper_left_y;
}
break;
case RDP::Op::SyncFull:
if (rdp_device.last_sync != rdp_device.vi_counter)
{
processor->wait_for_timeline(processor->signal_timeline());
rdp_device.last_sync = rdp_device.vi_counter;
}
sync_signal = processor->signal_timeline();
interrupt_timer = rdp_device.region;
if (interrupt_timer == 0)
interrupt_timer = 5000;
+1
View File
@@ -47,6 +47,7 @@ extern "C"
uint64_t rdp_process_commands();
void rdp_onscreen_message(const char *_message);
void rdp_new_processor(GFX_INFO _gfx_info);
void rdp_check_framebuffers(uint32_t address, uint32_t length);
size_t rdp_state_size();
void rdp_save_state(uint8_t *state);
void rdp_load_state(const uint8_t *state);
+1 -1
View File
@@ -1,2 +1,2 @@
[toolchain]
channel = "1.89.0"
channel = "1.90.0"
+2 -1
View File
@@ -81,7 +81,8 @@ fn update_init_mode(device: &mut device::Device, w: u32) {
device.mi.regs[MI_INIT_MODE_REG as usize] &= !MI_INIT_MODE
}
if w & MI_SET_INIT != 0 {
device.mi.regs[MI_INIT_MODE_REG as usize] |= MI_INIT_MODE
panic!("MI_SET_INIT not implemented")
//device.mi.regs[MI_INIT_MODE_REG as usize] |= MI_INIT_MODE
}
if w & MI_CLR_EBUS != 0 {
device.mi.regs[MI_INIT_MODE_REG as usize] &= !MI_EBUS_MODE
+4
View File
@@ -1,4 +1,5 @@
use crate::device;
use crate::ui;
use rand_chacha::rand_core::RngCore;
const PI_DRAM_ADDR_REG: u32 = 0;
@@ -92,6 +93,9 @@ fn dma_write(device: &mut device::Device) {
length -= dram_addr & 0x7;
}
// check RDP before PI writes to RDRAM
ui::video::check_framebuffers(dram_addr, length);
let cycles = (handler.write)(device, cart_addr, dram_addr, length);
device::events::create_event(device, device::events::EVENT_TYPE_PI, cycles);
+5
View File
@@ -1,4 +1,5 @@
use crate::device;
use crate::ui;
use std::alloc::{Layout, alloc_zeroed};
//const RDRAM_CONFIG_REG: u32 = 0;
@@ -50,6 +51,8 @@ pub fn read_mem(
);
let masked_address = address as usize & RDRAM_MASK;
ui::video::check_framebuffers(masked_address as u32, 4);
u32::from_ne_bytes(
device
.rdram
@@ -62,6 +65,8 @@ pub fn read_mem(
}
pub fn write_mem(device: &mut device::Device, address: u64, value: u32, mask: u32) {
ui::video::check_framebuffers(address as u32, 4);
let mut data = u32::from_ne_bytes(
device
.rdram
+14 -10
View File
@@ -1,4 +1,5 @@
use crate::device;
use crate::ui;
const SP_MEM_ADDR_REG: u32 = 0;
const SP_DRAM_ADDR_REG: u32 = 1;
@@ -146,6 +147,7 @@ fn do_dma(device: &mut device::Device, dma: RspDma) {
let mut dram_addr = dma.dramaddr & 0xfffff8;
let offset = dma.memaddr & 0x1000;
ui::video::check_framebuffers(dram_addr, count * (length + skip) - skip);
if dma.dir == DmaDir::Read {
let mut j = 0;
while j < count {
@@ -219,6 +221,8 @@ fn fifo_push(device: &mut device::Device, dir: DmaDir) {
panic!("RSP DMA already full")
}
device.rsp.cpu.sync_point = true;
if device.rsp.regs[SP_DMA_BUSY_REG as usize] != 0 {
device.rsp.fifo[1].dir = dir;
if dir == DmaDir::Read {
@@ -276,21 +280,20 @@ pub fn read_regs(
}
let reg = (address & 0xFFFF) >> 2;
match reg as u32 {
SP_DMA_BUSY_REG | SP_DMA_FULL_REG => {
if device.rsp.regs[reg as usize] != 0 {
device.rsp.cpu.sync_point = true;
}
device.rsp.regs[reg as usize]
}
SP_STATUS_REG => {
let value = device.rsp.regs[reg as usize]
& !(SP_STATUS_HALT | SP_STATUS_BROKE | SP_STATUS_INTR_BREAK);
& (SP_STATUS_SIG0
| SP_STATUS_SIG1
| SP_STATUS_SIG2
| SP_STATUS_SIG3
| SP_STATUS_SIG4
| SP_STATUS_SIG5
| SP_STATUS_SIG6
| SP_STATUS_SIG7);
if value == device.rsp.last_status_value && value != 0 {
device.rsp.cpu.sync_point = true;
}
if value & (SP_STATUS_DMA_BUSY | SP_STATUS_DMA_FULL) != 0 {
device.rsp.cpu.sync_point = true;
}
device.rsp.last_status_value = value;
device.rsp.regs[reg as usize]
}
@@ -464,6 +467,7 @@ fn update_sp_status(device: &mut device::Device, w: u32) {
fn do_task(device: &mut device::Device) {
device.rsp.cpu.sync_point = false;
device.rsp.last_status_value = 0;
device.rdp.last_status_value = 0;
if device.rsp.regs[SP_DMA_BUSY_REG as usize] == 1 {
device.rsp.run_after_dma = true
} else {
+138 -43
View File
@@ -304,25 +304,44 @@ 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];
// Optimize for aligned access when possible
let addr_masked = address as usize & 0xFFF;
let value = if addr_masked <= 0xFFE {
u16::from_be_bytes(
device.rsp.mem[addr_masked..addr_masked + 2]
.try_into()
.unwrap(),
)
} else {
let w0 = device.rsp.mem[addr_masked];
let w1 = device.rsp.mem[(addr_masked + 1) & 0xFFF];
((w0 as u16) << 8) | w1 as u16
};
device.rsp.cpu.gpr[rt(opcode) as usize] =
(((w[0] as u16) << 8) | w[1] as u16) as i16 as i32 as u32
device.rsp.cpu.gpr[rt(opcode) as usize] = value 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];
for (i, item) in w.iter_mut().enumerate() {
*item = device.rsp.mem[(address as usize + i) & 0xFFF];
}
// Optimize for aligned access when possible
let addr_masked = address as usize & 0xFFF;
let value = if addr_masked <= 0xFFC {
u32::from_be_bytes(
device.rsp.mem[addr_masked..addr_masked + 4]
.try_into()
.unwrap(),
)
} else {
let mut value = 0;
for i in 0..4 {
value |= (device.rsp.mem[(addr_masked + i) & 0xFFF] as u32) << (8 * (3 - i));
}
value
};
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)
device.rsp.cpu.gpr[rt(opcode) as usize] = value;
}
pub fn lbu(device: &mut device::Device, opcode: u32) {
@@ -336,24 +355,44 @@ 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];
// Optimize for aligned access when possible
let addr_masked = address as usize & 0xFFF;
let value = if addr_masked <= 0xFFE {
u16::from_be_bytes(
device.rsp.mem[addr_masked..addr_masked + 2]
.try_into()
.unwrap(),
)
} else {
let w0 = device.rsp.mem[addr_masked];
let w1 = device.rsp.mem[(addr_masked + 1) & 0xFFF];
((w0 as u16) << 8) | w1 as u16
};
device.rsp.cpu.gpr[rt(opcode) as usize] = (((w[0] as u16) << 8) | w[1] as u16) as u32
device.rsp.cpu.gpr[rt(opcode) as usize] = value 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];
for (i, item) in w.iter_mut().enumerate() {
*item = device.rsp.mem[(address as usize + i) & 0xFFF];
}
// Optimize for aligned access when possible
let addr_masked = address as usize & 0xFFF;
let value = if addr_masked <= 0xFFC {
u32::from_be_bytes(
device.rsp.mem[addr_masked..addr_masked + 4]
.try_into()
.unwrap(),
)
} else {
let mut value = 0;
for i in 0..4 {
value |= (device.rsp.mem[(addr_masked + i) & 0xFFF] as u32) << (8 * (3 - i));
}
value
};
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)
device.rsp.cpu.gpr[rt(opcode) as usize] = value;
}
pub fn sb(device: &mut device::Device, opcode: u32) {
@@ -367,18 +406,30 @@ 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;
let addr_masked = address as usize & 0xFFF;
let value = device.rsp.cpu.gpr[rt(opcode) as usize] as u16;
// Optimize for aligned access when possible
if addr_masked <= 0xFFE {
device.rsp.mem[addr_masked..addr_masked + 2].copy_from_slice(&value.to_be_bytes());
} else {
device.rsp.mem[addr_masked] = (value >> 8) as u8;
device.rsp.mem[(addr_masked + 1) & 0xFFF] = value 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);
for i in 0..4 {
device.rsp.mem[(address as usize + i) & 0xFFF] =
(device.rsp.cpu.gpr[rt(opcode) as usize] >> ((3 - i) * 8)) as u8;
let addr_masked = address as usize & 0xFFF;
let value = device.rsp.cpu.gpr[rt(opcode) as usize];
// Optimize for aligned access when possible
if addr_masked <= 0xFFC {
device.rsp.mem[addr_masked..addr_masked + 4].copy_from_slice(&value.to_be_bytes());
} else {
for i in 0..4 {
device.rsp.mem[(addr_masked + i) & 0xFFF] = (value >> ((3 - i) * 8)) as u8;
}
}
}
@@ -737,10 +788,21 @@ pub fn llv(device: &mut device::Device, opcode: u32) {
let mut element = velement(opcode);
if element.is_multiple_of(4) {
let mut value = 0;
for i in 0..4 {
value |= (device.rsp.mem[((address + i) & 0xFFF) as usize] as u32) << (8 * (3 - i));
}
// Optimize for aligned access when possible
let addr_masked = address as usize & 0xFFF;
let value = if addr_masked <= 0xFFC {
u32::from_be_bytes(
device.rsp.mem[addr_masked..addr_masked + 4]
.try_into()
.unwrap(),
)
} else {
let mut value = 0;
for i in 0..4 {
value |= (device.rsp.mem[(addr_masked + i) & 0xFFF] as u32) << (8 * (3 - i));
}
value
};
modify_vpr32(
&mut device.rsp.cpu.vpr[rt(opcode) as usize],
element / 4,
@@ -767,10 +829,21 @@ pub fn ldv(device: &mut device::Device, opcode: u32) {
let mut element = velement(opcode);
if element.is_multiple_of(8) {
let mut value = 0;
for i in 0..8 {
value |= (device.rsp.mem[((address + i) & 0xFFF) as usize] as u64) << (8 * (7 - i));
}
// Optimize for aligned access when possible
let addr_masked = address as usize & 0xFFF;
let value = if addr_masked <= 0xFF8 {
u64::from_be_bytes(
device.rsp.mem[addr_masked..addr_masked + 8]
.try_into()
.unwrap(),
)
} else {
let mut value = 0;
for i in 0..8 {
value |= (device.rsp.mem[(addr_masked + i) & 0xFFF] as u64) << (8 * (7 - i));
}
value
};
modify_vpr64(
&mut device.rsp.cpu.vpr[rt(opcode) as usize],
element / 8,
@@ -797,10 +870,21 @@ pub fn lqv(device: &mut device::Device, opcode: u32) {
let mut element = velement(opcode);
if element == 0 && address.is_multiple_of(16) {
let mut value = 0;
for i in 0..16 {
value |= (device.rsp.mem[((address + i) & 0xFFF) as usize] as u128) << (8 * (15 - i));
}
// Optimize for aligned 16-byte access
let addr_masked = address as usize & 0xFFF;
let value = if addr_masked <= 0xFF0 {
u128::from_be_bytes(
device.rsp.mem[addr_masked..addr_masked + 16]
.try_into()
.unwrap(),
)
} else {
let mut value = 0;
for i in 0..16 {
value |= (device.rsp.mem[(addr_masked + i) & 0xFFF] as u128) << (8 * (15 - i));
}
value
};
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);
@@ -823,10 +907,21 @@ pub fn lrv(device: &mut device::Device, opcode: u32) {
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));
}
// Optimize for aligned 16-byte access
let addr_masked = address as usize & 0xFFF;
let value = if addr_masked <= 0xFF0 {
u128::from_be_bytes(
device.rsp.mem[addr_masked..addr_masked + 16]
.try_into()
.unwrap(),
)
} else {
let mut value = 0;
for i in 0..16 {
value |= (device.rsp.mem[(addr_masked + i) & 0xFFF] as u128) << (8 * (15 - i));
}
value
};
modify_vpr128(&mut device.rsp.cpu.vpr[rt(opcode) as usize], value);
} else {
while element < 16 {
File diff suppressed because it is too large Load Diff
+3
View File
@@ -1,6 +1,7 @@
use rand_chacha::rand_core::RngCore;
use crate::device;
use crate::ui;
const SI_DRAM_ADDR_REG: u32 = 0;
const SI_PIF_ADDR_RD64B_REG: u32 = 1;
@@ -98,6 +99,8 @@ fn copy_pif_rdram(device: &mut device::Device) {
i += 4;
}
} else if device.si.dma_dir == DmaDir::Read {
// check RDP before SI writes to RDRAM
ui::video::check_framebuffers(dram_addr as u32, device::pif::PIF_RAM_SIZE as u32);
let mut i = 0;
while i < device::pif::PIF_RAM_SIZE {
let data = u32::from_be_bytes(device.pif.ram[i..i + 4].try_into().unwrap());
+4 -2
View File
@@ -9,6 +9,7 @@ export component NetplayJoin inherits Window {
in-out property sessions <=> NetplayData.sessions;
in-out property current_session <=> NetplayData.current_session;
in-out property room_urls <=> NetplayData.room_urls;
in-out property room_ports <=> NetplayData.room_ports;
in-out property game_name <=> NetplayData.game_name;
in-out property game_hash <=> NetplayData.game_hash;
in-out property game_cheats <=> NetplayData.game_cheats;
@@ -19,7 +20,7 @@ export component NetplayJoin inherits Window {
in-out property rom_dir <=> NetplayData.rom_dir;
callback refresh_session();
callback select_rom(string);
callback join_session(string, string, string, string, string);
callback join_session(string, string, string, string, int);
preferred-width: 700px;
VerticalBox {
@@ -93,6 +94,7 @@ export component NetplayJoin inherits Window {
NetplayData.current_session = -1;
NetplayData.sessions = [];
NetplayData.room_urls = [];
NetplayData.room_ports = [];
refresh_session();
}
}
@@ -129,7 +131,7 @@ export component NetplayJoin inherits Window {
NetplayData.game_hash,
NetplayData.password,
NetplayData.room_urls[NetplayData.current_session],
NetplayData.sessions[NetplayData.current_session][1].text);
NetplayData.room_ports[NetplayData.current_session]);
}
}
}
+1
View File
@@ -19,6 +19,7 @@ export global NetplayData {
in-out property <string> session_name;
in-out property <[[StandardListViewItem]]> sessions;
in-out property <[string]> room_urls;
in-out property <[int]> room_ports;
in-out property <int> current_session: -1;
in-out property <string> rom_dir;
in-out property <string> custom_server_url;
+15 -55
View File
@@ -491,6 +491,7 @@ fn update_sessions(weak: slint::Weak<NetplayJoin>) {
tokio::spawn(async move {
let mut sessions = vec![];
let mut room_urls = vec![];
let mut room_ports = vec![];
for (server_name, server_url) in servers.iter() {
if let Ok(Ok((socket, _response))) = tokio::time::timeout(
std::time::Duration::from_secs(2),
@@ -533,6 +534,7 @@ fn update_sessions(weak: slint::Weak<NetplayJoin>) {
for room in rooms {
let mut session = vec![];
room_urls.push(server_url.into());
room_ports.push(room.port.unwrap());
session.push(slint::StandardListViewItem::from(
slint::SharedString::from(server_name),
@@ -585,6 +587,11 @@ fn update_sessions(weak: slint::Weak<NetplayJoin>) {
std::rc::Rc::new(room_urls_vec);
handle.set_room_urls(slint::ModelRc::from(room_urls_model));
let room_ports_vec = slint::VecModel::from(room_ports.to_vec());
let room_ports_model: std::rc::Rc<slint::VecModel<i32>> =
std::rc::Rc::new(room_ports_vec);
handle.set_room_ports(slint::ModelRc::from(room_ports_model));
handle.set_current_session(-1);
handle.set_pending_refresh(false);
})
@@ -732,7 +739,7 @@ fn join_session(
player_name: String,
game_hash: String,
password: String,
room_name: String,
room_port: i32,
fullscreen: bool,
weak_app: slint::Weak<AppWindow>,
weak: slint::Weak<NetplayJoin>,
@@ -740,73 +747,26 @@ fn join_session(
tokio::spawn(async move {
let now_utc = chrono::Utc::now().timestamp_millis().to_string();
let hasher = Sha256::new().chain_update(&now_utc).chain_update(EMU_NAME);
let request_rooms = NetplayMessage {
message_type: "request_get_rooms".to_string(),
player_name: None,
client_sha: None,
netplay_version: Some(NETPLAY_VERSION),
player_names: None,
emulator: Some(EMU_NAME.to_string()),
accept: None,
rooms: None,
message: None,
auth_time: Some(now_utc),
auth: Some(format!("{:x}", hasher.finalize())),
room: None,
};
netplay_write_sender.send(Some(request_rooms)).unwrap();
let mut port = 0;
match tokio::time::timeout(
std::time::Duration::from_secs(2),
netplay_read_receiver.recv(),
)
.await
{
Ok(Ok(message)) => {
if message.message_type == "reply_get_rooms"
&& message.accept.unwrap() == 0
&& let Some(rooms) = message.rooms
{
for room in rooms {
if room.room_name.unwrap() == room_name {
port = room.port.unwrap_or(0);
}
}
}
}
Ok(Err(err)) => {
panic!("netplay_read_receiver error: {err}");
}
Err(_) => {
weak.upgrade_in_event_loop(move |handle| {
handle.set_pending_session(false);
show_netplay_error("Server did not respond".to_string());
})
.unwrap();
}
}
let join_room = NetplayMessage {
message_type: "request_join_room".to_string(),
player_name: Some(player_name),
client_sha: Some(env!("GIT_HASH").to_string()),
netplay_version: None,
emulator: None,
netplay_version: Some(NETPLAY_VERSION),
emulator: Some(EMU_NAME.to_string()),
accept: None,
message: None,
rooms: None,
auth_time: None,
player_names: None,
auth: None,
auth_time: Some(now_utc),
auth: Some(format!("{:x}", hasher.finalize())),
room: Some(NetplayRoom {
room_name: None,
password: Some(password),
game_name: None,
md5: Some(game_hash),
protected: None,
port: Some(port),
port: Some(room_port),
features: None,
buffer_target: None,
}),
@@ -1200,7 +1160,7 @@ pub fn setup_join_window(
});
let weak = join_window.as_weak();
join_window.on_join_session(
move |player_name, game_hash, password, room_url, room_name| {
move |player_name, game_hash, password, room_url, room_port| {
let _ = netplay_write_sender.send(None); // close current websocket if any
manage_websocket(
room_url.to_string(),
@@ -1215,7 +1175,7 @@ pub fn setup_join_window(
player_name.to_string(),
game_hash.to_string(),
password.to_string(),
room_name.to_string(),
room_port,
fullscreen,
weak_app.clone(),
weak.clone(),
+4
View File
@@ -192,6 +192,10 @@ pub fn process_rdp_list() -> u64 {
unsafe { rdp_process_commands() }
}
pub fn check_framebuffers(address: u32, length: u32) {
unsafe { rdp_check_framebuffers(address, length) }
}
pub fn onscreen_message(_ui: &ui::Ui, message: &str) {
unsafe { rdp_onscreen_message(std::ffi::CString::new(message).unwrap().as_ptr()) };
}