Compare commits

...

9 Commits

Author SHA1 Message Date
Logan McNaughton 63b8b79dd7 More RSP cleanup 2025-01-11 15:02:22 +01:00
Logan McNaughton 90c9bfbf09 More RSP Cleanup (#125) 2025-01-11 14:46:13 +01:00
Logan McNaughton 9a3a56d0c6 RSP cleanup (#124) 2025-01-11 14:34:16 +01:00
Logan McNaughton e71d5a1b2d add build flags for aarch64 (#123) 2025-01-10 11:16:09 +01:00
Logan McNaughton a731b870da add portable mode (#122)
* add portable mode

* readme

* more

* more

* more
2025-01-10 09:26:40 +01:00
Logan McNaughton c54356e6f4 Fix VRU demo encoding (#120) 2025-01-09 21:10:03 +01:00
Logan McNaughton b2d2089d95 Remove un-needed entry in Cargo.toml (#119) 2025-01-09 18:39:39 +01:00
Logan McNaughton a47801b9cb Minor changes to boot latest LibDragon ROMs (#117) 2025-01-09 16:11:48 +01:00
Logan McNaughton 9a76bcd303 Bump to 0.1.15 (#116) 2025-01-09 10:38:34 +01:00
15 changed files with 192 additions and 192 deletions
+3
View File
@@ -1,2 +1,5 @@
[target.'cfg(target_arch = "x86_64")']
rustflags = ["-C", "target-cpu=x86-64-v3"]
[target.'cfg(target_arch = "aarch64")']
rustflags = ["-C", "target-cpu=cortex-a76"]
+2 -3
View File
@@ -1,6 +1,6 @@
[package]
name = "gopher64"
version = "0.1.14"
version = "0.1.15"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -14,7 +14,6 @@ chrono = "0.4"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
eframe = "0.30"
epaint = "0.30"
rfd = "0.15"
sha2 = "0.10"
rusttype = "0.9"
@@ -31,7 +30,7 @@ features = ["static-link","bundled"]
[build-dependencies]
winres = "0.1"
cc = { version = "1.0", features = ["parallel"] }
cc = { version = "1.2", features = ["parallel"] }
[profile.release]
lto = true
+4
View File
@@ -46,6 +46,10 @@ You can create you own mappings by running `./gopher64 --configure-input-profile
In order to use a controller (for example, an Xbox controller), run `./gopher64 --list-controllers` to get a list of attached controllers, and then assign it by doing `./gopher64 --assign-controller <controller_number> --port 1`
## portable mode
If you would like to keep all the game data in the same folder as executable, you just need to create a file called "portable.txt" in the same directory as the executable.
## contributing
I am very open to contributions! Please reach out to me via a GitHub issue, or via discord (loganmc10) before doing substantial work on a PR.
+16 -9
View File
@@ -52,11 +52,15 @@ fn main() {
.include("parallel-rdp/parallel-rdp-standalone/util")
.includes(std::env::var("DEP_SDL2_INCLUDE"));
#[cfg(target_os = "windows")]
{
#[cfg(target_arch = "x86_64")]
{
let os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();
let arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap();
if os == "windows" {
if arch == "x86_64" {
build.flag("/arch:AVX2");
} else if arch == "aarch64" {
build.flag("/arch:armv8.2");
} else {
panic!("unknown arch")
}
build.flag("-DVK_USE_PLATFORM_WIN32_KHR");
@@ -64,13 +68,16 @@ fn main() {
.set_icon("data/icon.ico")
.compile()
.unwrap();
}
#[cfg(any(target_os = "linux", target_os = "macos"))]
{
#[cfg(target_arch = "x86_64")]
{
} else if os == "linux" || os == "macos" {
if arch == "x86_64" {
build.flag("-march=x86-64-v3");
} else if arch == "aarch64" {
build.flag("-march=armv8.2-a");
} else {
panic!("unknown arch")
}
} else {
panic!("unknown OS")
}
build.compile("parallel-rdp");
+9 -4
View File
@@ -36,7 +36,12 @@ pub mod unmapped;
pub mod vi;
pub mod vru;
pub fn run_game(file_path: &std::path::Path, device: &mut Device, fullscreen: bool) {
pub fn run_game(
file_path: &std::path::Path,
data_dir: std::path::PathBuf,
device: &mut Device,
fullscreen: bool,
) {
let rom_contents = get_rom_contents(file_path);
cart_rom::init(device, rom_contents); // cart needs to come before rdram
@@ -59,7 +64,7 @@ pub fn run_game(file_path: &std::path::Path, device: &mut Device, fullscreen: bo
vi::init(device);
cpu::init(device);
ui::storage::init(&mut device.ui);
ui::storage::init(&mut device.ui, data_dir);
ui::storage::load_saves(&mut device.ui);
cart_rom::load_rom_save(device);
@@ -166,7 +171,7 @@ pub struct Device {
}
impl Device {
pub fn new() -> Device {
pub fn new(config_dir: std::path::PathBuf) -> Device {
let mut byte_swap: usize = 0;
let test: [u8; 4] = [1, 2, 3, 4];
// if the host computer is little endian, that means the RDRAM will be stored as little endian
@@ -175,7 +180,7 @@ impl Device {
byte_swap = 3;
}
Device {
ui: ui::Ui::new(),
ui: ui::Ui::new(config_dir),
byte_swap,
cpu: cpu::Cpu {
cop0: cop0::Cop0 {
+2 -1
View File
@@ -13,7 +13,8 @@ const PI_BSD_DOM2_LAT_REG: u32 = 9;
const PI_BSD_DOM2_PWD_REG: u32 = 10;
const PI_BSD_DOM2_PGS_REG: u32 = 11;
const PI_BSD_DOM2_RLS_REG: u32 = 12;
pub const PI_REGS_COUNT: u32 = 13;
//const UNKNOWN_REG: u32 = 13; //LibDragon
pub const PI_REGS_COUNT: u32 = 14;
/* PI_STATUS - read */
const PI_STATUS_DMA_BUSY: u32 = 1 << 0;
+3 -2
View File
@@ -57,10 +57,11 @@ pub fn write_mem(device: &mut device::Device, address: u64, value: u32, mask: u3
pub fn read_regs(
_device: &mut device::Device,
_address: u64,
address: u64,
_access_size: device::memory::AccessSize,
) -> u32 {
panic!("rdram read reg");
println!("Warning: read from RDRAM reg {:#x}", address);
0
}
pub fn write_regs(_device: &mut device::Device, _address: u64, _value: u32, _mask: u32) {
+27 -40
View File
@@ -39,7 +39,7 @@ pub fn sign_extend_7bit_offset(offset: u8, shift_amount: u32) -> u32 {
(((soffset) as i32) as u32) << shift_amount
}
pub fn modify_vpr_byte(vpr: &mut u128, value: u8, element: u8) {
pub fn modify_vpr_byte(vpr: &mut u128, element: u8, value: u8) {
let pos = 15 - (element & 15);
let mask = 0xFF << (pos * 8);
*vpr &= !mask;
@@ -51,7 +51,7 @@ pub fn get_vpr_byte(vpr: u128, element: u8) -> u8 {
(vpr >> (pos * 8)) as u8
}
pub fn modify_vpr_element(vpr: &mut u128, value: u16, element: u8) {
pub fn modify_vpr_element(vpr: &mut u128, element: u8, value: u16) {
let pos = 7 - (element & 7);
let mask = 0xFFFF << (pos * 16);
*vpr &= !mask;
@@ -508,7 +508,7 @@ pub fn cfc2(device: &mut device::Device, opcode: u32) {
lo = &mut device.rsp.cpu.vce;
}
_ => {
panic!("unknown ctc2")
panic!("unknown cfc2")
}
}
@@ -522,14 +522,14 @@ pub fn cfc2(device: &mut device::Device, opcode: u32) {
pub fn mtc2(device: &mut device::Device, opcode: u32) {
modify_vpr_byte(
&mut device.rsp.cpu.vpr[rd(opcode) as usize],
(device.rsp.cpu.gpr[rt(opcode) as usize] >> 8) as u8,
velement(opcode),
(device.rsp.cpu.gpr[rt(opcode) as usize] >> 8) as u8,
);
if velement(opcode) != 15 {
modify_vpr_byte(
&mut device.rsp.cpu.vpr[rd(opcode) as usize],
device.rsp.cpu.gpr[rt(opcode) as usize] as u8,
velement(opcode) + 1,
device.rsp.cpu.gpr[rt(opcode) as usize] as u8,
);
}
}
@@ -591,8 +591,8 @@ pub fn lbv(device: &mut device::Device, opcode: u32) {
let element = velement(opcode);
modify_vpr_byte(
&mut device.rsp.cpu.vpr[rt(opcode) as usize],
device.rsp.mem[(address & 0xFFF) as usize],
element,
device.rsp.mem[(address & 0xFFF) as usize],
);
}
@@ -605,8 +605,8 @@ pub fn lsv(device: &mut device::Device, opcode: u32) {
while element < end {
modify_vpr_byte(
&mut device.rsp.cpu.vpr[rt(opcode) as usize],
device.rsp.mem[(address & 0xFFF) as usize],
element,
device.rsp.mem[(address & 0xFFF) as usize],
);
address += 1;
element += 1;
@@ -622,8 +622,8 @@ pub fn llv(device: &mut device::Device, opcode: u32) {
while element < end {
modify_vpr_byte(
&mut device.rsp.cpu.vpr[rt(opcode) as usize],
device.rsp.mem[(address & 0xFFF) as usize],
element,
device.rsp.mem[(address & 0xFFF) as usize],
);
address += 1;
element += 1;
@@ -639,8 +639,8 @@ pub fn ldv(device: &mut device::Device, opcode: u32) {
while element < end {
modify_vpr_byte(
&mut device.rsp.cpu.vpr[rt(opcode) as usize],
device.rsp.mem[(address & 0xFFF) as usize],
element,
device.rsp.mem[(address & 0xFFF) as usize],
);
address += 1;
element += 1;
@@ -656,8 +656,8 @@ pub fn lqv(device: &mut device::Device, opcode: u32) {
while element < end {
modify_vpr_byte(
&mut device.rsp.cpu.vpr[rt(opcode) as usize],
device.rsp.mem[(address & 0xFFF) as usize],
element,
device.rsp.mem[(address & 0xFFF) as usize],
);
address += 1;
element += 1;
@@ -673,8 +673,8 @@ pub fn lrv(device: &mut device::Device, opcode: u32) {
while element < 16 {
modify_vpr_byte(
&mut device.rsp.cpu.vpr[rt(opcode) as usize],
device.rsp.mem[(address & 0xFFF) as usize],
element,
device.rsp.mem[(address & 0xFFF) as usize],
);
address += 1;
element += 1;
@@ -687,16 +687,14 @@ pub fn lpv(device: &mut device::Device, opcode: u32) {
let index = ((address & 7) as u8).wrapping_sub(velement(opcode));
address &= !7;
let mut offset: u8 = 0;
while offset < 8 {
for offset in 0..8 {
modify_vpr_element(
&mut device.rsp.cpu.vpr[rt(opcode) as usize],
offset,
(device.rsp.mem[((address.wrapping_add(((index.wrapping_add(offset)) & 15) as u32))
& 0xFFF) as usize] as u16)
<< 8,
offset,
);
offset += 1;
}
}
@@ -706,16 +704,14 @@ pub fn luv(device: &mut device::Device, opcode: u32) {
let index = ((address & 7) as u8).wrapping_sub(velement(opcode));
address &= !7;
let mut offset: u8 = 0;
while offset < 8 {
for offset in 0..8 {
modify_vpr_element(
&mut device.rsp.cpu.vpr[rt(opcode) as usize],
offset,
(device.rsp.mem[((address.wrapping_add(((index.wrapping_add(offset)) & 15) as u32))
& 0xFFF) as usize] as u16)
<< 7,
offset,
);
offset += 1;
}
}
@@ -725,16 +721,14 @@ pub fn lhv(device: &mut device::Device, opcode: u32) {
let index = ((address & 7) as u8).wrapping_sub(velement(opcode));
address &= !7;
let mut offset: u8 = 0;
while offset < 8 {
for offset in 0..8 {
modify_vpr_element(
&mut device.rsp.cpu.vpr[rt(opcode) as usize],
offset,
(device.rsp.mem[((address.wrapping_add(((index.wrapping_add(offset * 2)) & 15) as u32))
& 0xFFF) as usize] as u16)
<< 7,
offset,
);
offset += 1;
}
}
@@ -751,25 +745,25 @@ pub fn lfv(device: &mut device::Device, opcode: u32) {
while offset < 4 {
modify_vpr_element(
&mut tmp,
offset,
(device.rsp.mem[((address.wrapping_add(((index.wrapping_add(offset * 4)) & 15) as u32))
& 0xFFF) as usize] as u16)
<< 7,
offset,
);
modify_vpr_element(
&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 + 4,
);
offset += 1;
}
offset = start;
while offset < end {
let value = get_vpr_byte(tmp, offset);
modify_vpr_byte(&mut device.rsp.cpu.vpr[rt(opcode) as usize], value, offset);
modify_vpr_byte(&mut device.rsp.cpu.vpr[rt(opcode) as usize], offset, value);
offset += 1;
}
}
@@ -784,12 +778,11 @@ pub fn ltv(device: &mut device::Device, opcode: u32) {
address = begin + (((velement(opcode)) as u32 + (address & 8)) & 15);
let vtbase = rt(opcode) & !7;
let mut vtoff = (velement(opcode)) as u32 >> 1;
let mut i = 0;
while i < 8 {
for i in 0..8 {
modify_vpr_byte(
&mut device.rsp.cpu.vpr[(vtbase + vtoff) as usize],
device.rsp.mem[(address & 0xFFF) as usize],
i * 2,
device.rsp.mem[(address & 0xFFF) as usize],
);
address += 1;
if address == begin + 16 {
@@ -797,15 +790,14 @@ pub fn ltv(device: &mut device::Device, opcode: u32) {
}
modify_vpr_byte(
&mut device.rsp.cpu.vpr[(vtbase + vtoff) as usize],
device.rsp.mem[(address & 0xFFF) as usize],
i * 2 + 1,
device.rsp.mem[(address & 0xFFF) as usize],
);
address += 1;
if address == begin + 16 {
address = begin
}
vtoff = (vtoff + 1) & 7;
i += 1;
}
}
@@ -934,13 +926,11 @@ pub fn shv(device: &mut device::Device, opcode: u32) {
let element = velement(opcode);
let index = (address & 7) as u8;
address &= !7;
let mut offset = 0;
while offset < 8 {
for offset in 0..8 {
let byte_val = element + offset * 2;
let value = (get_vpr_byte(device.rsp.cpu.vpr[rt(opcode) as usize], byte_val) << 1)
| (get_vpr_byte(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;
offset += 1;
}
}
@@ -949,8 +939,7 @@ pub fn sfv(device: &mut device::Device, opcode: u32) {
.wrapping_add(sign_extend_7bit_offset(voffset(opcode), 4));
let base = address & 7;
address &= !7;
let element = velement(opcode);
let elements = match element {
let elements = match velement(opcode) {
0 | 15 => [0, 1, 2, 3],
1 => [6, 7, 4, 5],
4 => [1, 2, 3, 0],
@@ -967,12 +956,10 @@ pub fn sfv(device: &mut device::Device, opcode: u32) {
}
};
let mut offset = 0;
let mut i = 0;
while i < 4 {
for element in elements {
device.rsp.mem[((address + ((base + offset) & 15)) & 0xFFF) as usize] =
(get_vpr_element(device.rsp.cpu.vpr[rt(opcode) as usize], elements[i]) >> 7) as u8;
(get_vpr_element(device.rsp.cpu.vpr[rt(opcode) as usize], element) >> 7) as u8;
offset += 4;
i += 1;
}
}
+33 -77
View File
@@ -1,4 +1,5 @@
use crate::device;
use crate::device::rsp_su_instructions::{get_vpr_element, modify_vpr_element};
use std::arch::x86_64::*;
pub fn vt(opcode: u32) -> u32 {
@@ -22,34 +23,11 @@ pub fn de(opcode: u32) -> u32 {
}
pub fn clamp_signed_32(value: i32) -> i16 {
if value < -32768 {
return -32768;
}
if value > 32767 {
return 32767;
}
value as i16
value.clamp(-32768, 32767) as i16
}
pub fn clamp_signed_64(value: i64) -> i16 {
if value < -32768 {
return -32768;
}
if value > 32767 {
return 32767;
}
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;
}
(31 - index) as u32
value.clamp(-32768, 32767) as i16
}
pub fn s_clip(x: i64, bits: u32) -> i64 {
@@ -58,18 +36,6 @@ pub fn s_clip(x: i64, bits: u32) -> i64 {
((((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);
(vpr >> (pos * 16)) as u16
}
pub fn vte(device: &device::Device, vt: u32, index: usize) -> __m128i {
unsafe {
_mm_shuffle_epi8(
@@ -178,8 +144,7 @@ pub fn vrndp(device: &mut device::Device, opcode: u32) {
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 {
for n in 0..8 {
let mut product = get_vpr_element(vte, n) as i16 as i32;
if vs(opcode) & 1 != 0 {
product <<= 16
@@ -195,16 +160,14 @@ pub fn vrndp(device: &mut device::Device, opcode: u32) {
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(acch, n, (acc >> 32) as u16);
modify_vpr_element(accm, n, (acc >> 16) as u16);
modify_vpr_element(accl, n, acc as u16);
modify_vpr_element(
&mut device.rsp.cpu.vpr[vd(opcode) as usize],
clamp_signed_64(acc >> 16) as u16,
n,
clamp_signed_64(acc >> 16) as u16,
);
n += 1;
}
}
@@ -220,23 +183,21 @@ pub fn vmulq(device: &mut device::Device, opcode: u32) {
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 {
for n in 0..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(acch, n, (product >> 16) as u16);
modify_vpr_element(accm, n, (product) as u16);
modify_vpr_element(accl, n, 0);
modify_vpr_element(
&mut device.rsp.cpu.vpr[vd(opcode) as usize],
(clamp_signed_32(product >> 1) & !15) as u16,
n,
(clamp_signed_32(product >> 1) & !15) as u16,
);
n += 1;
}
}
@@ -441,8 +402,7 @@ pub fn vrndn(device: &mut device::Device, opcode: u32) {
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 {
for n in 0..8 {
let mut product = get_vpr_element(vte, n) as i16 as i32;
if vs(opcode) & 1 != 0 {
product <<= 16
@@ -458,16 +418,14 @@ pub fn vrndn(device: &mut device::Device, opcode: u32) {
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(acch, n, (acc >> 32) as u16);
modify_vpr_element(accm, n, (acc >> 16) as u16);
modify_vpr_element(accl, n, acc as u16);
modify_vpr_element(
&mut device.rsp.cpu.vpr[vd(opcode) as usize],
clamp_signed_64(acc >> 16) as u16,
n,
clamp_signed_64(acc >> 16) as u16,
);
n += 1;
}
}
@@ -475,8 +433,7 @@ 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 {
for n in 0..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 {
@@ -484,14 +441,13 @@ pub fn vmacq(device: &mut device::Device, opcode: u32) {
} 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(acch, n, (product >> 16) as u16);
modify_vpr_element(accm, n, (product) as u16);
modify_vpr_element(
&mut device.rsp.cpu.vpr[vd(opcode) as usize],
(clamp_signed_32(product >> 1) & !15) as u16,
n,
(clamp_signed_32(product >> 1) & !15) as u16,
);
n += 1;
}
}
@@ -1255,7 +1211,7 @@ pub fn vrcp(device: &mut device::Device, opcode: u32) {
} else if input == -32768 {
result = 0xffff0000
} else {
let shift = count_leading_zeros(data as u32);
let shift = (data as u32).leading_zeros();
let index = (((data as u64) << shift) & 0x7fc00000) >> 22;
result = device.rsp.cpu.reciprocals[index as usize] as u32;
result = (0x10000 | result) << 14;
@@ -1266,8 +1222,8 @@ pub fn vrcp(device: &mut device::Device, opcode: u32) {
device.rsp.cpu.accl = vte;
modify_vpr_element(
&mut device.rsp.cpu.vpr[vd(opcode) as usize],
result as u16,
de(opcode) as u8,
result as u16,
);
}
@@ -1291,7 +1247,7 @@ pub fn vrcpl(device: &mut device::Device, opcode: u32) {
} else if input == -32768 {
result = 0xffff0000
} else {
let shift = count_leading_zeros(data as u32);
let shift = (data as u32).leading_zeros();
let index = (((data as u64) << shift) & 0x7fc00000) >> 22;
result = device.rsp.cpu.reciprocals[index as usize] as u32;
result = (0x10000 | result) << 14;
@@ -1302,8 +1258,8 @@ pub fn vrcpl(device: &mut device::Device, opcode: u32) {
device.rsp.cpu.accl = vte;
modify_vpr_element(
&mut device.rsp.cpu.vpr[vd(opcode) as usize],
result as u16,
de(opcode) as u8,
result as u16,
);
}
@@ -1316,8 +1272,8 @@ pub fn vrcph(device: &mut device::Device, opcode: u32) {
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,
device.rsp.cpu.divout as u16,
);
}
@@ -1329,8 +1285,8 @@ pub fn vmov(device: &mut device::Device, opcode: u32) {
);
modify_vpr_element(
&mut device.rsp.cpu.vpr[vd(opcode) as usize],
value,
de(opcode) as u8,
value,
);
device.rsp.cpu.accl = vte;
}
@@ -1350,7 +1306,7 @@ pub fn vrsq(device: &mut device::Device, opcode: u32) {
} else if input == -32768 {
result = 0xffff0000
} else {
let shift = count_leading_zeros(data as u32);
let shift = (data as u32).leading_zeros();
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;
@@ -1362,8 +1318,8 @@ pub fn vrsq(device: &mut device::Device, opcode: u32) {
device.rsp.cpu.accl = vte;
modify_vpr_element(
&mut device.rsp.cpu.vpr[vd(opcode) as usize],
result as u16,
de(opcode) as u8,
result as u16,
);
}
@@ -1387,7 +1343,7 @@ pub fn vrsql(device: &mut device::Device, opcode: u32) {
} else if input == -32768 {
result = 0xffff0000
} else {
let shift = count_leading_zeros(data as u32);
let shift = (data as u32).leading_zeros();
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;
@@ -1399,8 +1355,8 @@ pub fn vrsql(device: &mut device::Device, opcode: u32) {
device.rsp.cpu.accl = vte;
modify_vpr_element(
&mut device.rsp.cpu.vpr[vd(opcode) as usize],
result as u16,
de(opcode) as u8,
result as u16,
);
}
@@ -1413,8 +1369,8 @@ pub fn vrsqh(device: &mut device::Device, opcode: u32) {
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,
device.rsp.cpu.divout as u16,
);
}
+5 -14
View File
@@ -117,21 +117,12 @@ pub fn process(device: &mut device::Device, channel: usize) {
for i in 0..length {
data.extend(device.vru.word_buffer[offset + i as usize].to_be_bytes());
}
if device.cart.rom[0x3E] == /* Japan */ 0x4A {
let (res, _enc, errors) = encoding_rs::SHIFT_JIS.decode(&data);
if errors {
panic!("Failed to decode Japanese word {:X?}", data);
} else {
device.vru.words.push(res.to_string());
}
let (res, _enc, errors) = encoding_rs::SHIFT_JIS.decode(&data);
if errors {
panic!("Failed to decode Japanese word {:X?}", data);
} else {
let decoded: Result<String, std::string::FromUtf8Error> =
String::from_utf8(data);
if let Ok(result) = decoded {
device.vru.words.push(result)
} else {
panic!("Could not decode VRU word")
}
device.vru.words.push(res.to_string());
}
} else {
offset += 1;
+41 -8
View File
@@ -54,18 +54,47 @@ struct Args {
}
fn main() {
let config_dir = dirs::config_dir().unwrap().join("gopher64");
let cache_dir = dirs::cache_dir().unwrap().join("gopher64");
let exe_path = std::env::current_exe().unwrap();
let portable_dir = exe_path.parent();
let portable = portable_dir.unwrap().join("portable.txt").exists();
let config_dir;
let cache_dir;
let data_dir;
if portable {
config_dir = portable_dir.unwrap().join("portable_data").join("config");
cache_dir = portable_dir.unwrap().join("portable_data").join("cache");
data_dir = portable_dir.unwrap().join("portable_data").join("data");
} else {
config_dir = dirs::config_dir().unwrap().join("gopher64");
cache_dir = dirs::cache_dir().unwrap().join("gopher64");
data_dir = dirs::data_dir().unwrap().join("gopher64");
};
let _ = std::fs::create_dir_all(config_dir.clone());
let _ = std::fs::create_dir_all(cache_dir.clone());
let _ = std::fs::remove_file(cache_dir.clone().join("game_running"));
let mut result = std::fs::create_dir_all(config_dir.clone());
if result.is_err() {
panic!("could not create config dir: {}", result.err().unwrap())
}
result = std::fs::create_dir_all(cache_dir.clone());
if result.is_err() {
panic!("could not create cache dir: {}", result.err().unwrap())
}
result = std::fs::create_dir_all(data_dir.clone().join("saves"));
if result.is_err() {
panic!("could not create data dir: {}", result.err().unwrap())
}
let running_file = cache_dir.join("game_running");
if running_file.exists() {
result = std::fs::remove_file(running_file);
if result.is_err() {
panic!("could not remove running file: {}", result.err().unwrap())
}
}
let args = Args::parse();
let args_as_strings: Vec<String> = std::env::args().collect();
let args_count = args_as_strings.len();
if args_count > 1 {
let mut device = device::Device::new();
let mut device = device::Device::new(config_dir);
if args.clear_input_bindings {
ui::input::clear_bindings(&mut device.ui);
@@ -116,7 +145,7 @@ fn main() {
if args.game.is_some() {
let file_path = std::path::Path::new(args.game.as_ref().unwrap());
device::run_game(file_path, &mut device, args.fullscreen);
device::run_game(file_path, data_dir, &mut device, args.fullscreen);
}
} else {
let options = eframe::NativeOptions {
@@ -126,7 +155,11 @@ fn main() {
eframe::run_native(
"gopher64",
options,
Box::new(|cc| Ok(Box::new(ui::gui::GopherEguiApp::new(cc)))),
Box::new(|cc| {
Ok(Box::new(ui::gui::GopherEguiApp::new(
cc, config_dir, cache_dir, data_dir,
)))
}),
)
.unwrap();
}
+2 -5
View File
@@ -37,17 +37,14 @@ fn write_config(ui: &Ui) {
}
impl Ui {
pub fn new() -> Ui {
pub fn new(config_dir: std::path::PathBuf) -> Ui {
let sdl_context = sdl2::init().unwrap();
let video_subsystem = sdl_context.video().unwrap();
let audio_subsystem = sdl_context.audio().unwrap();
let joystick_subsystem = sdl_context.joystick().unwrap();
let controller_subsystem = sdl_context.game_controller().unwrap();
let config_file_path = dirs::config_dir()
.unwrap()
.join("gopher64")
.join("config.json");
let config_file_path = config_dir.join("config.json");
let config_file = std::fs::read(config_file_path.clone());
let mut config_map = config::Config::new();
if config_file.is_ok() {
+39 -21
View File
@@ -3,6 +3,9 @@ use crate::ui;
use eframe::egui;
pub struct GopherEguiApp {
config_dir: std::path::PathBuf,
cache_dir: std::path::PathBuf,
data_dir: std::path::PathBuf,
configure_profile: bool,
profile_name: String,
controllers: Vec<String>,
@@ -38,10 +41,14 @@ fn get_controllers(game_ui: &ui::Ui) -> Vec<String> {
}
impl GopherEguiApp {
pub fn new(cc: &eframe::CreationContext<'_>) -> GopherEguiApp {
pub fn new(
cc: &eframe::CreationContext<'_>,
config_dir: std::path::PathBuf,
cache_dir: std::path::PathBuf,
data_dir: std::path::PathBuf,
) -> GopherEguiApp {
add_japanese_font(&cc.egui_ctx);
let game_ui = ui::Ui::new();
let game_ui = ui::Ui::new(config_dir.clone());
let joystick_subsystem = game_ui.joystick_subsystem.as_ref().unwrap();
let num_joysticks = joystick_subsystem.num_joysticks().unwrap();
let mut guids: Vec<String> = vec![];
@@ -66,6 +73,9 @@ impl GopherEguiApp {
}
}
GopherEguiApp {
cache_dir: cache_dir.clone(),
config_dir: config_dir.clone(),
data_dir: data_dir.clone(),
configure_profile: false,
profile_name: "".to_string(),
selected_profile: game_ui.config.input.input_profile_binding.clone(),
@@ -114,7 +124,7 @@ fn save_config(
impl Drop for GopherEguiApp {
fn drop(&mut self) {
let mut game_ui = ui::Ui::new();
let mut game_ui = ui::Ui::new(self.config_dir.clone());
save_config(
&mut game_ui,
self.selected_controller,
@@ -140,8 +150,9 @@ impl eframe::App for GopherEguiApp {
ui.horizontal(|ui| {
if ui.button("Configure Profile").clicked() {
let profile_name = self.profile_name.clone();
let config_dir = self.config_dir.clone();
execute(async {
let mut game_ui = ui::Ui::new();
let mut game_ui = ui::Ui::new(config_dir);
ui::input::configure_input_profile(&mut game_ui, profile_name);
});
self.configure_profile = false;
@@ -171,6 +182,9 @@ impl eframe::App for GopherEguiApp {
let controller_enabled = self.controller_enabled;
let upscale = self.upscale;
let emulate_vru = self.emulate_vru;
let config_dir = self.config_dir.clone();
let cache_dir = self.cache_dir.clone();
let data_dir = self.data_dir.clone();
let (vru_window_notifier, vru_window_receiver): (
std::sync::mpsc::Sender<Vec<String>>,
@@ -192,15 +206,15 @@ impl eframe::App for GopherEguiApp {
let file = task.await;
if let Some(file) = file {
let running_file = dirs::cache_dir()
.unwrap()
.join("gopher64")
.join("game_running");
let running_file = cache_dir.join("game_running");
if running_file.exists() {
return;
}
let _ = std::fs::File::create(running_file.clone());
let mut device = device::Device::new();
let result = std::fs::File::create(running_file.clone());
if result.is_err() {
panic!("could not create running file: {}", result.err().unwrap())
}
let mut device = device::Device::new(config_dir);
save_config(
&mut device.ui,
selected_controller,
@@ -214,18 +228,22 @@ impl eframe::App for GopherEguiApp {
device.vru.word_receiver = Some(vru_word_receiver);
device.vru.gui_ctx = Some(gui_ctx);
}
device::run_game(std::path::Path::new(file.path()), &mut device, false);
let _ = std::fs::remove_file(running_file.clone());
device::run_game(
std::path::Path::new(file.path()),
data_dir,
&mut device,
false,
);
let result = std::fs::remove_file(running_file.clone());
if result.is_err() {
panic!("could not remove running file: {}", result.err().unwrap())
}
}
});
}
if ui.button("Configure Input Profile").clicked() {
let running_file = dirs::cache_dir()
.unwrap()
.join("gopher64")
.join("game_running");
if running_file.exists() {
if self.cache_dir.join("game_running").exists() {
return;
}
self.configure_profile = true;
@@ -345,15 +363,15 @@ fn execute<F: std::future::Future<Output = ()> + Send + 'static>(f: F) {
}
fn add_japanese_font(ctx: &egui::Context) {
ctx.add_font(epaint::text::FontInsert::new(
ctx.add_font(eframe::epaint::text::FontInsert::new(
"japanese_font",
egui::FontData::from_static(include_bytes!("../../data/NotoSansJP-Regular.ttf")),
vec![
epaint::text::InsertFontFamily {
eframe::epaint::text::InsertFontFamily {
family: egui::FontFamily::Proportional,
priority: egui::epaint::text::FontPriority::Lowest,
},
epaint::text::InsertFontFamily {
eframe::epaint::text::InsertFontFamily {
family: egui::FontFamily::Monospace,
priority: egui::epaint::text::FontPriority::Lowest,
},
+4 -1
View File
@@ -541,7 +541,10 @@ pub fn init(ui: &mut ui::Ui) {
.unwrap()
.open(joystick_index);
if joystick_result.is_err() {
println!("could not connect joystick")
println!(
"could not connect joystick: {}",
joystick_result.err().unwrap()
)
} else {
ui.controllers[i].joystick = Some(joystick_result.unwrap());
}
+2 -7
View File
@@ -86,16 +86,11 @@ pub fn get_save_type(game_id: &str) -> Vec<SaveTypes> {
}
}
pub fn init(ui: &mut ui::Ui) {
pub fn init(ui: &mut ui::Ui, data_dir: std::path::PathBuf) {
let id = ui.game_id.as_str();
ui.save_type = get_save_type(id);
let base_path = dirs::data_dir().unwrap().join("gopher64").join("saves");
let result = std::fs::create_dir_all(base_path.clone());
if result.is_err() {
panic!("could not create save dir")
}
let base_path = data_dir.join("saves");
ui.paths.eep_file_path.clone_from(&base_path);
ui.paths