mirror of
https://github.com/gopher64/gopher64.git
synced 2026-07-11 01:25:20 +02:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 63b8b79dd7 | |||
| 90c9bfbf09 | |||
| 9a3a56d0c6 | |||
| e71d5a1b2d | |||
| a731b870da | |||
| c54356e6f4 | |||
| b2d2089d95 | |||
| a47801b9cb | |||
| 9a76bcd303 |
@@ -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
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user