Compare commits

...

48 Commits

Author SHA1 Message Date
Logan McNaughton ba6fe1bc05 VRU support (#115)
* VRU support

* clean

* more

* more

* more

* more

* more

* more

* more

* add mappings

* more

* more

* more

* more

* VRU window

* more

* more

* more

* more

* more

* change fony

* more

* clippy

* clip

* demo

* demo

* if

* fix

* if

* if
2025-01-09 10:31:21 +01:00
Logan McNaughton e02add9676 Remove pub modifier for consts (#114) 2025-01-07 19:54:15 +01:00
Logan McNaughton 24b464fea4 Add option for high-res graphics (#111) 2025-01-07 13:38:57 +01:00
Logan McNaughton 89673df459 Add multi controller option (#110) 2025-01-07 12:34:36 +01:00
Logan McNaughton 774bb672fd Fix cart ROM save (#109) 2025-01-07 12:04:37 +01:00
Logan McNaughton f5d4160a5b Bump to 0.1.14 (#108) 2025-01-07 09:17:46 +01:00
Logan McNaughton 913ec771bb new speed limiter code (#107)
* new speed limiter code

* add version
2025-01-07 09:11:59 +01:00
Logan McNaughton c3dee292a2 build update (#106) 2025-01-06 19:11:27 +01:00
Logan McNaughton 508ae5bc17 build updates (#105)
* build updates

* more

* more

* more

* more
2025-01-06 19:08:47 +01:00
Logan McNaughton 376fc85660 Fix typo (#104) 2025-01-06 18:15:52 +01:00
Logan McNaughton 31bad0416d Code cleanup (#103) 2025-01-06 10:08:58 +01:00
Logan McNaughton e103118407 Use github action to set up rust (#102) 2025-01-01 16:46:54 +01:00
Logan McNaughton 12e37b0b29 code formatting (#100) 2024-12-31 22:21:55 +01:00
Logan McNaughton 415c3eca40 Clippy fixes (#99) 2024-12-31 22:15:39 +01:00
Logan McNaughton 2c60f6bf81 Bumpto 0.1.13 (#98) 2024-12-29 12:15:01 +01:00
Logan McNaughton 5409b0f5d4 use spin sleep for more accurate VI timing (#97) 2024-12-29 12:06:59 +01:00
Logan McNaughton f9de4110ce Bump to 0.1.12 (#96) 2024-12-23 12:09:18 +01:00
Logan McNaughton 0eadc38917 fix out-of-bound access in sram (#95) 2024-12-23 11:20:09 +01:00
Logan McNaughton a40e795036 deal with out-of-bounds reads for RDRAM->RSP DMA (#94) 2024-12-23 10:15:30 +01:00
dependabot[bot] b70c943a43 Update eframe requirement from 0.29 to 0.30 (#93)
Updates the requirements on [eframe](https://github.com/emilk/egui) to permit the latest version.
- [Release notes](https://github.com/emilk/egui/releases)
- [Changelog](https://github.com/emilk/egui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/emilk/egui/compare/0.29.0...0.30.0)

---
updated-dependencies:
- dependency-name: eframe
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-17 06:52:15 +01:00
dependabot[bot] c962589478 Update governor requirement from 0.7 to 0.8 (#92)
Updates the requirements on [governor](https://github.com/boinkor-net/governor) to permit the latest version.
- [Release notes](https://github.com/boinkor-net/governor/releases)
- [Changelog](https://github.com/boinkor-net/governor/blob/master/release.toml)
- [Commits](https://github.com/boinkor-net/governor/compare/v0.7.0...v0.8.0)

---
updated-dependencies:
- dependency-name: governor
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-11 06:46:17 +01:00
Logan McNaughton 6dec154351 Bump to 0.1.11 (#91) 2024-11-10 23:01:50 +01:00
Logan McNaughton ca33797973 Update parallel-rdp (#90) 2024-11-10 22:53:53 +01:00
dependabot[bot] 8d331e1aed Update governor requirement from 0.6 to 0.7 (#88)
Updates the requirements on [governor](https://github.com/boinkor-net/governor) to permit the latest version.
- [Release notes](https://github.com/boinkor-net/governor/releases)
- [Changelog](https://github.com/boinkor-net/governor/blob/master/release.toml)
- [Commits](https://github.com/boinkor-net/governor/compare/v0.6.0...v0.7.0)

---
updated-dependencies:
- dependency-name: governor
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-22 05:07:08 +02:00
Logan McNaughton 5e7f562d0d update eframe to 0.29 (#87) 2024-10-18 21:22:51 +02:00
dependabot[bot] 14e3fe2a55 Update rfd requirement from 0.14 to 0.15 (#86)
Updates the requirements on [rfd](https://github.com/PolyMeilex/rfd) to permit the latest version.
- [Release notes](https://github.com/PolyMeilex/rfd/releases)
- [Changelog](https://github.com/PolyMeilex/rfd/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PolyMeilex/rfd/compare/0.14.0...0.15.0)

---
updated-dependencies:
- dependency-name: rfd
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-18 21:14:29 +02:00
Logan McNaughton b1c6dd2910 Add unsafe keyword for extern C (#83) 2024-10-17 20:35:39 +02:00
Logan McNaughton e87c4736ee Update parallel-rdp (#80) 2024-10-07 14:35:12 +02:00
Logan McNaughton e9e1e000c2 Bump to 0.1.10 (#79) 2024-09-02 20:07:27 +02:00
Logan McNaughton bc83dd26ee Update parallel-rdp (#78) 2024-09-02 19:57:47 +02:00
Logan McNaughton ae97990308 Add x86_64 build flag for parallel-rdp (#77)
* Add x86_64 build flag for parallel-rdp

* Fix flag

* Update build.rs
2024-08-28 12:35:52 +02:00
Logan McNaughton e02ac09703 Fix build target for optimizations (#76) 2024-08-25 23:01:52 +02:00
Logan McNaughton 4cbdae2fce Bump version to 0.1.9 (#75) 2024-08-25 17:58:42 +02:00
Logan McNaughton 877eff0fd4 update parallel rdp 2024-08-25 16:52:13 +02:00
Logan McNaughton b560944234 Update eframe to 0.28 (#74) 2024-07-04 22:19:05 +02:00
Logan McNaughton c6bfea5018 Update rust sdl2 to 0.37 (#72) 2024-06-14 01:35:46 -06:00
Logan McNaughton 74db103659 Bump to 0.1.8 (#69) 2024-06-13 14:48:29 -06:00
Logan McNaughton fb756d5d94 Update parallel rdp (#67) 2024-06-13 14:08:01 -06:00
Logan McNaughton bdd15e340b Add annotations suggested by linter (#68) 2024-06-13 14:04:32 -06:00
Logan McNaughton f9dbaeeb23 Update RDP (#66) 2024-06-04 07:51:23 -06:00
Logan McNaughton d644617d62 Fix some crashes with test rom (#64)
* Fix some crashes with test rom

* fix lint
2024-05-30 19:49:56 -06:00
Logan McNaughton bbb0bd1447 re-enable mac os build (#63)
* re-enable mac os build

* collapse
2024-05-29 07:26:24 -06:00
Logan McNaughton 711edef9cc update parallel rdp 2024-05-29 07:09:16 -06:00
Logan McNaughton 64dae8970d Bump ver to 0.1.7 (#62) 2024-05-27 13:35:34 -06:00
Logan McNaughton 4da7cd0551 Update parallel-rdp WSI integration (#61)
* Update parallel-rdp WSI integration

* fix build

* disable mac build
2024-05-27 13:23:56 -06:00
Logan McNaughton ce5ee30ef0 Update parallel rdp 2024-05-27 12:37:21 -06:00
dependabot[bot] 9eb4e73c4d Update zip requirement from 1.1 to 2.1 (#60)
Updates the requirements on [zip](https://github.com/zip-rs/zip2) to permit the latest version.
- [Release notes](https://github.com/zip-rs/zip2/releases)
- [Changelog](https://github.com/zip-rs/zip2/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zip-rs/zip2/compare/1.1.0...v2.1.0)

---
updated-dependencies:
- dependency-name: zip
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-26 20:54:48 -06:00
Logan McNaughton 3b1ef2938d Bump version to 0.1.6 (#57) 2024-05-24 11:49:22 -06:00
48 changed files with 4197 additions and 637 deletions
+1 -7
View File
@@ -1,8 +1,2 @@
[target.x86_64-unknown-linux-gnu]
[target.'cfg(target_arch = "x86_64")']
rustflags = ["-C", "target-cpu=x86-64-v3"]
[target.x86_64-pc-windows-msvc]
rustflags = ["-C", "target-cpu=x86-64-v3"]
[target.x86_64-apple-darwin]
rustflags = ["-C", "target-cpu=x86-64-v2"]
+23 -19
View File
@@ -12,6 +12,8 @@ env:
jobs:
build-linux:
runs-on: ubuntu-latest
env:
TARGET: x86_64-unknown-linux-gnu
steps:
- uses: actions/checkout@v4
with:
@@ -19,53 +21,55 @@ jobs:
- name: Install sdl2 headers
run: |
sudo apt -y install libsdl2-dev
- name: Update rust
run: |
rustup update
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
rustflags: ""
- name: Build
run: |
cargo build --release -v
cargo build --release -v --target=${{ env.TARGET }}
- name: Upload file
uses: actions/upload-artifact@v4
with:
name: gopher64-linux
path: target/release/gopher64
path: target/${{ env.TARGET }}/release/gopher64
build-windows:
runs-on: windows-latest
env:
TARGET: x86_64-pc-windows-msvc
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Update rust
run: |
rustup update
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
rustflags: ""
- name: Build
run: |
cargo build --release -v
cargo build --release -v --target=${{ env.TARGET }}
- name: Upload file
uses: actions/upload-artifact@v4
with:
name: gopher64-windows
path: target/release/gopher64.exe
path: target/${{ env.TARGET }}/release/gopher64.exe
build-macos:
runs-on: macos-13
runs-on: macos-latest
env:
TARGET: x86_64-apple-darwin
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install sdl2 headers
run: |
brew install sdl2
- name: Update rust
run: |
rustup update
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
target: ${{ env.TARGET }}
rustflags: ""
- name: Build
run: |
cargo build --release -v
cargo build --release -v --target=${{ env.TARGET }}
- name: Upload file
uses: actions/upload-artifact@v4
with:
name: gopher64-mac
path: target/release/gopher64
path: target/${{ env.TARGET }}/release/gopher64
+5 -7
View File
@@ -16,13 +16,11 @@ jobs:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install sdl2 headers
run: |
sudo apt -y install libsdl2-dev
- name: Update rust
run: |
rustup update
rustup component add clippy
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
components: clippy, rustfmt
- name: Rustfmt Check
uses: actions-rust-lang/rustfmt@v1
- name: Lint
run: |
cargo clippy -- -Dwarnings
-5
View File
@@ -1,5 +0,0 @@
{
"rust-analyzer.linkedProjects": [
"./Cargo.toml"
]
}
+10 -7
View File
@@ -1,28 +1,31 @@
[package]
name = "gopher64"
version = "0.1.5"
version = "0.1.14"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
dirs = "5.0"
zip = "1.1"
governor = "0.6"
zip = "2.1"
governor = "0.8"
sevenz-rust = "0.6"
chrono = "0.4"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
eframe = "0.27"
rfd = "0.14"
eframe = "0.30"
epaint = "0.30"
rfd = "0.15"
sha2 = "0.10"
rusttype = "0.9"
futures = "0.3"
sdl2-sys = "0.36"
sdl2-sys = "0.37"
spin_sleep = "1.3"
encoding_rs = "0.8"
clap = { version = "4.4", features = ["derive"] }
[dependencies.sdl2]
version = "0.36"
version = "0.37"
default-features = false
features = ["static-link","bundled"]
+13 -3
View File
@@ -1,7 +1,10 @@
fn main() {
println!("cargo::rerun-if-changed=parallel-rdp");
let mut build = cc::Build::new();
build
.cpp(true)
.warnings(false)
.std("c++17")
.file("parallel-rdp/parallel-rdp-standalone/parallel-rdp/command_ring.cpp")
.file("parallel-rdp/parallel-rdp-standalone/parallel-rdp/rdp_device.cpp")
@@ -37,6 +40,7 @@ fn main() {
.file("parallel-rdp/parallel-rdp-standalone/util/aligned_alloc.cpp")
.file("parallel-rdp/parallel-rdp-standalone/util/timer.cpp")
.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/volk/volk.c")
.file("parallel-rdp/interface.cpp")
@@ -50,6 +54,10 @@ fn main() {
#[cfg(target_os = "windows")]
{
#[cfg(target_arch = "x86_64")]
{
build.flag("/arch:AVX2");
}
build.flag("-DVK_USE_PLATFORM_WIN32_KHR");
winres::WindowsResource::new()
@@ -59,9 +67,11 @@ fn main() {
}
#[cfg(any(target_os = "linux", target_os = "macos"))]
{
build
.flag("-Wno-missing-field-initializers")
.flag("-Wno-unused-parameter");
#[cfg(target_arch = "x86_64")]
{
build.flag("-march=x86-64-v3");
}
}
build.compile("parallel-rdp");
}
Binary file not shown.
+57 -47
View File
@@ -51,16 +51,16 @@ enum vi_registers
};
static bool fullscreen;
static void *rdram;
static SDL_Window *window;
static RDP::CommandProcessor *processor;
static SDL_WSIPlatform *wsi_platform;
static WSI *wsi;
static uint32_t cmd_data[0x00040000 >> 2];
static int cmd_cur;
static int cmd_ptr;
static uint8_t emu_running;
static bool emu_running;
static uint64_t rdp_sync_signal;
static uint32_t vi_registers[14];
static GFX_INFO gfx_info;
static uint64_t last_frame_counter;
static uint64_t frame_counter;
@@ -132,18 +132,16 @@ static const unsigned cmd_len_lut[64] = {
1,
};
enum
void rdp_init(void *_window, GFX_INFO _gfx_info, bool _fullscreen, bool _upscale)
{
MB_RDRAM_DRAM_ALIGNMENT_REQUIREMENT = 64 * 1024
};
window = (SDL_Window *)_window;
SDL_SetEventFilter(sdl_event_filter, nullptr);
void vk_init(void *mem_base, uint32_t rdram_size, uint8_t _fullscreen)
{
fullscreen = _fullscreen != 0;
rdram = mem_base;
gfx_info = _gfx_info;
fullscreen = _fullscreen;
bool window_vsync = 0;
wsi = new WSI;
SDL_WSIPlatform *wsi_platform = new SDL_WSIPlatform;
wsi_platform = new SDL_WSIPlatform;
wsi_platform->set_window(window);
wsi->set_platform(wsi_platform);
wsi->set_present_mode(window_vsync ? PresentMode::SyncToVBlank : PresentMode::UnlockedMaybeTear);
@@ -151,47 +149,66 @@ void vk_init(void *mem_base, uint32_t rdram_size, uint8_t _fullscreen)
Context::SystemHandles handles = {};
if (!::Vulkan::Context::init_loader(nullptr))
{
vk_close();
rdp_close();
}
if (!wsi->init_simple(1, handles))
{
vk_close();
rdp_close();
}
RDP::CommandProcessorFlags flags = 0;
processor = new RDP::CommandProcessor(wsi->get_device(), rdram, 0, rdram_size, rdram_size / 2, flags);
if (_upscale)
{
flags |= RDP::COMMAND_PROCESSOR_FLAG_UPSCALING_2X_BIT;
flags |= RDP::COMMAND_PROCESSOR_FLAG_SUPER_SAMPLED_DITHER_BIT;
}
processor = new RDP::CommandProcessor(wsi->get_device(), gfx_info.RDRAM, 0, gfx_info.RDRAM_SIZE, gfx_info.RDRAM_SIZE / 2, flags);
if (!processor->device_is_supported())
{
delete processor;
delete wsi;
processor = nullptr;
vk_close();
rdp_close();
}
wsi->begin_frame();
emu_running = 1;
emu_running = true;
last_frame_counter = 0;
frame_counter = 0;
}
void vk_close()
void rdp_close()
{
delete processor;
delete wsi;
wsi->end_frame();
if (processor)
{
delete processor;
processor = nullptr;
}
if (wsi)
{
delete wsi;
wsi = nullptr;
}
if (wsi_platform)
{
delete wsi_platform;
wsi_platform = nullptr;
}
}
int sdl_event_filter(void *userdata, SDL_Event *event)
{
if (event->type == SDL_WINDOWEVENT)
{
SDL_WSIPlatform *platform = (SDL_WSIPlatform *)&wsi->get_platform();
switch (event->window.event)
{
case SDL_WINDOWEVENT_CLOSE:
emu_running = 0;
emu_running = false;
break;
case SDL_WINDOWEVENT_RESIZED:
platform->do_resize();
wsi_platform->do_resize();
break;
default:
break;
@@ -202,7 +219,7 @@ int sdl_event_filter(void *userdata, SDL_Event *event)
switch (event->key.keysym.scancode)
{
case SDL_SCANCODE_ESCAPE:
emu_running = 0;
emu_running = false;
break;
default:
break;
@@ -212,12 +229,6 @@ int sdl_event_filter(void *userdata, SDL_Event *event)
return 0;
}
void set_sdl_window(void *_window)
{
window = (SDL_Window *)_window;
SDL_SetEventFilter(sdl_event_filter, nullptr);
}
static void calculate_viewport(float *x, float *y, float *width, float *height)
{
bool window_widescreen = false;
@@ -301,10 +312,9 @@ static void render_frame(Vulkan::Device &device)
void rdp_set_vi_register(uint32_t reg, uint32_t value)
{
processor->set_vi_register(RDP::VIRegister(reg), value);
vi_registers[reg] = value;
}
uint8_t rdp_update_screen()
bool rdp_update_screen()
{
auto &device = wsi->get_device();
render_frame(device);
@@ -353,11 +363,11 @@ static uint32_t viCalculateVerticalHeight(uint32_t vstart, uint32_t yscale)
return (delta * scale) / 0x800;
}
uint64_t rdp_process_commands(uint32_t *dpc_regs, uint8_t *SP_DMEM)
uint64_t rdp_process_commands()
{
uint64_t interrupt_timer = 0;
const uint32_t DP_CURRENT = dpc_regs[DPC_CURRENT_REG] & 0x00FFFFF8;
const uint32_t DP_END = dpc_regs[DPC_END_REG] & 0x00FFFFF8;
const uint32_t DP_CURRENT = *gfx_info.DPC_CURRENT_REG & 0x00FFFFF8;
const uint32_t DP_END = *gfx_info.DPC_END_REG & 0x00FFFFF8;
int length = DP_END - DP_CURRENT;
if (length <= 0)
@@ -367,16 +377,16 @@ uint64_t rdp_process_commands(uint32_t *dpc_regs, uint8_t *SP_DMEM)
if ((cmd_ptr + length) & ~(0x0003FFFF >> 3))
return interrupt_timer;
dpc_regs[DPC_STATUS_REG] |= DP_STATUS_PIPE_BUSY | DP_STATUS_START_GCLK;
*gfx_info.DPC_STATUS_REG |= DP_STATUS_PIPE_BUSY | DP_STATUS_START_GCLK;
uint32_t offset = DP_CURRENT;
if (dpc_regs[DPC_STATUS_REG] & DP_STATUS_XBUS_DMA)
if (*gfx_info.DPC_STATUS_REG & DP_STATUS_XBUS_DMA)
{
do
{
offset &= 0xFF8;
cmd_data[2 * cmd_ptr + 0] = SDL_SwapBE32(*reinterpret_cast<const uint32_t *>(SP_DMEM + offset));
cmd_data[2 * cmd_ptr + 1] = SDL_SwapBE32(*reinterpret_cast<const uint32_t *>(SP_DMEM + offset + 4));
cmd_data[2 * cmd_ptr + 0] = SDL_SwapBE32(*reinterpret_cast<const uint32_t *>(gfx_info.DMEM + offset));
cmd_data[2 * cmd_ptr + 1] = SDL_SwapBE32(*reinterpret_cast<const uint32_t *>(gfx_info.DMEM + offset + 4));
offset += sizeof(uint64_t);
cmd_ptr++;
} while (--length > 0);
@@ -392,8 +402,8 @@ uint64_t rdp_process_commands(uint32_t *dpc_regs, uint8_t *SP_DMEM)
do
{
offset &= 0xFFFFF8;
cmd_data[2 * cmd_ptr + 0] = *reinterpret_cast<const uint32_t *>((uint8_t *)rdram + offset);
cmd_data[2 * cmd_ptr + 1] = *reinterpret_cast<const uint32_t *>((uint8_t *)rdram + offset + 4);
cmd_data[2 * cmd_ptr + 0] = *reinterpret_cast<const uint32_t *>(gfx_info.RDRAM + offset);
cmd_data[2 * cmd_ptr + 1] = *reinterpret_cast<const uint32_t *>(gfx_info.RDRAM + offset + 4);
offset += sizeof(uint64_t);
cmd_ptr++;
} while (--length > 0);
@@ -408,7 +418,7 @@ uint64_t rdp_process_commands(uint32_t *dpc_regs, uint8_t *SP_DMEM)
if (cmd_ptr - cmd_cur - cmd_length < 0)
{
dpc_regs[DPC_START_REG] = dpc_regs[DPC_CURRENT_REG] = dpc_regs[DPC_END_REG];
*gfx_info.DPC_START_REG = *gfx_info.DPC_CURRENT_REG = *gfx_info.DPC_END_REG;
return interrupt_timer;
}
@@ -427,19 +437,19 @@ uint64_t rdp_process_commands(uint32_t *dpc_regs, uint8_t *SP_DMEM)
rdp_sync_signal = 0;
}
uint32_t width = viCalculateHorizonalWidth(vi_registers[VI_H_START_REG], vi_registers[VI_X_SCALE_REG], vi_registers[VI_WIDTH_REG]);
uint32_t width = viCalculateHorizonalWidth(*gfx_info.VI_H_START_REG, *gfx_info.VI_X_SCALE_REG, *gfx_info.VI_WIDTH_REG);
if (width == 0)
{
width = 320;
}
uint32_t height = viCalculateVerticalHeight(vi_registers[VI_V_START_REG], vi_registers[VI_Y_SCALE_REG]);
uint32_t height = viCalculateVerticalHeight(*gfx_info.VI_V_START_REG, *gfx_info.VI_Y_SCALE_REG);
if (height == 0)
{
height = 240;
}
interrupt_timer = width * height * 4;
dpc_regs[DPC_STATUS_REG] &= ~(DP_STATUS_PIPE_BUSY | DP_STATUS_START_GCLK);
*gfx_info.DPC_STATUS_REG &= ~(DP_STATUS_PIPE_BUSY | DP_STATUS_START_GCLK);
}
cmd_cur += cmd_length;
@@ -447,13 +457,13 @@ uint64_t rdp_process_commands(uint32_t *dpc_regs, uint8_t *SP_DMEM)
cmd_ptr = 0;
cmd_cur = 0;
dpc_regs[DPC_CURRENT_REG] = dpc_regs[DPC_END_REG];
dpc_regs[DPC_STATUS_REG] |= DP_STATUS_CBUF_READY;
*gfx_info.DPC_CURRENT_REG = *gfx_info.DPC_END_REG;
*gfx_info.DPC_STATUS_REG |= DP_STATUS_CBUF_READY;
return interrupt_timer;
}
void full_sync()
void rdp_full_sync()
{
if (rdp_sync_signal)
{
+25 -7
View File
@@ -1,17 +1,35 @@
#pragma once
#ifdef __cplusplus
#include <cstdint>
extern "C"
{
#endif
void vk_init(void *mem_base, uint32_t rdram_size, uint8_t fullscreen);
void vk_close();
void set_sdl_window(void *_window);
void rdp_set_vi_register(uint32_t reg, uint32_t value);
uint8_t rdp_update_screen();
uint64_t rdp_process_commands(uint32_t *dpc_regs, uint8_t *SP_DMEM);
void full_sync();
typedef struct
{
uint8_t *RDRAM;
uint8_t *DMEM;
uint32_t RDRAM_SIZE;
uint32_t *DPC_CURRENT_REG;
uint32_t *DPC_START_REG;
uint32_t *DPC_END_REG;
uint32_t *DPC_STATUS_REG;
uint32_t *VI_H_START_REG;
uint32_t *VI_V_START_REG;
uint32_t *VI_X_SCALE_REG;
uint32_t *VI_Y_SCALE_REG;
uint32_t *VI_WIDTH_REG;
} GFX_INFO;
void rdp_init(void *_window, GFX_INFO _gfx_info, bool fullscreen, bool _upscale);
void rdp_close();
void rdp_set_vi_register(uint32_t reg, uint32_t value);
bool rdp_update_screen();
uint64_t rdp_process_commands();
void rdp_full_sync();
int sdl_event_filter(void *userdata, SDL_Event *event);
#ifdef __cplusplus
}
+5
View File
@@ -54,6 +54,11 @@ void SDL_WSIPlatform::poll_input()
SDL_PumpEvents();
}
void SDL_WSIPlatform::poll_input_async(Granite::InputTrackerHandler *handler)
{
SDL_PumpEvents();
}
void SDL_WSIPlatform::set_window(SDL_Window *_window)
{
window = _window;
+1 -1
View File
@@ -13,10 +13,10 @@ public:
uint32_t get_surface_height() override;
bool alive(Vulkan::WSI &wsi) override;
void poll_input() override;
void poll_input_async(Granite::InputTrackerHandler *handler) override;
void set_window(SDL_Window *_window);
void do_resize();
private:
VkSurfaceKHR surface;
SDL_Window *window;
};
+35 -9
View File
@@ -1,4 +1,5 @@
use crate::ui;
use std::collections::HashMap;
use std::fs;
use std::io::Read;
@@ -33,6 +34,7 @@ pub mod sram;
pub mod tlb;
pub mod unmapped;
pub mod vi;
pub mod vru;
pub fn run_game(file_path: &std::path::Path, device: &mut Device, fullscreen: bool) {
let rom_contents = get_rom_contents(file_path);
@@ -40,14 +42,17 @@ pub fn run_game(file_path: &std::path::Path, device: &mut Device, fullscreen: bo
cart_rom::init(device, rom_contents); // cart needs to come before rdram
// rdram pointer is shared with parallel-rdp
let (rdram_ptr, rdram_size) = rdram::init(device);
rdram::init(device);
ui::audio::init(&mut device.ui, 33600);
ui::video::init(&mut device.ui, rdram_ptr, rdram_size, fullscreen);
ui::video::init(device, fullscreen);
ui::input::init(&mut device.ui);
mi::init(device);
pif::init(device);
if device.ui.config.input.emulate_vru {
vru::init(device);
}
memory::init(device);
rsp_interface::init(device);
rdp::init(device);
@@ -59,6 +64,9 @@ pub fn run_game(file_path: &std::path::Path, device: &mut Device, fullscreen: bo
cart_rom::load_rom_save(device);
cpu::run(device);
ui::video::close();
ui::storage::write_saves(&device.ui);
}
fn swap_rom(contents: Vec<u8>) -> Vec<u8> {
@@ -89,7 +97,7 @@ fn swap_rom(contents: Vec<u8>) -> Vec<u8> {
fn get_rom_contents(file_path: &std::path::Path) -> Vec<u8> {
let mut contents = vec![];
if file_path.extension().unwrap().to_ascii_lowercase() == "zip" {
if file_path.extension().unwrap().eq_ignore_ascii_case("zip") {
let zip_file = fs::File::open(file_path).unwrap();
let mut archive = zip::ZipArchive::new(zip_file).unwrap();
for i in 0..archive.len() {
@@ -106,7 +114,7 @@ fn get_rom_contents(file_path: &std::path::Path) -> Vec<u8> {
break;
}
}
} else if file_path.extension().unwrap().to_ascii_lowercase() == "7z" {
} else if file_path.extension().unwrap().eq_ignore_ascii_case("7z") {
let mut archive =
sevenz_rust::SevenZReader::open(file_path, sevenz_rust::Password::empty()).unwrap();
@@ -144,16 +152,17 @@ pub struct Device {
pif: pif::Pif,
cart: cart_rom::Cart,
memory: memory::Memory,
rsp: rsp_interface::Rsp,
rdp: rdp::Rdp,
pub rsp: rsp_interface::Rsp,
pub rdp: rdp::Rdp,
pub rdram: rdram::Rdram,
mi: mi::Mi,
pi: pi::Pi,
vi: vi::Vi,
pub vi: vi::Vi,
ai: ai::Ai,
si: si::Si,
ri: ri::Ri,
flashram: sram::Flashram,
pub vru: vru::Vru,
}
impl Device {
@@ -239,7 +248,7 @@ impl Device {
llbit: false,
lo: 0,
hi: 0,
running: 0,
running: false,
instrs: [cop0::reserved; 64],
special_instrs: [cop0::reserved; 64],
regimm_instrs: [cop0::reserved; 32],
@@ -292,7 +301,10 @@ impl Device {
words: [0; 4],
}; 512],
},
rdram: rdram::Rdram { mem: vec![] },
rdram: rdram::Rdram {
mem: vec![],
size: 0x800000,
},
rsp: rsp_interface::Rsp {
cpu: rsp_cpu::Cpu {
instructions: [rsp_cpu::Instructions {
@@ -380,6 +392,7 @@ impl Device {
delay: 0,
count_per_scanline: 0,
limiter: None,
vi_counter: 0,
},
flashram: sram::Flashram {
status: 0,
@@ -388,6 +401,19 @@ impl Device {
silicon_id: [sram::FLASHRAM_TYPE_ID, sram::MX29L1100_ID],
mode: sram::FlashramMode::ReadArray,
},
vru: vru::Vru {
status: 0,
voice_state: 0,
load_offset: 0,
voice_init: 0,
word_buffer: [0; 40],
words: Vec::new(),
talking: false,
word_mappings: HashMap::new(),
window_notifier: None,
word_receiver: None,
gui_ctx: None,
},
}
}
}
+8 -8
View File
@@ -1,16 +1,16 @@
use crate::device;
use crate::ui;
pub const AI_DRAM_ADDR_REG: u32 = 0;
pub const AI_LEN_REG: u32 = 1;
//pub const AI_CONTROL_REG: u32 = 2;
pub const AI_STATUS_REG: u32 = 3;
pub const AI_DACRATE_REG: u32 = 4;
//pub const AI_BITRATE_REG: u32 = 5;
const AI_DRAM_ADDR_REG: u32 = 0;
const AI_LEN_REG: u32 = 1;
// const AI_CONTROL_REG: u32 = 2;
const AI_STATUS_REG: u32 = 3;
const AI_DACRATE_REG: u32 = 4;
// const AI_BITRATE_REG: u32 = 5;
pub const AI_REGS_COUNT: u32 = 6;
pub const AI_STATUS_BUSY: u32 = 0x40000000;
pub const AI_STATUS_FULL: u32 = 0x80000000;
const AI_STATUS_BUSY: u32 = 0x40000000;
const AI_STATUS_FULL: u32 = 0x80000000;
pub struct Ai {
pub regs: [u32; AI_REGS_COUNT as usize],
+13 -13
View File
@@ -4,19 +4,19 @@ use chrono::Timelike;
use crate::device;
use crate::ui;
pub const JCMD_STATUS: u8 = 0x00;
pub const JCMD_EEPROM_READ: u8 = 0x04;
pub const JCMD_EEPROM_WRITE: u8 = 0x05;
pub const JCMD_AF_RTC_STATUS: u8 = 0x06;
pub const JCMD_AF_RTC_READ: u8 = 0x07;
pub const JCMD_AF_RTC_WRITE: u8 = 0x08;
pub const JCMD_RESET: u8 = 0xff;
const JCMD_STATUS: u8 = 0x00;
const JCMD_EEPROM_READ: u8 = 0x04;
const JCMD_EEPROM_WRITE: u8 = 0x05;
const JCMD_AF_RTC_STATUS: u8 = 0x06;
const JCMD_AF_RTC_READ: u8 = 0x07;
const JCMD_AF_RTC_WRITE: u8 = 0x08;
const JCMD_RESET: u8 = 0xff;
pub const JDT_AF_RTC: u16 = 0x1000; /* RTC */
pub const JDT_EEPROM_4K: u16 = 0x8000; /* 4k EEPROM */
pub const JDT_EEPROM_16K: u16 = 0xc000; /* 16k EEPROM */
pub const EEPROM_BLOCK_SIZE: usize = 8;
pub const EEPROM_MAX_SIZE: usize = 0x800;
const JDT_AF_RTC: u16 = 0x1000; /* RTC */
const JDT_EEPROM_4K: u16 = 0x8000; /* 4k EEPROM */
const JDT_EEPROM_16K: u16 = 0xc000; /* 16k EEPROM */
const EEPROM_BLOCK_SIZE: usize = 8;
const EEPROM_MAX_SIZE: usize = 0x800;
pub struct AfRtc {
pub control: u16,
@@ -159,7 +159,7 @@ pub fn af_rtc_write_block(device: &mut device::Device, block: usize, offset: usi
match device.pif.ram[block] {
0 => {
device.cart.rtc.control =
(device.pif.ram[offset + 1] as u16) << 8 | device.pif.ram[offset] as u16;
((device.pif.ram[offset + 1] as u16) << 8) | device.pif.ram[offset] as u16;
device.pif.ram[status] = 0x00;
}
1 => {
+13 -8
View File
@@ -10,7 +10,7 @@ pub enum CicType {
CicNus5167,
}
pub const CART_MASK: usize = 0xFFFFFFF;
const CART_MASK: usize = 0xFFFFFFF;
pub struct Cart {
pub rom: Vec<u8>,
pub is_viewer_buffer: [u8; 0xFFFF],
@@ -80,14 +80,16 @@ pub fn dma_read(
cart_addr &= CART_MASK as u32;
for i in 0..length {
device.cart.rom[(cart_addr + i) as usize] =
device.rdram.mem[(dram_addr + i) as usize ^ device.byte_swap];
if cart_addr + i < device.cart.rom.len() as u32 {
device.cart.rom[(cart_addr + i) as usize] =
device.rdram.mem[(dram_addr + i) as usize ^ device.byte_swap];
device.ui.saves.romsave.0.insert(
(cart_addr + i).to_string(),
serde_json::to_value(device.rdram.mem[(dram_addr + i) as usize ^ device.byte_swap])
.unwrap(),
);
device.ui.saves.romsave.0.insert(
(cart_addr + i).to_string(),
serde_json::to_value(device.rdram.mem[(dram_addr + i) as usize ^ device.byte_swap])
.unwrap(),
);
}
}
device.ui.saves.romsave.1 = true;
@@ -127,6 +129,9 @@ pub fn init(device: &mut device::Device, rom_file: Vec<u8>) {
device.ui.game_hash = calculate_hash(&device.cart.rom);
device.ui.game_id = String::from_utf8(device.cart.rom[0x3B..0x3E].to_vec()).unwrap();
if device.ui.game_id.contains('\0') {
device.ui.game_id = String::from("UNK");
}
}
pub fn load_rom_save(device: &mut device::Device) {
+17 -23
View File
@@ -3,24 +3,18 @@ use crate::ui;
pub const JCMD_STATUS: u8 = 0x00;
pub const JCMD_CONTROLLER_READ: u8 = 0x01;
pub const JCMD_PAK_READ: u8 = 0x02;
pub const JCMD_PAK_WRITE: u8 = 0x03;
//pub const JCMD_VRU_READ: u8 = 0x09;
//pub const JCMD_VRU_WRITE: u8 = 0x0A;
//pub const JCMD_VRU_READ_STATUS: u8 = 0x0B;
//pub const JCMD_VRU_WRITE_CONFIG: u8 = 0x0C;
//pub const JCMD_VRU_WRITE_INIT: u8 = 0x0D;
const JCMD_PAK_READ: u8 = 0x02;
const JCMD_PAK_WRITE: u8 = 0x03;
pub const JCMD_RESET: u8 = 0xff;
//pub const JDT_NONE: u16 = 0x0000;
pub const JDT_JOY_ABS_COUNTERS: u16 = 0x0001; /* joystick with absolute coordinates */
//pub const JDT_JOY_REL_COUNTERS: u16 = 0x0002; /* joystick with relative coordinates (= mouse) */
pub const JDT_JOY_PORT: u16 = 0x0004; /* has port for external paks */
//pub const JDT_VRU: u16 = 0x0100; /* VRU */
pub const PAK_CHUNK_SIZE: usize = 0x20;
pub const CONT_STATUS_PAK_NOT_PRESENT: u8 = 0;
pub const CONT_STATUS_PAK_PRESENT: u8 = 1;
pub const CONT_FLAVOR: u16 = JDT_JOY_ABS_COUNTERS | JDT_JOY_PORT;
//const JDT_NONE: u16 = 0x0000;
const JDT_JOY_ABS_COUNTERS: u16 = 0x0001; /* joystick with absolute coordinates */
//const JDT_JOY_REL_COUNTERS: u16 = 0x0002; /* joystick with relative coordinates (= mouse) */
const JDT_JOY_PORT: u16 = 0x0004; /* has port for external paks */
const PAK_CHUNK_SIZE: usize = 0x20;
const CONT_STATUS_PAK_NOT_PRESENT: u8 = 0;
const CONT_STATUS_PAK_PRESENT: u8 = 1;
const CONT_FLAVOR: u16 = JDT_JOY_ABS_COUNTERS | JDT_JOY_PORT;
#[derive(Copy, Clone)]
pub struct PakHandler {
@@ -75,14 +69,14 @@ pub fn pak_read_block(
channel: usize,
) {
let address =
(device.pif.ram[addr_acrc] as u16) << 8 | (device.pif.ram[addr_acrc + 1] & 0xe0) as u16;
((device.pif.ram[addr_acrc] as u16) << 8) | (device.pif.ram[addr_acrc + 1] & 0xe0) as u16;
let handler = device.pif.channels[channel].pak_handler;
if handler.is_some() {
(handler.unwrap().read)(device, channel, address, data, PAK_CHUNK_SIZE);
device.pif.ram[dcrc] = pak_data_crc(device, data, PAK_CHUNK_SIZE)
device.pif.ram[dcrc] = data_crc(device, data, PAK_CHUNK_SIZE)
} else {
device.pif.ram[dcrc] = !pak_data_crc(device, data, PAK_CHUNK_SIZE)
device.pif.ram[dcrc] = !data_crc(device, data, PAK_CHUNK_SIZE)
}
}
@@ -94,18 +88,18 @@ pub fn pak_write_block(
channel: usize,
) {
let address =
(device.pif.ram[addr_acrc] as u16) << 8 | (device.pif.ram[addr_acrc + 1] & 0xe0) as u16;
((device.pif.ram[addr_acrc] as u16) << 8) | (device.pif.ram[addr_acrc + 1] & 0xe0) as u16;
let handler = device.pif.channels[channel].pak_handler;
if handler.is_some() {
(handler.unwrap().write)(device, channel, address, data, PAK_CHUNK_SIZE);
device.pif.ram[dcrc] = pak_data_crc(device, data, PAK_CHUNK_SIZE)
device.pif.ram[dcrc] = data_crc(device, data, PAK_CHUNK_SIZE)
} else {
device.pif.ram[dcrc] = !pak_data_crc(device, data, PAK_CHUNK_SIZE)
device.pif.ram[dcrc] = !data_crc(device, data, PAK_CHUNK_SIZE)
}
}
pub fn pak_data_crc(device: &device::Device, data_offset: usize, size: usize) -> u8 {
pub fn data_crc(device: &device::Device, data_offset: usize, size: usize) -> u8 {
let mut i = 0;
let mut crc = 0;
+22 -22
View File
@@ -1,37 +1,37 @@
use crate::device;
pub const COP0_INDEX_REG: u32 = 0;
pub const COP0_RANDOM_REG: u32 = 1;
const COP0_RANDOM_REG: u32 = 1;
pub const COP0_ENTRYLO0_REG: u32 = 2;
pub const COP0_ENTRYLO1_REG: u32 = 3;
pub const COP0_CONTEXT_REG: u32 = 4;
pub const COP0_PAGEMASK_REG: u32 = 5;
pub const COP0_WIRED_REG: u32 = 6;
//pub const COP0_UNUSED_7: u32 = 7;
const COP0_WIRED_REG: u32 = 6;
//const COP0_UNUSED_7: u32 = 7;
pub const COP0_BADVADDR_REG: u32 = 8;
pub const COP0_COUNT_REG: u32 = 9;
pub const COP0_ENTRYHI_REG: u32 = 10;
pub const COP0_COMPARE_REG: u32 = 11;
const COP0_COMPARE_REG: u32 = 11;
pub const COP0_STATUS_REG: u32 = 12;
pub const COP0_CAUSE_REG: u32 = 13;
pub const COP0_EPC_REG: u32 = 14;
pub const COP0_PREVID_REG: u32 = 15;
pub const COP0_CONFIG_REG: u32 = 16;
const COP0_PREVID_REG: u32 = 15;
const COP0_CONFIG_REG: u32 = 16;
pub const COP0_LLADDR_REG: u32 = 17;
//pub const COP0_WATCHLO_REG: u32 = 18;
//pub const COP0_WATCHHI_REG: u32 = 19;
//const COP0_WATCHLO_REG: u32 = 18;
//const COP0_WATCHHI_REG: u32 = 19;
pub const COP0_XCONTEXT_REG: u32 = 20;
//pub const COP0_UNUSED_21: u32 = 21;
//pub const COP0_UNUSED_22: u32 = 22;
//pub const COP0_UNUSED_23: u32 = 23;
//pub const COP0_UNUSED_24: u32 = 24;
//pub const COP0_UNUSED_25: u32 = 25;
//pub const COP0_PARITYERR_REG: u32 = 26;
//pub const COP0_CACHEERR_REG: u32 = 27;
//const COP0_UNUSED_21: u32 = 21;
//const COP0_UNUSED_22: u32 = 22;
//const COP0_UNUSED_23: u32 = 23;
//const COP0_UNUSED_24: u32 = 24;
//const COP0_UNUSED_25: u32 = 25;
//const COP0_PARITYERR_REG: u32 = 26;
//const COP0_CACHEERR_REG: u32 = 27;
pub const COP0_TAGLO_REG: u32 = 28;
//pub const COP0_TAGHI_REG: u32 = 29;
pub const COP0_ERROREPC_REG: u32 = 30;
//pub const COP0_UNUSED_31: u32 = 31;
//const COP0_TAGHI_REG: u32 = 29;
const COP0_ERROREPC_REG: u32 = 30;
//const COP0_UNUSED_31: u32 = 31;
pub const COP0_REGS_COUNT: u32 = 32;
pub const COP0_STATUS_IE: u64 = 1 << 0;
@@ -42,12 +42,12 @@ pub const COP0_STATUS_FR: u64 = 1 << 26;
pub const COP0_STATUS_CU1: u64 = 1 << 29;
pub const COP0_STATUS_CU2: u64 = 1 << 30;
//pub const COP0_CAUSE_EXCCODE_INTR: u64 = 0 << 2;
//const COP0_CAUSE_EXCCODE_INTR: u64 = 0 << 2;
pub const COP0_CAUSE_EXCCODE_MOD: u64 = 1 << 2;
pub const COP0_CAUSE_EXCCODE_TLBL: u64 = 2 << 2;
pub const COP0_CAUSE_EXCCODE_TLBS: u64 = 3 << 2;
//pub const COP0_CAUSE_EXCCODE_ADEL: u64 = 4 << 2;
//pub const COP0_CAUSE_EXCCODE_ADES: u64 = 5 << 2;
//const COP0_CAUSE_EXCCODE_ADEL: u64 = 4 << 2;
//const COP0_CAUSE_EXCCODE_ADES: u64 = 5 << 2;
pub const COP0_CAUSE_EXCCODE_SYS: u64 = 8 << 2;
pub const COP0_CAUSE_EXCCODE_BP: u64 = 9 << 2;
pub const COP0_CAUSE_EXCCODE_RI: u64 = 10 << 2;
@@ -55,7 +55,7 @@ pub const COP0_CAUSE_EXCCODE_CPU: u64 = 11 << 2;
pub const COP0_CAUSE_EXCCODE_TR: u64 = 13 << 2;
pub const COP0_CAUSE_EXCCODE_FPE: u64 = 15 << 2;
pub const COP0_CAUSE_IP2: u64 = 1 << 10;
pub const COP0_CAUSE_IP7: u64 = 1 << 15;
const COP0_CAUSE_IP7: u64 = 1 << 15;
pub const COP0_CAUSE_BD: u64 = 1 << 31;
pub const COP0_CAUSE_CE1: u64 = 1 << 28;
+21 -21
View File
@@ -1,27 +1,27 @@
use crate::device;
//pub const FCR31_FLAG_INEXACT_BIT: u32 = 1 << 2;
//pub const FCR31_FLAG_UNDERFLOW_BIT: u32 = 1 << 3;
//pub const FCR31_FLAG_OVERFLOW_BIT: u32 = 1 << 4;
//pub const FCR31_FLAG_DIVBYZERO_BIT: u32 = 1 << 5;
//pub const FCR31_FLAG_INVALID_BIT: u32 = 1 << 6;
//pub const FCR31_ENABLE_INEXACT_BIT: u32 = 1 << 7;
//pub const FCR31_ENABLE_UNDERFLOW_BIT: u32 = 1 << 8;
//pub const FCR31_ENABLE_OVERFLOW_BIT: u32 = 1 << 9;
//pub const FCR31_ENABLE_DIVBYZERO_BIT: u32 = 1 << 10;
//pub const FCR31_ENABLE_INVALID_BIT: u32 = 1 << 11;
//pub const FCR31_CAUSE_INEXACT_BIT: u32 = 1 << 12;
//pub const FCR31_CAUSE_UNDERFLOW_BIT: u32 = 1 << 13;
//pub const FCR31_CAUSE_OVERFLOW_BIT: u32 = 1 << 14;
//pub const FCR31_CAUSE_DIVBYZERO_BIT: u32 = 1 << 15;
//pub const FCR31_CAUSE_INVALID_BIT: u32 = 1 << 16;
pub const FCR31_CAUSE_UNIMP_BIT: u32 = 1 << 17;
//const FCR31_FLAG_INEXACT_BIT: u32 = 1 << 2;
//const FCR31_FLAG_UNDERFLOW_BIT: u32 = 1 << 3;
//const FCR31_FLAG_OVERFLOW_BIT: u32 = 1 << 4;
//const FCR31_FLAG_DIVBYZERO_BIT: u32 = 1 << 5;
//const FCR31_FLAG_INVALID_BIT: u32 = 1 << 6;
//const FCR31_ENABLE_INEXACT_BIT: u32 = 1 << 7;
//const FCR31_ENABLE_UNDERFLOW_BIT: u32 = 1 << 8;
//const FCR31_ENABLE_OVERFLOW_BIT: u32 = 1 << 9;
//const FCR31_ENABLE_DIVBYZERO_BIT: u32 = 1 << 10;
//const FCR31_ENABLE_INVALID_BIT: u32 = 1 << 11;
//const FCR31_CAUSE_INEXACT_BIT: u32 = 1 << 12;
//const FCR31_CAUSE_UNDERFLOW_BIT: u32 = 1 << 13;
//const FCR31_CAUSE_OVERFLOW_BIT: u32 = 1 << 14;
//const FCR31_CAUSE_DIVBYZERO_BIT: u32 = 1 << 15;
//const FCR31_CAUSE_INVALID_BIT: u32 = 1 << 16;
const FCR31_CAUSE_UNIMP_BIT: u32 = 1 << 17;
pub const FCR31_CMP_BIT: u32 = 1 << 23;
pub const FCR31_FS_BIT: u32 = 1 << 24;
const FCR31_FS_BIT: u32 = 1 << 24;
pub const FCR31_CAUSE_MASK: u32 = 0b00000000000000111111000000000000;
pub const FCR31_ENABLE_MASK: u32 = 0b00000000000000000000111110000000;
pub const FCR31_WRITE_MASK: u32 = 0b00000001100000111111111111111111;
const FCR31_CAUSE_MASK: u32 = 0b00000000000000111111000000000000;
const FCR31_ENABLE_MASK: u32 = 0b00000000000000000000111110000000;
const FCR31_WRITE_MASK: u32 = 0b00000001100000111111111111111111;
pub struct Cop1 {
pub fcr0: u32,
@@ -359,7 +359,7 @@ pub fn set_control_registers_fpu(device: &mut device::Device, index: u32, data:
device.cpu.cop1.fcr31 = data & FCR31_WRITE_MASK;
// the Cause bits are ANDed with the Enable bits to check for exceptions
// "Unimplemented Operation" has no Enable bit and always causes an exception
if (device.cpu.cop1.fcr31 & FCR31_CAUSE_MASK) >> 5
if ((device.cpu.cop1.fcr31 & FCR31_CAUSE_MASK) >> 5)
& (device.cpu.cop1.fcr31 & FCR31_ENABLE_MASK)
!= 0
|| device.cpu.cop1.fcr31 & FCR31_CAUSE_UNIMP_BIT != 0
+3 -3
View File
@@ -25,7 +25,7 @@ pub struct Cpu {
pub pc_phys: u64,
pub lo: u64,
pub hi: u64,
pub running: u8,
pub running: bool,
pub llbit: bool,
pub clock_rate: u64,
pub instrs: [fn(&mut device::Device, u32); 64],
@@ -231,8 +231,8 @@ pub fn in_delay_slot_taken(device: &device::Device) -> bool {
}
pub fn run(device: &mut device::Device) {
device.cpu.running = 1;
while device.cpu.running == 1 {
device.cpu.running = true;
while device.cpu.running {
device.cpu.gpr[0] = 0; // gpr 0 is read only
let (cached, err);
(device.cpu.pc_phys, cached, err) = device::memory::translate_address(
+4 -4
View File
@@ -346,12 +346,12 @@ pub fn lwl(device: &mut device::Device, opcode: u32) {
device.cpu.gpr[rt(opcode) as usize] = se32(
((device.cpu.gpr[rt(opcode) as usize] as u32) & mask
| device::memory::data_read(
| (device::memory::data_read(
device,
phys_address,
device::memory::AccessSize::Word,
cached,
) << shift) as i32,
) << shift)) as i32,
)
}
@@ -431,12 +431,12 @@ pub fn lwr(device: &mut device::Device, opcode: u32) {
device.cpu.gpr[rt(opcode) as usize] = se32(
((device.cpu.gpr[rt(opcode) as usize] as u32) & (mask as u32)
| device::memory::data_read(
| (device::memory::data_read(
device,
phys_address,
device::memory::AccessSize::Word,
cached,
) >> shift) as i32,
) >> shift)) as i32,
)
}
+1
View File
@@ -11,6 +11,7 @@ pub enum EventType {
InterruptCheck,
SPDma,
Compare,
Vru,
Count,
}
+1 -1
View File
@@ -1,6 +1,6 @@
use crate::device;
pub const IS_VIEWER_MASK: usize = 0xFFFF;
const IS_VIEWER_MASK: usize = 0xFFFF;
pub fn read_mem(
device: &mut device::Device,
+16 -16
View File
@@ -1,24 +1,24 @@
use crate::device;
pub const MM_RDRAM_DRAM: usize = 0x00000000;
pub const MM_RDRAM_REGS: usize = 0x03f00000;
pub const MM_RSP_MEM: usize = 0x04000000;
pub const MM_RSP_REGS: usize = 0x04040000;
pub const MM_RSP_REGS_PC: usize = 0x04080000;
pub const MM_DPC_REGS: usize = 0x04100000;
pub const MM_DPS_REGS: usize = 0x04200000;
pub const MM_MI_REGS: usize = 0x04300000;
pub const MM_VI_REGS: usize = 0x04400000;
pub const MM_AI_REGS: usize = 0x04500000;
pub const MM_PI_REGS: usize = 0x04600000;
pub const MM_RI_REGS: usize = 0x04700000;
pub const MM_SI_REGS: usize = 0x04800000;
const MM_RDRAM_DRAM: usize = 0x00000000;
const MM_RDRAM_REGS: usize = 0x03f00000;
const MM_RSP_MEM: usize = 0x04000000;
const MM_RSP_REGS: usize = 0x04040000;
const MM_RSP_REGS_PC: usize = 0x04080000;
const MM_DPC_REGS: usize = 0x04100000;
const MM_DPS_REGS: usize = 0x04200000;
const MM_MI_REGS: usize = 0x04300000;
const MM_VI_REGS: usize = 0x04400000;
const MM_AI_REGS: usize = 0x04500000;
const MM_PI_REGS: usize = 0x04600000;
const MM_RI_REGS: usize = 0x04700000;
const MM_SI_REGS: usize = 0x04800000;
//const MM_DOM2_ADDR1: usize = 0x05000000;
pub const MM_DOM2_ADDR2: usize = 0x08000000;
pub const MM_CART_ROM: usize = 0x10000000;
pub const MM_PIF_MEM: usize = 0x1fc00000;
//pub const MM_DOM1_ADDR3: usize = 0x1fd00000;
pub const MM_IS_VIEWER: usize = 0x13ff0000;
const MM_PIF_MEM: usize = 0x1fc00000;
//const MM_DOM1_ADDR3: usize = 0x1fd00000;
const MM_IS_VIEWER: usize = 0x13ff0000;
#[derive(PartialEq)]
pub enum AccessType {
+2 -2
View File
@@ -1,7 +1,7 @@
use crate::device;
pub const MEMPAK_SIZE: usize = 0x8000;
pub const MPK_PAGE_SIZE: usize = 256;
const MEMPAK_SIZE: usize = 0x8000;
const MPK_PAGE_SIZE: usize = 256;
pub fn format_mempak(device: &mut device::Device) {
if device.ui.saves.mempak.0.len() < MEMPAK_SIZE * 4 {
+27 -27
View File
@@ -1,9 +1,9 @@
use crate::device;
pub const MI_INIT_MODE_REG: u32 = 0;
pub const MI_VERSION_REG: u32 = 1;
pub const MI_INTR_REG: u32 = 2;
pub const MI_INTR_MASK_REG: u32 = 3;
const MI_INIT_MODE_REG: u32 = 0;
const MI_VERSION_REG: u32 = 1;
const MI_INTR_REG: u32 = 2;
const MI_INTR_MASK_REG: u32 = 3;
pub const MI_REGS_COUNT: u32 = 4;
/* read */
@@ -15,34 +15,34 @@ pub const MI_INTR_PI: u32 = 1 << 4;
pub const MI_INTR_DP: u32 = 1 << 5;
/* write */
pub const MI_CLR_SP: u32 = 1 << 0;
pub const MI_SET_SP: u32 = 1 << 1;
pub const MI_CLR_SI: u32 = 1 << 2;
pub const MI_SET_SI: u32 = 1 << 3;
pub const MI_CLR_AI: u32 = 1 << 4;
pub const MI_SET_AI: u32 = 1 << 5;
pub const MI_CLR_VI: u32 = 1 << 6;
pub const MI_SET_VI: u32 = 1 << 7;
pub const MI_CLR_PI: u32 = 1 << 8;
pub const MI_SET_PI: u32 = 1 << 9;
pub const MI_CLR_DP: u32 = 1 << 10;
pub const MI_SET_DP: u32 = 1 << 11;
const MI_CLR_SP: u32 = 1 << 0;
const MI_SET_SP: u32 = 1 << 1;
const MI_CLR_SI: u32 = 1 << 2;
const MI_SET_SI: u32 = 1 << 3;
const MI_CLR_AI: u32 = 1 << 4;
const MI_SET_AI: u32 = 1 << 5;
const MI_CLR_VI: u32 = 1 << 6;
const MI_SET_VI: u32 = 1 << 7;
const MI_CLR_PI: u32 = 1 << 8;
const MI_SET_PI: u32 = 1 << 9;
const MI_CLR_DP: u32 = 1 << 10;
const MI_SET_DP: u32 = 1 << 11;
/* mode read */
pub const MI_INIT_MODE: u32 = 1 << 7;
pub const MI_EBUS_MODE: u32 = 1 << 8;
pub const MI_RDRAM_MODE: u32 = 1 << 9;
const MI_INIT_MODE: u32 = 1 << 7;
const MI_EBUS_MODE: u32 = 1 << 8;
const MI_RDRAM_MODE: u32 = 1 << 9;
/* mode write */
pub const MI_CLR_INIT: u32 = 1 << 7;
pub const MI_SET_INIT: u32 = 1 << 8;
pub const MI_CLR_EBUS: u32 = 1 << 9;
pub const MI_SET_EBUS: u32 = 1 << 10;
pub const MI_CLR_DP_INTR: u32 = 1 << 11;
pub const MI_CLR_RDRAM: u32 = 1 << 12;
pub const MI_SET_RDRAM: u32 = 1 << 13;
const MI_CLR_INIT: u32 = 1 << 7;
const MI_SET_INIT: u32 = 1 << 8;
const MI_CLR_EBUS: u32 = 1 << 9;
const MI_SET_EBUS: u32 = 1 << 10;
const MI_CLR_DP_INTR: u32 = 1 << 11;
const MI_CLR_RDRAM: u32 = 1 << 12;
const MI_SET_RDRAM: u32 = 1 << 13;
pub const MI_INIT_LENGTH_MASK: u32 = 0b1111111;
const MI_INIT_LENGTH_MASK: u32 = 0b1111111;
pub struct Mi {
pub regs: [u32; MI_REGS_COUNT as usize],
+17 -17
View File
@@ -1,29 +1,29 @@
use crate::device;
pub const PI_DRAM_ADDR_REG: u32 = 0;
pub const PI_CART_ADDR_REG: u32 = 1;
pub const PI_RD_LEN_REG: u32 = 2;
pub const PI_WR_LEN_REG: u32 = 3;
const PI_DRAM_ADDR_REG: u32 = 0;
const PI_CART_ADDR_REG: u32 = 1;
const PI_RD_LEN_REG: u32 = 2;
const PI_WR_LEN_REG: u32 = 3;
pub const PI_STATUS_REG: u32 = 4;
pub const PI_BSD_DOM1_LAT_REG: u32 = 5;
pub const PI_BSD_DOM1_PWD_REG: u32 = 6;
pub const PI_BSD_DOM1_PGS_REG: u32 = 7;
pub const PI_BSD_DOM1_RLS_REG: u32 = 8;
pub const PI_BSD_DOM2_LAT_REG: u32 = 9;
pub const PI_BSD_DOM2_PWD_REG: u32 = 10;
pub const PI_BSD_DOM2_PGS_REG: u32 = 11;
pub const PI_BSD_DOM2_RLS_REG: u32 = 12;
const PI_BSD_DOM1_LAT_REG: u32 = 5;
const PI_BSD_DOM1_PWD_REG: u32 = 6;
const PI_BSD_DOM1_PGS_REG: u32 = 7;
const PI_BSD_DOM1_RLS_REG: u32 = 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;
/* PI_STATUS - read */
pub const PI_STATUS_DMA_BUSY: u32 = 1 << 0;
const PI_STATUS_DMA_BUSY: u32 = 1 << 0;
pub const PI_STATUS_IO_BUSY: u32 = 1 << 1;
//pub const PI_STATUS_ERROR: u32 = 1 << 2;
pub const PI_STATUS_INTERRUPT: u32 = 1 << 3;
//const PI_STATUS_ERROR: u32 = 1 << 2;
const PI_STATUS_INTERRUPT: u32 = 1 << 3;
/* PI_STATUS - write */
pub const PI_STATUS_RESET: u32 = 1 << 0;
pub const PI_STATUS_CLR_INTR: u32 = 1 << 1;
const PI_STATUS_RESET: u32 = 1 << 0;
const PI_STATUS_CLR_INTR: u32 = 1 << 1;
pub struct Pi {
pub regs: [u32; PI_REGS_COUNT as usize],
+11 -3
View File
@@ -99,7 +99,7 @@ pub fn update_pif_ram(device: &mut device::Device) -> u64 {
for k in 0..PIF_CHANNELS_COUNT {
active_channels += process_channel(device, k)
}
(24000 + (active_channels * 28000)) as u64
(24000 + (active_channels * 30000)) as u64
}
pub fn disable_pif_channel(channel: &mut PifChannel) {
@@ -229,8 +229,16 @@ pub fn init(device: &mut device::Device) {
write: device::mempak::write,
};
device.pif.channels[0].pak_handler = Some(mempak_handler);
device.pif.channels[0].process = Some(device::controller::process);
for i in 0..4 {
if device.ui.config.input.controller_enabled[i] {
device.pif.channels[i].pak_handler = Some(mempak_handler);
device.pif.channels[i].process = Some(device::controller::process);
}
}
if device.ui.config.input.emulate_vru {
device.pif.channels[3].pak_handler = None;
device.pif.channels[3].process = Some(device::vru::process);
}
device.pif.channels[4].process = Some(device::cart::process)
}
+33 -31
View File
@@ -5,41 +5,41 @@ pub const DPC_START_REG: u32 = 0;
pub const DPC_END_REG: u32 = 1;
pub const DPC_CURRENT_REG: u32 = 2;
pub const DPC_STATUS_REG: u32 = 3;
pub const DPC_CLOCK_REG: u32 = 4;
pub const DPC_BUFBUSY_REG: u32 = 5;
pub const DPC_PIPEBUSY_REG: u32 = 6;
pub const DPC_TMEM_REG: u32 = 7;
const DPC_CLOCK_REG: u32 = 4;
const DPC_BUFBUSY_REG: u32 = 5;
const DPC_PIPEBUSY_REG: u32 = 6;
const DPC_TMEM_REG: u32 = 7;
pub const DPC_REGS_COUNT: u32 = 8;
//pub const DPS_TBIST_REG: u32 = 0;
//pub const DPS_TEST_MODE_REG: u32 = 1;
//pub const DPS_BUFTEST_ADDR_REG: u32 = 2;
//pub const DPS_BUFTEST_DATA_REG: u32 = 3;
//const DPS_TBIST_REG: u32 = 0;
//const DPS_TEST_MODE_REG: u32 = 1;
//const DPS_BUFTEST_ADDR_REG: u32 = 2;
//const DPS_BUFTEST_DATA_REG: u32 = 3;
pub const DPS_REGS_COUNT: u32 = 4;
/* DPC status - read */
pub const DPC_STATUS_XBUS_DMEM_DMA: u32 = 1 << 0;
pub const DPC_STATUS_FREEZE: u32 = 1 << 1;
pub const DPC_STATUS_FLUSH: u32 = 1 << 2;
pub const DPC_STATUS_START_GCLK: u32 = 1 << 3;
pub const DPC_STATUS_TMEM_BUSY: u32 = 1 << 4;
pub const DPC_STATUS_PIPE_BUSY: u32 = 1 << 5;
pub const DPC_STATUS_CMD_BUSY: u32 = 1 << 6;
pub const DPC_STATUS_CBUF_READY: u32 = 1 << 7;
//pub const DPC_STATUS_DMA_BUSY: u32 = 1 << 8;
//pub const DPC_STATUS_END_VALID: u32 = 1 << 9;
pub const DPC_STATUS_START_VALID: u32 = 1 << 10;
const DPC_STATUS_XBUS_DMEM_DMA: u32 = 1 << 0;
const DPC_STATUS_FREEZE: u32 = 1 << 1;
const DPC_STATUS_FLUSH: u32 = 1 << 2;
const DPC_STATUS_START_GCLK: u32 = 1 << 3;
const DPC_STATUS_TMEM_BUSY: u32 = 1 << 4;
const DPC_STATUS_PIPE_BUSY: u32 = 1 << 5;
const DPC_STATUS_CMD_BUSY: u32 = 1 << 6;
const DPC_STATUS_CBUF_READY: u32 = 1 << 7;
//const DPC_STATUS_DMA_BUSY: u32 = 1 << 8;
//const DPC_STATUS_END_VALID: u32 = 1 << 9;
const DPC_STATUS_START_VALID: u32 = 1 << 10;
/* DPC status - write */
pub const DPC_CLR_XBUS_DMEM_DMA: u32 = 1 << 0;
pub const DPC_SET_XBUS_DMEM_DMA: u32 = 1 << 1;
pub const DPC_CLR_FREEZE: u32 = 1 << 2;
pub const DPC_SET_FREEZE: u32 = 1 << 3;
pub const DPC_CLR_FLUSH: u32 = 1 << 4;
pub const DPC_SET_FLUSH: u32 = 1 << 5;
pub const DPC_CLR_TMEM_CTR: u32 = 1 << 6;
pub const DPC_CLR_PIPE_CTR: u32 = 1 << 7;
pub const DPC_CLR_CMD_CTR: u32 = 1 << 8;
pub const DPC_CLR_CLOCK_CTR: u32 = 1 << 9;
const DPC_CLR_XBUS_DMEM_DMA: u32 = 1 << 0;
const DPC_SET_XBUS_DMEM_DMA: u32 = 1 << 1;
const DPC_CLR_FREEZE: u32 = 1 << 2;
const DPC_SET_FREEZE: u32 = 1 << 3;
const DPC_CLR_FLUSH: u32 = 1 << 4;
const DPC_SET_FLUSH: u32 = 1 << 5;
const DPC_CLR_TMEM_CTR: u32 = 1 << 6;
const DPC_CLR_PIPE_CTR: u32 = 1 << 7;
const DPC_CLR_CMD_CTR: u32 = 1 << 8;
const DPC_CLR_CLOCK_CTR: u32 = 1 << 9;
pub struct Rdp {
pub regs_dpc: [u32; DPC_REGS_COUNT as usize],
@@ -92,7 +92,8 @@ pub fn write_regs_dpc(device: &mut device::Device, address: u64, value: u32, mas
}
pub fn run_rdp(device: &mut device::Device) {
let timer = ui::video::process_rdp_list(&mut device.rdp.regs_dpc, &mut device.rsp.mem);
let timer = ui::video::process_rdp_list();
if timer != 0 {
device::events::create_event(
device,
@@ -173,6 +174,7 @@ pub fn init(device: &mut device::Device) {
}
pub fn rdp_interrupt_event(device: &mut device::Device) {
ui::video::rdp_full_sync();
ui::video::full_sync();
device::mi::set_rcp_interrupt(device, device::mi::MI_INTR_DP)
}
+10 -11
View File
@@ -3,10 +3,9 @@ use std::alloc::{alloc_zeroed, Layout};
pub const RDRAM_MASK: usize = 0xFFFFFF;
pub const RDRAM_SIZE: usize = 0x800000; // 8MB
pub struct Rdram {
pub mem: Vec<u8>,
pub size: u32,
}
pub fn read_mem_fast(
@@ -32,7 +31,7 @@ pub fn read_mem(
rdram_calculate_cycles(access_size as u64) / (access_size as u64 / 4),
);
let masked_address = address as usize & RDRAM_MASK;
if address < RDRAM_SIZE as u64 {
if address < device.rdram.size as u64 {
u32::from_ne_bytes(
device.rdram.mem[masked_address..masked_address + 4]
.try_into()
@@ -44,7 +43,7 @@ pub fn read_mem(
}
pub fn write_mem(device: &mut device::Device, address: u64, value: u32, mask: u32) {
if address < RDRAM_SIZE as u64 {
if address < device.rdram.size as u64 {
let mut data = u32::from_ne_bytes(
device.rdram.mem[address as usize..(address + 4) as usize]
.try_into()
@@ -68,19 +67,19 @@ pub fn write_regs(_device: &mut device::Device, _address: u64, _value: u32, _mas
panic!("rdram write reg");
}
pub fn init(device: &mut device::Device) -> (*mut u8, usize) {
pub fn init(device: &mut device::Device) {
let alignment = 64 * 1024;
let layout = Layout::from_size_align(RDRAM_SIZE, alignment).expect("Invalid layout");
let layout =
Layout::from_size_align(device.rdram.size as usize, alignment).expect("Invalid layout");
let ptr = unsafe { alloc_zeroed(layout) };
device.rdram.mem = unsafe { Vec::from_raw_parts(ptr, RDRAM_SIZE, RDRAM_SIZE) };
device.rdram.mem =
unsafe { Vec::from_raw_parts(ptr, device.rdram.size as usize, device.rdram.size as usize) };
// hack, skip RDRAM initialization
let data: u32 = RDRAM_SIZE as u32;
device.rdram.mem[device.cart.rdram_size_offset..device.cart.rdram_size_offset + 4]
.copy_from_slice(&data.to_ne_bytes());
(ptr, RDRAM_SIZE)
.copy_from_slice(&device.rdram.size.to_ne_bytes());
}
pub fn rdram_calculate_cycles(length: u64) -> u64 {
31 + (length / 3)// https://hcs64.com/dma.html, https://github.com/rasky/n64-systembench
31 + (length / 3) // https://hcs64.com/dma.html, https://github.com/rasky/n64-systembench
}
+8 -8
View File
@@ -1,13 +1,13 @@
use crate::device;
//pub const RI_MODE_REG: u32 = 0;
//pub const RI_CONFIG_REG: u32 = 1;
//pub const RI_CURRENT_LOAD_REG: u32 = 2;
pub const RI_SELECT_REG: u32 = 3;
//pub const RI_REFRESH_REG: u32 = 4;
//pub const RI_LATENCY_REG: u32 = 5;
//pub const RI_ERROR_REG: u32 = 6;
//pub const RI_WERROR_REG: u32 = 7;
//const RI_MODE_REG: u32 = 0;
//const RI_CONFIG_REG: u32 = 1;
//const RI_CURRENT_LOAD_REG: u32 = 2;
const RI_SELECT_REG: u32 = 3;
//const RI_REFRESH_REG: u32 = 4;
//const RI_LATENCY_REG: u32 = 5;
//const RI_ERROR_REG: u32 = 6;
//const RI_WERROR_REG: u32 = 7;
pub const RI_REGS_COUNT: u32 = 8;
pub struct Ri {
+55 -52
View File
@@ -1,64 +1,64 @@
use crate::device;
pub const SP_MEM_ADDR_REG: u32 = 0;
pub const SP_DRAM_ADDR_REG: u32 = 1;
pub const SP_RD_LEN_REG: u32 = 2;
pub const SP_WR_LEN_REG: u32 = 3;
const SP_MEM_ADDR_REG: u32 = 0;
const SP_DRAM_ADDR_REG: u32 = 1;
const SP_RD_LEN_REG: u32 = 2;
const SP_WR_LEN_REG: u32 = 3;
pub const SP_STATUS_REG: u32 = 4;
pub const SP_DMA_FULL_REG: u32 = 5;
pub const SP_DMA_BUSY_REG: u32 = 6;
pub const SP_SEMAPHORE_REG: u32 = 7;
const SP_DMA_FULL_REG: u32 = 5;
const SP_DMA_BUSY_REG: u32 = 6;
const SP_SEMAPHORE_REG: u32 = 7;
pub const SP_REGS_COUNT: u32 = 8;
pub const SP_PC_REG: u32 = 0;
//pub const SP_IBIST_REG: u32 = 1;
//const SP_IBIST_REG: u32 = 1;
pub const SP_REGS2_COUNT: u32 = 2;
/* SP_STATUS - read */
pub const SP_STATUS_HALT: u32 = 1 << 0;
pub const SP_STATUS_BROKE: u32 = 1 << 1;
pub const SP_STATUS_DMA_BUSY: u32 = 1 << 2;
pub const SP_STATUS_DMA_FULL: u32 = 1 << 3;
//pub const SP_STATUS_IO_FULL: u32 = 1 << 4;
pub const SP_STATUS_SSTEP: u32 = 1 << 5;
pub const SP_STATUS_INTR_BREAK: u32 = 1 << 6;
pub const SP_STATUS_SIG0: u32 = 1 << 7;
pub const SP_STATUS_SIG1: u32 = 1 << 8;
pub const SP_STATUS_SIG2: u32 = 1 << 9;
pub const SP_STATUS_SIG3: u32 = 1 << 10;
pub const SP_STATUS_SIG4: u32 = 1 << 11;
pub const SP_STATUS_SIG5: u32 = 1 << 12;
pub const SP_STATUS_SIG6: u32 = 1 << 13;
pub const SP_STATUS_SIG7: u32 = 1 << 14;
const SP_STATUS_BROKE: u32 = 1 << 1;
const SP_STATUS_DMA_BUSY: u32 = 1 << 2;
const SP_STATUS_DMA_FULL: u32 = 1 << 3;
//const SP_STATUS_IO_FULL: u32 = 1 << 4;
const SP_STATUS_SSTEP: u32 = 1 << 5;
const SP_STATUS_INTR_BREAK: u32 = 1 << 6;
const SP_STATUS_SIG0: u32 = 1 << 7;
const SP_STATUS_SIG1: u32 = 1 << 8;
const SP_STATUS_SIG2: u32 = 1 << 9;
const SP_STATUS_SIG3: u32 = 1 << 10;
const SP_STATUS_SIG4: u32 = 1 << 11;
const SP_STATUS_SIG5: u32 = 1 << 12;
const SP_STATUS_SIG6: u32 = 1 << 13;
const SP_STATUS_SIG7: u32 = 1 << 14;
/* SP_STATUS - write */
pub const SP_CLR_HALT: u32 = 1 << 0;
const SP_CLR_HALT: u32 = 1 << 0;
pub const SP_SET_HALT: u32 = 1 << 1;
pub const SP_CLR_BROKE: u32 = 1 << 2;
pub const SP_CLR_INTR: u32 = 1 << 3;
pub const SP_SET_INTR: u32 = 1 << 4;
pub const SP_CLR_SSTEP: u32 = 1 << 5;
pub const SP_SET_SSTEP: u32 = 1 << 6;
pub const SP_CLR_INTR_BREAK: u32 = 1 << 7;
pub const SP_SET_INTR_BREAK: u32 = 1 << 8;
pub const SP_CLR_SIG0: u32 = 1 << 9;
pub const SP_SET_SIG0: u32 = 1 << 10;
pub const SP_CLR_SIG1: u32 = 1 << 11;
pub const SP_SET_SIG1: u32 = 1 << 12;
pub const SP_CLR_SIG2: u32 = 1 << 13;
pub const SP_SET_SIG2: u32 = 1 << 14;
pub const SP_CLR_SIG3: u32 = 1 << 15;
pub const SP_SET_SIG3: u32 = 1 << 16;
pub const SP_CLR_SIG4: u32 = 1 << 17;
pub const SP_SET_SIG4: u32 = 1 << 18;
pub const SP_CLR_SIG5: u32 = 1 << 19;
pub const SP_SET_SIG5: u32 = 1 << 20;
pub const SP_CLR_SIG6: u32 = 1 << 21;
pub const SP_SET_SIG6: u32 = 1 << 22;
pub const SP_CLR_SIG7: u32 = 1 << 23;
pub const SP_SET_SIG7: u32 = 1 << 24;
const SP_CLR_BROKE: u32 = 1 << 2;
const SP_CLR_INTR: u32 = 1 << 3;
const SP_SET_INTR: u32 = 1 << 4;
const SP_CLR_SSTEP: u32 = 1 << 5;
const SP_SET_SSTEP: u32 = 1 << 6;
const SP_CLR_INTR_BREAK: u32 = 1 << 7;
const SP_SET_INTR_BREAK: u32 = 1 << 8;
const SP_CLR_SIG0: u32 = 1 << 9;
const SP_SET_SIG0: u32 = 1 << 10;
const SP_CLR_SIG1: u32 = 1 << 11;
const SP_SET_SIG1: u32 = 1 << 12;
const SP_CLR_SIG2: u32 = 1 << 13;
const SP_SET_SIG2: u32 = 1 << 14;
const SP_CLR_SIG3: u32 = 1 << 15;
const SP_SET_SIG3: u32 = 1 << 16;
const SP_CLR_SIG4: u32 = 1 << 17;
const SP_SET_SIG4: u32 = 1 << 18;
const SP_CLR_SIG5: u32 = 1 << 19;
const SP_SET_SIG5: u32 = 1 << 20;
const SP_CLR_SIG6: u32 = 1 << 21;
const SP_SET_SIG6: u32 = 1 << 22;
const SP_CLR_SIG7: u32 = 1 << 23;
const SP_SET_SIG7: u32 = 1 << 24;
pub const RSP_MEM_MASK: usize = 0x1FFF;
const RSP_MEM_MASK: usize = 0x1FFF;
#[derive(PartialEq, Copy, Clone)]
pub enum DmaDir {
@@ -165,11 +165,14 @@ pub fn do_dma(device: &mut device::Device, dma: RspDma) {
while j < count {
let mut i = 0;
while i < length {
let data = u32::from_ne_bytes(
device.rdram.mem[dram_addr as usize..dram_addr as usize + 4]
.try_into()
.unwrap(),
);
let mut data = 0;
if dram_addr < device.rdram.size {
data = u32::from_ne_bytes(
device.rdram.mem[dram_addr as usize..dram_addr as usize + 4]
.try_into()
.unwrap(),
);
}
if offset != 0 {
// imem being updated
device.rsp.cpu.instructions[((mem_addr & 0xFFF) / 4) as usize].func =
+6 -5
View File
@@ -208,7 +208,7 @@ pub fn lw(device: &mut device::Device, opcode: u32) {
w[3] = device.rsp.mem[(address as usize + 3) & 0xFFF];
device.rsp.cpu.gpr[rt(opcode) as usize] =
(w[0] as u32) << 24 | (w[1] as u32) << 16 | (w[2] as u32) << 8 | (w[3] as u32)
((w[0] as u32) << 24) | ((w[1] as u32) << 16) | ((w[2] as u32) << 8) | (w[3] as u32)
}
pub fn lbu(device: &mut device::Device, opcode: u32) {
@@ -240,7 +240,7 @@ pub fn lwu(device: &mut device::Device, opcode: u32) {
w[3] = device.rsp.mem[(address as usize + 3) & 0xFFF];
device.rsp.cpu.gpr[rt(opcode) as usize] =
(w[0] as u32) << 24 | (w[1] as u32) << 16 | (w[2] as u32) << 8 | (w[3] as u32)
((w[0] as u32) << 24) | ((w[1] as u32) << 16) | ((w[2] as u32) << 8) | (w[3] as u32)
}
pub fn sb(device: &mut device::Device, opcode: u32) {
@@ -486,7 +486,8 @@ pub fn mfc2(device: &mut device::Device, opcode: u32) {
device.rsp.cpu.vpr[rd(opcode) as usize],
velement(opcode) + 1,
);
device.rsp.cpu.gpr[rt(opcode) as usize] = ((hi as u16) << 8 | (lo as u16)) as i16 as i32 as u32
device.rsp.cpu.gpr[rt(opcode) as usize] =
(((hi as u16) << 8) | (lo as u16)) as i16 as i32 as u32
}
pub fn cfc2(device: &mut device::Device, opcode: u32) {
@@ -936,8 +937,8 @@ pub fn shv(device: &mut device::Device, opcode: u32) {
let mut offset = 0;
while offset < 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;
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;
}
File diff suppressed because it is too large Load Diff
+9 -9
View File
@@ -1,18 +1,18 @@
use crate::device;
pub const SI_DRAM_ADDR_REG: u32 = 0;
pub const SI_PIF_ADDR_RD64B_REG: u32 = 1;
//pub const SI_R2_REG: u32 = 2;
//pub const SI_R3_REG: u32 = 3;
pub const SI_PIF_ADDR_WR64B_REG: u32 = 4;
//pub const SI_R5_REG: u32 = 5;
const SI_DRAM_ADDR_REG: u32 = 0;
const SI_PIF_ADDR_RD64B_REG: u32 = 1;
//const SI_R2_REG: u32 = 2;
//const SI_R3_REG: u32 = 3;
const SI_PIF_ADDR_WR64B_REG: u32 = 4;
//const SI_R5_REG: u32 = 5;
pub const SI_STATUS_REG: u32 = 6;
pub const SI_REGS_COUNT: u32 = 7;
pub const SI_STATUS_DMA_BUSY: u32 = 1 << 0;
pub const SI_STATUS_IO_BUSY: u32 = 1 << 1;
//pub const SI_STATUS_DMA_ERROR: u32 = 1 << 3;
pub const SI_STATUS_INTERRUPT: u32 = 1 << 12;
//const SI_STATUS_DMA_ERROR: u32 = 1 << 3;
const SI_STATUS_INTERRUPT: u32 = 1 << 12;
#[derive(PartialEq)]
pub enum DmaDir {
@@ -59,7 +59,7 @@ pub fn dma_write(device: &mut device::Device) {
device::events::create_event(
device,
device::events::EventType::SI,
device.cpu.cop0.regs[device::cop0::COP0_COUNT_REG as usize] + 5200, //based on https://github.com/rasky/n64-systembench
device.cpu.cop0.regs[device::cop0::COP0_COUNT_REG as usize] + 6000, //based on https://github.com/rasky/n64-systembench
dma_event,
)
}
+7 -7
View File
@@ -1,13 +1,13 @@
use crate::device;
use crate::ui;
pub const SRAM_MASK: usize = 0xFFFF;
pub const SRAM_SIZE: usize = 0x8000;
pub const FLASHRAM_SIZE: usize = 0x20000;
const SRAM_MASK: usize = 0xFFFF;
const SRAM_SIZE: usize = 0x8000;
const FLASHRAM_SIZE: usize = 0x20000;
pub const FLASHRAM_TYPE_ID: u32 = 0x11118001;
pub const MX29L1100_ID: u32 = 0x00c2001e;
pub const MX29L0000_ID: u32 = 0x00c20000;
pub const MX29L0001_ID: u32 = 0x00c20001;
const MX29L0000_ID: u32 = 0x00c20000;
const MX29L0001_ID: u32 = 0x00c20001;
#[derive(PartialEq)]
pub enum FlashramMode {
@@ -141,7 +141,7 @@ pub fn dma_read_sram(
format_sram(device);
while i < dram_addr + length {
while i < dram_addr + length && i < device.rdram.size {
device.ui.saves.sram.0[j as usize] = device.rdram.mem[i as usize ^ device.byte_swap];
i += 1;
j += 1;
@@ -191,7 +191,7 @@ pub fn dma_write_sram(
format_sram(device);
while i < dram_addr + length {
while i < dram_addr + length && i < device.rdram.size {
device.rdram.mem[i as usize ^ device.byte_swap] = device.ui.saves.sram.0[j as usize];
i += 1;
j += 1;
+14 -7
View File
@@ -38,8 +38,8 @@ pub fn read(device: &mut device::Device, index: u64) {
device.cpu.cop0.tlb_entries[index as usize].mask << 13;
device.cpu.cop0.regs[device::cop0::COP0_ENTRYHI_REG as usize] =
(device.cpu.cop0.tlb_entries[index as usize].region as u64) << 62
| device.cpu.cop0.tlb_entries[index as usize].vpn2 << 13
((device.cpu.cop0.tlb_entries[index as usize].region as u64) << 62)
| (device.cpu.cop0.tlb_entries[index as usize].vpn2 << 13)
| (device.cpu.cop0.tlb_entries[index as usize].asid) as u64;
device.cpu.cop0.regs[device::cop0::COP0_ENTRYLO0_REG as usize] =
@@ -136,7 +136,8 @@ pub fn probe(device: &mut device::Device) {
if e.region != (device.cpu.cop0.regs[device::cop0::COP0_ENTRYHI_REG as usize] >> 62) as u8 {
continue;
}
if e.g == 0 && e.asid != device.cpu.cop0.regs[device::cop0::COP0_ENTRYHI_REG as usize] as u8 {
if e.g == 0 && e.asid != device.cpu.cop0.regs[device::cop0::COP0_ENTRYHI_REG as usize] as u8
{
continue;
}
device.cpu.cop0.regs[device::cop0::COP0_INDEX_REG as usize] = pos as u64;
@@ -185,8 +186,11 @@ pub fn tlb_unmap(device: &mut device::Device, index: u64) {
pub fn tlb_map(device: &mut device::Device, index: u64) {
let e = &mut device.cpu.cop0.tlb_entries[index as usize];
if e.v_even != 0 && e.start_even < e.end_even
&& !(e.start_even >= 0x80000000 && e.end_even < 0xC0000000) && e.phys_even < 0x20000000 {
if e.v_even != 0
&& e.start_even < e.end_even
&& !(e.start_even >= 0x80000000 && e.end_even < 0xC0000000)
&& e.phys_even < 0x20000000
{
let mut i = e.start_even;
while i < e.end_even {
device.cpu.cop0.tlb_lut_r[(i >> 12) as usize].address =
@@ -205,8 +209,11 @@ pub fn tlb_map(device: &mut device::Device, index: u64) {
}
}
if e.v_odd != 0 && e.start_odd < e.end_odd
&& !(e.start_odd >= 0x80000000 && e.end_odd < 0xC0000000) && e.phys_odd < 0x20000000 {
if e.v_odd != 0
&& e.start_odd < e.end_odd
&& !(e.start_odd >= 0x80000000 && e.end_odd < 0xC0000000)
&& e.phys_odd < 0x20000000
{
let mut i = e.start_odd;
while i < e.end_odd {
device.cpu.cop0.tlb_lut_r[(i >> 12) as usize].address =
+25 -21
View File
@@ -2,20 +2,20 @@ use crate::device;
use crate::ui;
use governor::clock::Clock;
pub const VI_STATUS_REG: u32 = 0;
//pub const VI_ORIGIN_REG: u32 = 1;
//pub const VI_WIDTH_REG: u32 = 2;
//pub const VI_V_INTR_REG: u32 = 3;
pub const VI_CURRENT_REG: u32 = 4;
//pub const VI_BURST_REG: u32 = 5;
pub const VI_V_SYNC_REG: u32 = 6;
pub const VI_H_SYNC_REG: u32 = 7;
//pub const VI_LEAP_REG: u32 = 8;
//pub const VI_H_START_REG: u32 = 9;
//pub const VI_V_START_REG: u32 = 10;
//pub const VI_V_BURST_REG: u32 = 11;
//pub const VI_X_SCALE_REG: u32 = 12;
//pub const VI_Y_SCALE_REG: u32 = 13;
const VI_STATUS_REG: u32 = 0;
//const VI_ORIGIN_REG: u32 = 1;
pub const VI_WIDTH_REG: u32 = 2;
//const VI_V_INTR_REG: u32 = 3;
const VI_CURRENT_REG: u32 = 4;
//const VI_BURST_REG: u32 = 5;
const VI_V_SYNC_REG: u32 = 6;
const VI_H_SYNC_REG: u32 = 7;
//const VI_LEAP_REG: u32 = 8;
pub const VI_H_START_REG: u32 = 9;
pub const VI_V_START_REG: u32 = 10;
//const VI_V_BURST_REG: u32 = 11;
pub const VI_X_SCALE_REG: u32 = 12;
pub const VI_Y_SCALE_REG: u32 = 13;
pub const VI_REGS_COUNT: u32 = 14;
pub struct Vi {
@@ -25,10 +25,13 @@ pub struct Vi {
pub field: u32,
pub limiter: Option<governor::DefaultDirectRateLimiter>,
pub count_per_scanline: u64,
pub vi_counter: u64,
}
//static mut FRAME_COUNTER: u64 = 0;
const LIMIT_BUFFER: u64 = 3;
pub fn set_expected_refresh_rate(device: &mut device::Device) {
let expected_refresh_rate = device.vi.clock as f64
/ (device.vi.regs[VI_V_SYNC_REG as usize] + 1) as f64
@@ -39,7 +42,7 @@ pub fn set_expected_refresh_rate(device: &mut device::Device) {
device.vi.delay / (device.vi.regs[VI_V_SYNC_REG as usize] + 1) as u64;
let quota = governor::Quota::with_period(std::time::Duration::from_secs_f64(
1.0 / expected_refresh_rate,
(1.0 / expected_refresh_rate) * LIMIT_BUFFER as f64,
))
.unwrap();
device.vi.limiter = Some(governor::RateLimiter::direct(quota))
@@ -97,21 +100,19 @@ pub fn write_regs(device: &mut device::Device, address: u64, value: u32, mask: u
device::memory::masked_write_32(&mut device.vi.regs[reg as usize], value, mask);
set_vertical_interrupt(device);
set_expected_refresh_rate(device);
ui::video::set_register(reg as u32, device.vi.regs[reg as usize])
}
}
VI_H_SYNC_REG => {
if device.vi.regs[reg as usize] != value & mask {
device::memory::masked_write_32(&mut device.vi.regs[reg as usize], value, mask);
set_expected_refresh_rate(device);
ui::video::set_register(reg as u32, device.vi.regs[reg as usize])
}
}
_ => {
device::memory::masked_write_32(&mut device.vi.regs[reg as usize], value, mask);
ui::video::set_register(reg as u32, device.vi.regs[reg as usize])
}
}
ui::video::set_register(reg as u32, device.vi.regs[reg as usize])
}
pub fn vertical_interrupt_event(device: &mut device::Device) {
@@ -123,7 +124,10 @@ pub fn vertical_interrupt_event(device: &mut device::Device) {
}
*/
speed_limiter(device);
device.vi.vi_counter += 1;
if device.vi.vi_counter % LIMIT_BUFFER == 0 {
speed_limiter(device);
}
/* toggle vi field if in interlaced mode */
device.vi.field ^= (device.vi.regs[VI_STATUS_REG as usize] >> 6) & 0x1;
@@ -163,8 +167,8 @@ pub fn speed_limiter(device: &device::Device) {
if result.is_err() {
let outcome = result.unwrap_err();
let dur = outcome.wait_time_from(governor::clock::DefaultClock::default().now());
std::thread::sleep(dur);
spin_sleep::sleep(dur);
device.vi.limiter.as_ref().unwrap().check().unwrap();
let _ = device.vi.limiter.as_ref().unwrap().check();
}
}
+2997
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -126,7 +126,7 @@ fn main() {
eframe::run_native(
"gopher64",
options,
Box::new(|_cc| Box::new(ui::gui::GopherEguiApp::new())),
Box::new(|cc| Ok(Box::new(ui::gui::GopherEguiApp::new(cc)))),
)
.unwrap();
}
+2 -1
View File
@@ -4,6 +4,7 @@ pub mod gui;
pub mod input;
pub mod storage;
pub mod video;
pub mod vru;
pub struct Ui {
pub controllers: [input::Controllers; 4],
@@ -18,6 +19,7 @@ pub struct Ui {
pub video_subsystem: Option<sdl2::VideoSubsystem>,
pub audio_subsystem: Option<sdl2::AudioSubsystem>,
pub joystick_subsystem: Option<sdl2::JoystickSubsystem>,
#[allow(dead_code)]
pub controller_subsystem: Option<sdl2::GameControllerSubsystem>,
pub window: Option<sdl2::video::Window>,
pub audio_device: Option<sdl2::audio::AudioQueue<i16>>,
@@ -25,7 +27,6 @@ pub struct Ui {
impl Drop for Ui {
fn drop(&mut self) {
storage::write_saves(self);
write_config(self);
}
}
+2 -2
View File
@@ -24,11 +24,11 @@ pub fn play_audio(device: &mut device::Device, dram_addr: usize, length: u64) {
while i < length as usize / 2 {
// Left channel
primary_buffer[i] = device.rdram.mem[dram_addr + (i * 2) + 2] as i16
| (device.rdram.mem[dram_addr + (i * 2) + 3] as i16) << 8;
| ((device.rdram.mem[dram_addr + (i * 2) + 3] as i16) << 8);
// Right channel
primary_buffer[i + 1] = device.rdram.mem[dram_addr + (i * 2)] as i16
| (device.rdram.mem[dram_addr + (i * 2) + 1] as i16) << 8;
| ((device.rdram.mem[dram_addr + (i * 2) + 1] as i16) << 8);
i += 2;
}
+10
View File
@@ -15,10 +15,17 @@ pub struct Input {
pub input_profiles: std::collections::HashMap<String, InputProfile>,
pub input_profile_binding: [String; 4],
pub controller_assignment: [Option<String>; 4],
pub controller_enabled: [bool; 4],
pub emulate_vru: bool,
}
#[derive(serde::Serialize, serde::Deserialize)]
pub struct Video {
pub upscale: bool,
}
#[derive(serde::Serialize, serde::Deserialize)]
pub struct Config {
pub input: Input,
pub video: Video,
}
impl Config {
@@ -35,7 +42,10 @@ impl Config {
],
controller_assignment: [None, None, None, None],
input_profiles,
controller_enabled: [true, false, false, false],
emulate_vru: false,
},
video: Video { upscale: false },
}
}
}
+147 -7
View File
@@ -9,6 +9,13 @@ pub struct GopherEguiApp {
selected_controller: [i32; 4],
selected_profile: [String; 4],
input_profiles: Vec<String>,
controller_enabled: [bool; 4],
upscale: bool,
emulate_vru: bool,
show_vru_dialog: bool,
vru_window_receiver: Option<std::sync::mpsc::Receiver<Vec<String>>>,
vru_word_notifier: Option<std::sync::mpsc::Sender<String>>,
vru_word_list: Vec<String>,
}
fn get_input_profiles(game_ui: &ui::Ui) -> Vec<String> {
@@ -31,7 +38,9 @@ fn get_controllers(game_ui: &ui::Ui) -> Vec<String> {
}
impl GopherEguiApp {
pub fn new() -> GopherEguiApp {
pub fn new(cc: &eframe::CreationContext<'_>) -> GopherEguiApp {
add_japanese_font(&cc.egui_ctx);
let game_ui = ui::Ui::new();
let joystick_subsystem = game_ui.joystick_subsystem.as_ref().unwrap();
let num_joysticks = joystick_subsystem.num_joysticks().unwrap();
@@ -63,11 +72,25 @@ impl GopherEguiApp {
selected_controller,
controllers: get_controllers(&game_ui),
input_profiles: get_input_profiles(&game_ui),
controller_enabled: game_ui.config.input.controller_enabled,
upscale: game_ui.config.video.upscale,
emulate_vru: game_ui.config.input.emulate_vru,
show_vru_dialog: false,
vru_window_receiver: None,
vru_word_notifier: None,
vru_word_list: Vec::new(),
}
}
}
fn save_config(game_ui: &mut ui::Ui, selected_controller: [i32; 4], selected_profile: [String; 4]) {
fn save_config(
game_ui: &mut ui::Ui,
selected_controller: [i32; 4],
selected_profile: [String; 4],
controller_enabled: [bool; 4],
upscale: bool,
emulate_vru: bool,
) {
let joystick_subsystem = game_ui.joystick_subsystem.as_ref().unwrap();
for (pos, item) in selected_controller.iter().enumerate() {
if *item != -1 {
@@ -83,6 +106,10 @@ fn save_config(game_ui: &mut ui::Ui, selected_controller: [i32; 4], selected_pro
}
game_ui.config.input.input_profile_binding = selected_profile;
game_ui.config.input.controller_enabled = controller_enabled;
game_ui.config.video.upscale = upscale;
game_ui.config.input.emulate_vru = emulate_vru;
}
impl Drop for GopherEguiApp {
@@ -92,6 +119,9 @@ impl Drop for GopherEguiApp {
&mut game_ui,
self.selected_controller,
self.selected_profile.clone(),
self.controller_enabled,
self.upscale,
self.emulate_vru,
);
}
}
@@ -129,13 +159,35 @@ impl eframe::App for GopherEguiApp {
}
egui::CentralPanel::default().show(ctx, |ui| {
ui.set_enabled(!self.configure_profile);
if self.configure_profile {
ui.disable()
}
if ui.button("Open ROM").clicked() {
// Spawn dialog on main thread
let task = rfd::AsyncFileDialog::new().pick_file();
let selected_controller = self.selected_controller;
let selected_profile = self.selected_profile.clone();
let controller_enabled = self.controller_enabled;
let upscale = self.upscale;
let emulate_vru = self.emulate_vru;
let (vru_window_notifier, vru_window_receiver): (
std::sync::mpsc::Sender<Vec<String>>,
std::sync::mpsc::Receiver<Vec<String>>,
) = std::sync::mpsc::channel();
let (vru_word_notifier, vru_word_receiver): (
std::sync::mpsc::Sender<String>,
std::sync::mpsc::Receiver<String>,
) = std::sync::mpsc::channel();
if emulate_vru {
self.vru_window_receiver = Some(vru_window_receiver);
self.vru_word_notifier = Some(vru_word_notifier);
}
let gui_ctx = ctx.clone();
execute(async move {
let file = task.await;
@@ -149,7 +201,19 @@ impl eframe::App for GopherEguiApp {
}
let _ = std::fs::File::create(running_file.clone());
let mut device = device::Device::new();
save_config(&mut device.ui, selected_controller, selected_profile);
save_config(
&mut device.ui,
selected_controller,
selected_profile,
controller_enabled,
upscale,
emulate_vru,
);
if emulate_vru {
device.vru.window_notifier = Some(vru_window_notifier);
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());
}
@@ -169,15 +233,17 @@ impl eframe::App for GopherEguiApp {
ui.add_space(32.0);
ui.label("Controller Config:");
egui::Grid::new("some_unique_id").show(ui, |ui| {
egui::Grid::new("controller_config").show(ui, |ui| {
ui.label("Port");
ui.label("Enabled");
ui.label("Profile");
ui.label("Controller");
ui.end_row();
for i in 0..4 {
ui.label(format!("{}", i + 1));
ui.checkbox(&mut self.controller_enabled[i], "");
egui::ComboBox::from_id_source(format!("profile-combo-{}", i))
egui::ComboBox::from_id_salt(format!("profile-combo-{}", i))
.selected_text(self.selected_profile[i].clone())
.show_ui(ui, |ui| {
for j in 0..self.input_profiles.len() {
@@ -194,7 +260,7 @@ impl eframe::App for GopherEguiApp {
} else {
self.controllers[self.selected_controller[i] as usize].clone()
};
egui::ComboBox::from_id_source(format!("controller-combo-{}", i))
egui::ComboBox::from_id_salt(format!("controller-combo-{}", i))
.selected_text(controller_text)
.show_ui(ui, |ui| {
ui.selectable_value(
@@ -213,10 +279,84 @@ impl eframe::App for GopherEguiApp {
ui.end_row();
}
});
ui.add_space(32.0);
ui.checkbox(&mut self.upscale, "High-Res Graphics");
ui.checkbox(
&mut self.emulate_vru,
"Emulate VRU (connects VRU to controller port 4)",
);
ui.add_space(32.0);
ui.label(format!("Version: {}", env!("CARGO_PKG_VERSION")));
});
if self.emulate_vru && self.vru_window_receiver.is_some() {
let result = self.vru_window_receiver.as_ref().unwrap().try_recv();
if result.is_ok() {
self.show_vru_dialog = true;
self.vru_word_list = result.unwrap();
}
}
if self.show_vru_dialog {
ctx.show_viewport_immediate(
egui::ViewportId::from_hash_of("vru_dialog"),
egui::ViewportBuilder::default()
.with_title("What would you like to say?")
.with_always_on_top(),
|ctx, class| {
assert!(
class == egui::ViewportClass::Immediate,
"This egui backend doesn't support multiple viewports"
);
egui::CentralPanel::default().show(ctx, |ui| {
egui::Grid::new("vru_words").show(ui, |ui| {
for (i, v) in self.vru_word_list.iter().enumerate() {
if i % 5 == 0 {
ui.end_row();
}
if ui.button((*v).to_string()).clicked() {
self.vru_word_notifier
.as_ref()
.unwrap()
.send(v.clone())
.unwrap();
self.show_vru_dialog = false;
}
}
});
});
if ctx.input(|i| i.viewport().close_requested()) {
self.vru_word_notifier
.as_ref()
.unwrap()
.send(String::from(""))
.unwrap();
self.show_vru_dialog = false;
}
},
);
}
}
}
fn execute<F: std::future::Future<Output = ()> + Send + 'static>(f: F) {
std::thread::spawn(move || futures::executor::block_on(f));
}
fn add_japanese_font(ctx: &egui::Context) {
ctx.add_font(epaint::text::FontInsert::new(
"japanese_font",
egui::FontData::from_static(include_bytes!("../../data/NotoSansJP-Regular.ttf")),
vec![
epaint::text::InsertFontFamily {
family: egui::FontFamily::Proportional,
priority: egui::epaint::text::FontPriority::Lowest,
},
epaint::text::InsertFontFamily {
family: egui::FontFamily::Monospace,
priority: egui::epaint::text::FontPriority::Lowest,
},
],
));
}
+72 -38
View File
@@ -2,29 +2,29 @@ use std::ops::Neg;
use crate::ui;
pub const R_DPAD: usize = 0;
pub const L_DPAD: usize = 1;
pub const D_DPAD: usize = 2;
pub const U_DPAD: usize = 3;
pub const START_BUTTON: usize = 4;
pub const Z_TRIG: usize = 5;
pub const B_BUTTON: usize = 6;
pub const A_BUTTON: usize = 7;
pub const R_CBUTTON: usize = 8;
pub const L_CBUTTON: usize = 9;
pub const D_CBUTTON: usize = 10;
pub const U_CBUTTON: usize = 11;
pub const R_TRIG: usize = 12;
pub const L_TRIG: usize = 13;
pub const X_AXIS: usize = 16;
pub const Y_AXIS: usize = 24;
const R_DPAD: usize = 0;
const L_DPAD: usize = 1;
const D_DPAD: usize = 2;
const U_DPAD: usize = 3;
const START_BUTTON: usize = 4;
const Z_TRIG: usize = 5;
const B_BUTTON: usize = 6;
const A_BUTTON: usize = 7;
const R_CBUTTON: usize = 8;
const L_CBUTTON: usize = 9;
const D_CBUTTON: usize = 10;
const U_CBUTTON: usize = 11;
const R_TRIG: usize = 12;
const L_TRIG: usize = 13;
const X_AXIS: usize = 16;
const Y_AXIS: usize = 24;
pub const AXIS_LEFT: usize = 14;
pub const AXIS_RIGHT: usize = 15;
pub const AXIS_UP: usize = 16;
pub const AXIS_DOWN: usize = 17;
const AXIS_LEFT: usize = 14;
const AXIS_RIGHT: usize = 15;
const AXIS_UP: usize = 16;
const AXIS_DOWN: usize = 17;
pub const MAX_AXIS_VALUE: f64 = 85.0;
const MAX_AXIS_VALUE: f64 = 85.0;
pub struct Controllers {
pub game_controller: Option<sdl2::controller::GameController>,
@@ -87,28 +87,36 @@ pub fn set_axis_from_controller(
let mut y = 0.0;
if profile.controller_axis[AXIS_LEFT].0 {
let axis_position =
controller.axis(std::mem::transmute(profile.controller_axis[AXIS_LEFT].1));
controller.axis(std::mem::transmute::<i32, sdl2::controller::Axis>(
profile.controller_axis[AXIS_LEFT].1,
));
if axis_position as isize * profile.controller_axis[AXIS_LEFT].2 as isize > 0 {
x = axis_position as f64 * MAX_AXIS_VALUE / i16::MAX as f64;
}
}
if profile.controller_axis[AXIS_RIGHT].0 {
let axis_position =
controller.axis(std::mem::transmute(profile.controller_axis[AXIS_RIGHT].1));
controller.axis(std::mem::transmute::<i32, sdl2::controller::Axis>(
profile.controller_axis[AXIS_RIGHT].1,
));
if axis_position as isize * profile.controller_axis[AXIS_RIGHT].2 as isize > 0 {
x = axis_position as f64 * MAX_AXIS_VALUE / i16::MAX as f64;
}
}
if profile.controller_axis[AXIS_DOWN].0 {
let axis_position =
controller.axis(std::mem::transmute(profile.controller_axis[AXIS_DOWN].1));
controller.axis(std::mem::transmute::<i32, sdl2::controller::Axis>(
profile.controller_axis[AXIS_DOWN].1,
));
if axis_position as isize * profile.controller_axis[AXIS_DOWN].2 as isize > 0 {
y = (axis_position as f64 * MAX_AXIS_VALUE / i16::MAX as f64).neg();
}
}
if profile.controller_axis[AXIS_UP].0 {
let axis_position =
controller.axis(std::mem::transmute(profile.controller_axis[AXIS_UP].1));
controller.axis(std::mem::transmute::<i32, sdl2::controller::Axis>(
profile.controller_axis[AXIS_UP].1,
));
if axis_position as isize * profile.controller_axis[AXIS_UP].2 as isize > 0 {
y = (axis_position as f64 * MAX_AXIS_VALUE / i16::MAX as f64).neg();
}
@@ -125,22 +133,34 @@ pub fn set_axis_from_keys(
let mut x = 0.0;
let mut y = 0.0;
if profile.keys[AXIS_LEFT].0
&& keyboard_state.is_scancode_pressed(std::mem::transmute(profile.keys[AXIS_LEFT].1))
&& keyboard_state
.is_scancode_pressed(std::mem::transmute::<i32, sdl2::keyboard::Scancode>(
profile.keys[AXIS_LEFT].1,
))
{
x = -MAX_AXIS_VALUE
}
if profile.keys[AXIS_RIGHT].0
&& keyboard_state.is_scancode_pressed(std::mem::transmute(profile.keys[AXIS_RIGHT].1))
&& keyboard_state
.is_scancode_pressed(std::mem::transmute::<i32, sdl2::keyboard::Scancode>(
profile.keys[AXIS_RIGHT].1,
))
{
x = MAX_AXIS_VALUE
}
if profile.keys[AXIS_DOWN].0
&& keyboard_state.is_scancode_pressed(std::mem::transmute(profile.keys[AXIS_DOWN].1))
&& keyboard_state
.is_scancode_pressed(std::mem::transmute::<i32, sdl2::keyboard::Scancode>(
profile.keys[AXIS_DOWN].1,
))
{
y = -MAX_AXIS_VALUE
}
if profile.keys[AXIS_UP].0
&& keyboard_state.is_scancode_pressed(std::mem::transmute(profile.keys[AXIS_UP].1))
&& keyboard_state
.is_scancode_pressed(std::mem::transmute::<i32, sdl2::keyboard::Scancode>(
profile.keys[AXIS_UP].1,
))
{
y = MAX_AXIS_VALUE
}
@@ -162,7 +182,9 @@ pub fn set_buttons_from_joystick(
let profile_joystick_hat = profile.joystick_hat[i];
if profile_joystick_hat.0
&& joystick.hat(profile_joystick_hat.1).unwrap()
== unsafe { std::mem::transmute(profile_joystick_hat.2) }
== unsafe {
std::mem::transmute::<i8, sdl2::joystick::HatState>(profile_joystick_hat.2)
}
{
*keys |= 1 << i;
}
@@ -187,15 +209,20 @@ pub fn set_buttons_from_controller(
let profile_controller_button = profile.controller_buttons[i];
if profile_controller_button.0 {
unsafe {
*keys |=
(controller.button(std::mem::transmute(profile_controller_button.1)) as u32) << i;
*keys |= (controller.button(std::mem::transmute::<i32, sdl2::controller::Button>(
profile_controller_button.1,
)) as u32)
<< i;
}
}
let profile_controller_axis = profile.controller_axis[i];
if profile_controller_axis.0 {
let axis_position =
unsafe { controller.axis(std::mem::transmute(profile_controller_axis.1)) };
let axis_position = unsafe {
controller.axis(std::mem::transmute::<i32, sdl2::controller::Axis>(
profile_controller_axis.1,
))
};
if axis_position as isize * profile_controller_axis.2 as isize > 0
&& axis_position.saturating_abs() > i16::MAX / 2
{
@@ -219,8 +246,10 @@ pub fn get(ui: &mut ui::Ui, channel: usize) -> u32 {
let profile_key = profile.keys[i];
if profile_key.0 {
unsafe {
keys |= (keyboard_state.is_scancode_pressed(std::mem::transmute(profile_key.1))
as u32)
keys |= (keyboard_state
.is_scancode_pressed(std::mem::transmute::<i32, sdl2::keyboard::Scancode>(
profile_key.1,
)) as u32)
<< i;
}
}
@@ -377,8 +406,13 @@ pub fn configure_input_profile(ui: &mut ui::Ui, profile: String) {
key_set = true
}
sdl2::event::Event::JoyHatMotion { hat_idx, state, .. } => {
new_joystick_hat[*value] =
unsafe { (true, hat_idx as u32, std::mem::transmute(state)) };
new_joystick_hat[*value] = unsafe {
(
true,
hat_idx as u32,
std::mem::transmute::<sdl2::joystick::HatState, i8>(state),
)
};
key_set = true
}
sdl2::event::Event::JoyAxisMotion {
+1 -1
View File
@@ -148,7 +148,7 @@ pub fn load_saves(ui: &mut ui::Ui) {
pub fn write_rom_save(ui: &ui::Ui) {
let f = std::fs::File::create(ui.paths.romsave_file_path.clone()).unwrap();
serde_json::to_writer(f, &ui.saves.romsave).unwrap();
serde_json::to_writer(f, &ui.saves.romsave.0).unwrap();
}
pub fn write_saves(ui: &ui::Ui) {
+64 -21
View File
@@ -1,36 +1,80 @@
use crate::ui;
use crate::device;
extern "C" {
pub fn vk_init(rdram_ptr: usize, rdram_size: u32, fullscreen: u8);
pub fn set_sdl_window(window: usize);
pub fn rdp_update_screen() -> u8;
pub fn rdp_set_vi_register(reg: u32, value: u32);
pub fn rdp_process_commands(dpc_regs: &mut [u32; 8], SP_DMEM: &mut [u8; 8192]) -> u64;
pub fn full_sync();
#[repr(C)]
pub struct GfxInfo {
pub rdram: *mut u8,
pub dmem: *mut u8,
pub rdram_size: u32,
pub dpc_current_reg: *mut u32,
pub dpc_start_reg: *mut u32,
pub dpc_end_reg: *mut u32,
pub dpc_status_reg: *mut u32,
pub vi_h_start_reg: *mut u32,
pub vi_v_start_reg: *mut u32,
pub vi_x_scale_reg: *mut u32,
pub vi_y_scale_reg: *mut u32,
pub vi_width_reg: *mut u32,
}
pub fn init(ui: &mut ui::Ui, rdram_ptr: *mut u8, rdram_size: usize, fullscreen: bool) {
let mut builder = ui
unsafe extern "C" {
pub fn rdp_init(window: usize, gfx_info: GfxInfo, fullscreen: bool, upscale: bool);
pub fn rdp_close();
pub fn rdp_update_screen() -> bool;
pub fn rdp_set_vi_register(reg: u32, value: u32);
pub fn rdp_process_commands() -> u64;
pub fn rdp_full_sync();
}
pub fn init(device: &mut device::Device, fullscreen: bool) {
let mut builder = device
.ui
.video_subsystem
.as_ref()
.unwrap()
.window("gopher64", 640, 480);
builder.position_centered().vulkan();
if fullscreen {
builder.fullscreen_desktop();
} else {
builder.resizable();
}
ui.window = Some(builder.build().unwrap());
device.ui.window = Some(builder.build().unwrap());
let gfx_info = GfxInfo {
rdram: device.rdram.mem.as_mut_ptr(),
dmem: device.rsp.mem.as_mut_ptr(),
rdram_size: device.rdram.size,
dpc_current_reg: &mut device.rdp.regs_dpc[device::rdp::DPC_CURRENT_REG as usize],
dpc_start_reg: &mut device.rdp.regs_dpc[device::rdp::DPC_START_REG as usize],
dpc_end_reg: &mut device.rdp.regs_dpc[device::rdp::DPC_END_REG as usize],
dpc_status_reg: &mut device.rdp.regs_dpc[device::rdp::DPC_STATUS_REG as usize],
vi_h_start_reg: &mut device.vi.regs[device::vi::VI_H_START_REG as usize],
vi_v_start_reg: &mut device.vi.regs[device::vi::VI_V_START_REG as usize],
vi_x_scale_reg: &mut device.vi.regs[device::vi::VI_X_SCALE_REG as usize],
vi_y_scale_reg: &mut device.vi.regs[device::vi::VI_Y_SCALE_REG as usize],
vi_width_reg: &mut device.vi.regs[device::vi::VI_WIDTH_REG as usize],
};
unsafe {
set_sdl_window(ui.window.as_mut().unwrap().raw() as usize);
vk_init(rdram_ptr as usize, rdram_size as u32, fullscreen as u8)
rdp_init(
device.ui.window.as_mut().unwrap().raw() as usize,
gfx_info,
fullscreen,
device.ui.config.video.upscale,
)
}
}
pub fn update_screen() -> u8 {
// when the window is closed, running is set to 0
pub fn close() {
unsafe {
rdp_close();
}
}
pub fn update_screen() -> bool {
// when the window is closed, running is set to false
unsafe { rdp_update_screen() }
}
@@ -40,14 +84,13 @@ pub fn set_register(reg: u32, value: u32) {
}
}
pub fn process_rdp_list(dpc_regs: &mut [u32; 8], sp_dmem: &mut [u8; 8192]) -> u64 {
unsafe { rdp_process_commands(dpc_regs, sp_dmem) }
pub fn process_rdp_list() -> u64 {
unsafe { rdp_process_commands() }
}
pub fn rdp_full_sync() {
pub fn full_sync() {
unsafe {
full_sync();
rdp_full_sync();
}
}
+28
View File
@@ -0,0 +1,28 @@
use eframe::egui;
use crate::ui;
pub fn prompt_for_match(
words: &[String],
window_notifier: &std::sync::mpsc::Sender<Vec<String>>,
word_index_notifier: &std::sync::mpsc::Receiver<String>,
gui_ctx: &egui::Context,
) -> u16 {
let mut dedup_words = words.to_owned();
dedup_words.sort();
dedup_words.dedup();
window_notifier.send(dedup_words).unwrap();
gui_ctx.request_repaint(); // this is so the window pops up right away
let mut result = word_index_notifier.try_recv();
while result.is_err() {
result = word_index_notifier.try_recv();
std::thread::sleep(std::time::Duration::from_secs_f64(1.0 / 60.0));
ui::video::update_screen(); // so the OS doesn't complain about the game window being frozen
}
for (i, v) in words.iter().enumerate() {
if *v == *result.as_ref().unwrap() {
return i as u16;
}
}
0x7FFF
}