diff --git a/.gitmodules b/.gitmodules index 1e8cfea..775e0c4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -11,3 +11,6 @@ [submodule "incbin"] path = incbin url = https://github.com/graphitemaster/incbin +[submodule "implot"] + path = implot + url = https://github.com/epezent/implot diff --git a/CMakeLists.txt b/CMakeLists.txt index e7a9a4d..c5d66e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,6 +95,7 @@ target_sources(iris PRIVATE frontend/ui/memory_card_tool.cpp frontend/ui/menubar.cpp frontend/ui/modules.cpp + frontend/ui/overlay.cpp frontend/ui/pad.cpp frontend/ui/settings.cpp frontend/ui/spu2.cpp @@ -171,13 +172,17 @@ target_sources(iris PRIVATE imgui/imgui_tables.cpp imgui/imgui_widgets.cpp imgui/backends/imgui_impl_sdl3.cpp - imgui/backends/imgui_impl_sdlgpu3.cpp) + imgui/backends/imgui_impl_sdlgpu3.cpp + implot/implot_demo.cpp + implot/implot_items.cpp + implot/implot.cpp) add_subdirectory(SDL EXCLUDE_FROM_ALL) target_include_directories(iris PRIVATE imgui imgui/backends + implot SDL/include frontend incbin diff --git a/compat.txt b/compat.txt index 81e1d1e..f19443b 100644 --- a/compat.txt +++ b/compat.txt @@ -11,10 +11,12 @@ "Klonoa 2 - Lunatea's Veil (USA)" - Doesn't work on Release builds (!), requires 16-bit DMAC writes "Namco Museum 50th Anniversary (USA)" - Requires MFIFO "R-Type Final (Japan)" - Requires MFIFO +"Sega Ages 2500 Series Vol. 23 - Sega Memorial Selection (Japan)" - GIF DMA read from NULL "Sega Genesis Collection (USA)" - Works, "forgets" to change the videomode causing wrong graphics at startup (needs 24-bit 640x448 interlaced?) "Simpsons, The - Hit & Run (USA)" - Needs MFIFO "Tekken 4 (USA)" - Needs MFIFO "Tekken Tag Tournament (USA) (v1.00)" - Needs MFIFO "Thunder Force VI (Japan)" - Crashes on an invalid GIF DMA address when starting up (compare against Dobie) "Virtua Fighter 4 - Evolution (USA)" - Works, uses filling mode +"Virtua Fighter - Cyber Generation - Judgment Six no Yabou (Japan)" - PMTHL unimplemented "We Love Katamari (USA)" - Uses filling mode, gets stuck trying to play an FMV after the Namco logo? \ No newline at end of file diff --git a/frontend/input.cpp b/frontend/input.cpp index ab674a1..cfeb072 100644 --- a/frontend/input.cpp +++ b/frontend/input.cpp @@ -151,6 +151,10 @@ void handle_keydown_event(iris::instance* iris, SDL_KeyboardEvent& key) { case SDLK_0: { ps2_iop_intc_irq(iris->ps2->iop_intc, IOP_INTC_USB); } break; + case SDLK_I: ds_analog_change(iris->ds[0], DS_AX_LEFT_V, 0xff); break; + case SDLK_J: ds_analog_change(iris->ds[0], DS_AX_LEFT_H, 0); break; + case SDLK_K: ds_analog_change(iris->ds[0], DS_AX_LEFT_V, 0); break; + case SDLK_L: ds_analog_change(iris->ds[0], DS_AX_LEFT_H, 0xff); break; } uint16_t mask = map_button(key.key); @@ -159,6 +163,13 @@ void handle_keydown_event(iris::instance* iris, SDL_KeyboardEvent& key) { } void handle_keyup_event(iris::instance* iris, SDL_KeyboardEvent& key) { + switch (key.key) { + case SDLK_I: ds_analog_change(iris->ds[0], DS_AX_LEFT_V, 0x80); break; + case SDLK_J: ds_analog_change(iris->ds[0], DS_AX_LEFT_H, 0x80); break; + case SDLK_K: ds_analog_change(iris->ds[0], DS_AX_LEFT_V, 0x80); break; + case SDLK_L: ds_analog_change(iris->ds[0], DS_AX_LEFT_H, 0x80); break; + } + uint16_t mask = map_button(key.key); ds_button_release(iris->ds[0], mask); diff --git a/frontend/iris.cpp b/frontend/iris.cpp index 87cf9b0..7b83b11 100644 --- a/frontend/iris.cpp +++ b/frontend/iris.cpp @@ -247,6 +247,7 @@ void update_window(iris::instance* iris) { // if (iris->show_gamelist) show_gamelist(iris); if (iris->show_imgui_demo) ShowDemoWindow(&iris->show_imgui_demo); if (iris->show_bios_setting_window) show_bios_setting_window(iris); + if (iris->show_overlay) show_overlay(iris); // Display little pause icon in the top right corner if (iris->pause) { diff --git a/frontend/iris.hpp b/frontend/iris.hpp index e5da456..b668cca 100644 --- a/frontend/iris.hpp +++ b/frontend/iris.hpp @@ -65,6 +65,40 @@ struct elf_symbol { uint32_t size; }; +// Event -> Action +enum { + INPUT_ACTION_PRESS_BUTTON, + INPUT_ACTION_RELEASE_BUTTON, + INPUT_ACTION_MOVE_AXIS +}; + +enum { + INPUT_CONTROLLER_DUALSHOCK2 + + // Large To-do list here, we're missing the Namco GunCon + // controllers, JogCon, NegCon, Buzz! Buzzer, the Train + // controllers, Taiko Drum Master controller, the Dance Dance + // Revolution mat, Guitar Hero controllers, etc. +}; + +// struct input_action { +// int action; + +// union { +// uint32_t button; +// uint8_t axis; +// }; +// }; + +// class input_device { +// int controller; + +// public: +// void set_controller(int controller); +// int get_controller(); +// virtual input_action map_event(SDL_Event* event) = 0; +// }; + struct instance { SDL_Window* window = nullptr; SDL_GPUDevice* device = nullptr; @@ -101,6 +135,7 @@ struct instance { ImFont* font_body = nullptr; ImFont* font_icons = nullptr; ImFont* font_icons_big = nullptr; + ImFont* font_black = nullptr; std::string elf_path = ""; std::string boot_path = ""; @@ -149,6 +184,7 @@ struct instance { bool show_memory_card_tool = false; bool show_imgui_demo = false; bool show_vu_disassembler = false; + bool show_overlay = false; // Special windows bool show_bios_setting_window = false; @@ -177,6 +213,7 @@ struct instance { int menubar_height = 0; bool mute = false; float volume = 1.0f; + int timescale = 8; bool limit_fps = true; float fps_cap = 60.0f; @@ -192,6 +229,8 @@ struct instance { struct ds_state* ds[2] = { nullptr }; struct mcd_state* mcd[2] = { nullptr }; + // input_device* device[2]; + float drop_file_alpha = 0.0f; float drop_file_alpha_delta = 0.0f; float drop_file_alpha_target = 0.0f; @@ -239,6 +278,7 @@ void show_settings(iris::instance* iris); void show_pad_debugger(iris::instance* iris); void show_symbols(iris::instance* iris); void show_threads(iris::instance* iris); +void show_overlay(iris::instance* iris); void show_memory_card_tool(iris::instance* iris); void show_bios_setting_window(iris::instance* iris); // void show_gamelist(iris::instance* iris); diff --git a/frontend/settings.cpp b/frontend/settings.cpp index d6c9888..e0ce1a4 100644 --- a/frontend/settings.cpp +++ b/frontend/settings.cpp @@ -84,6 +84,8 @@ int parse_toml_settings(iris::instance* iris) { iris->integer_scaling = display["integer_scaling"].value_or(false); iris->scale = display["scale"].value_or(1.5f); iris->renderer_backend = display["renderer"].value_or(RENDERER_SOFTWARE_THREAD); + iris->window_width = display["window_width"].value_or(960); + iris->window_height = display["window_height"].value_or(720); auto audio = tbl["audio"]; iris->mute = audio["mute"].value_or(false); @@ -108,10 +110,13 @@ int parse_toml_settings(iris::instance* iris) { iris->show_status_bar = debugger["show_status_bar"].value_or(true); iris->show_pad_debugger = debugger["show_pad_debugger"].value_or(false); iris->show_threads = debugger["show_threads"].value_or(false); + iris->show_overlay = debugger["show_overlay"].value_or(false); + // iris->show_symbols = debugger["show_symbols"].value_or(false); iris->show_breakpoints = debugger["show_breakpoints"].value_or(false); iris->show_imgui_demo = debugger["show_imgui_demo"].value_or(false); iris->skip_fmv = debugger["skip_fmv"].value_or(false); + iris->timescale = debugger["timescale"].value_or(8); toml::array* recents = tbl["recents"]["array"].as_array(); @@ -123,6 +128,8 @@ int parse_toml_settings(iris::instance* iris) { renderer_set_integer_scaling(iris->ctx, iris->integer_scaling); renderer_set_scale(iris->ctx, iris->scale); + ps2_set_timescale(iris->ps2, iris->timescale); + ee_set_fmv_skip(iris->ps2->ee, iris->skip_fmv); return 0; @@ -282,7 +289,9 @@ void close_settings(iris::instance* iris) { { "show_breakpoints", iris->show_breakpoints }, { "show_threads", iris->show_threads }, { "show_imgui_demo", iris->show_imgui_demo }, - { "skip_fmv", iris->skip_fmv } + { "show_overlay", iris->show_overlay }, + { "skip_fmv", iris->skip_fmv }, + { "timescale", iris->timescale } } }, { "display", toml::table { { "scale", iris->scale }, @@ -290,7 +299,9 @@ void close_settings(iris::instance* iris) { { "integer_scaling", iris->integer_scaling }, { "fullscreen", iris->fullscreen }, { "bilinear", iris->bilinear }, - { "renderer", iris->renderer_backend } + { "renderer", iris->renderer_backend }, + { "window_width", iris->window_width }, + { "window_height", iris->window_height } } }, { "audio", toml::table { { "mute", iris->mute }, diff --git a/frontend/ui/menubar.cpp b/frontend/ui/menubar.cpp index f309005..346f124 100644 --- a/frontend/ui/menubar.cpp +++ b/frontend/ui/menubar.cpp @@ -234,7 +234,7 @@ void show_main_menubar(iris::instance* iris) { ImGui::EndMenu(); } - if (BeginMenu("Scale")) { + if (BeginMenu(ICON_MS_CROP " Scale")) { for (int i = 2; i <= 6; i++) { char buf[16]; snprintf(buf, 16, "%.1fx", (float)i * 0.5f); @@ -248,7 +248,7 @@ void show_main_menubar(iris::instance* iris) { ImGui::EndMenu(); } - if (BeginMenu("Aspect mode")) { + if (BeginMenu(ICON_MS_ASPECT_RATIO " Aspect mode")) { for (int i = 0; i < 7; i++) { if (Selectable(aspect_mode_names[i], iris->aspect_mode == i)) { iris->aspect_mode = i; @@ -260,7 +260,7 @@ void show_main_menubar(iris::instance* iris) { ImGui::EndMenu(); } - if (BeginMenu("Scaling filter")) { + if (BeginMenu(ICON_MS_FILTER " Scaling filter")) { if (Selectable("Nearest", !iris->bilinear)) { iris->bilinear = false; @@ -276,11 +276,43 @@ void show_main_menubar(iris::instance* iris) { ImGui::EndMenu(); } - if (MenuItem("Integer scaling", nullptr, &iris->integer_scaling)) { + if (BeginMenu(ICON_MS_ASPECT_RATIO " Window size")) { + const char* sizes[] = { + "640x480", + "800x600", + "960x720", + "1024x768", + "1280x720", + "1280x800" + }; + + int widths[] = { + 640, 800, 960, 1024, 1280, 1280 + }; + + int heights[] = { + 480, 600, 720, 768, 720, 800 + }; + + for (int i = 0; i < 6; i++) { + bool selected = iris->window_width == widths[i] && iris->window_height == heights[i]; + + if (MenuItem(sizes[i], nullptr, selected)) { + iris->window_width = widths[i]; + iris->window_height = heights[i]; + + SDL_SetWindowSize(iris->window, iris->window_width, iris->window_height); + } + } + + ImGui::EndMenu(); + } + + if (MenuItem(ICON_MS_SPEED_2X " Integer scaling", nullptr, &iris->integer_scaling)) { renderer_set_integer_scaling(iris->ctx, iris->integer_scaling); } - if (MenuItem("Fullscreen", "F11", &iris->fullscreen)) { + if (MenuItem(ICON_MS_FULLSCREEN " Fullscreen", "F11", &iris->fullscreen)) { SDL_SetWindowFullscreen(iris->window, iris->fullscreen); } @@ -385,9 +417,24 @@ void show_main_menubar(iris::instance* iris) { if (MenuItem(ICON_MS_MEMORY " Memory viewer", NULL, &iris->show_memory_viewer)); if (MenuItem(ICON_MS_VIEW_IN_AR " VU disassembler", NULL, &iris->show_vu_disassembler)); if (MenuItem(ICON_MS_GAMEPAD " DualShock debugger", NULL, &iris->show_pad_debugger)); + if (MenuItem(ICON_MS_BUG_REPORT " Performance overlay", NULL, &iris->show_overlay)); Separator(); + if (BeginMenu(ICON_MS_MORE_TIME " Timescale")) { + for (int i = 0; i < 9; i++) { + char buf[16]; snprintf(buf, 16, "%dx", 1 << i); + + if (Selectable(buf, iris->timescale == (1 << i))) { + iris->timescale = (1 << i); + + ps2_set_timescale(iris->ps2, iris->timescale); + } + } + + ImGui::EndMenu(); + } + if (MenuItem(ICON_MS_SKIP_NEXT " Skip FMVs", NULL, &iris->skip_fmv)) { printf("Skip FMVs: %d\n", iris->skip_fmv); ee_set_fmv_skip(iris->ps2->ee, iris->skip_fmv); @@ -413,6 +460,7 @@ void show_main_menubar(iris::instance* iris) { iris->show_symbols = false; iris->show_threads = false; iris->show_breakpoints = false; + iris->show_overlay = false; } ImGui::EndMenu(); diff --git a/frontend/ui/modules.cpp b/frontend/ui/modules.cpp index 3c4f106..0427b70 100644 --- a/frontend/ui/modules.cpp +++ b/frontend/ui/modules.cpp @@ -61,7 +61,7 @@ static inline void show_modules_table(iris::instance* iris) { // bss section TableSetColumnIndex(3); addr += mod->data_size; - Text("0x%08x", iop->module_list[i].text_addr); + Text("0x%08x", addr); PopFont(); } diff --git a/frontend/ui/overlay.cpp b/frontend/ui/overlay.cpp new file mode 100644 index 0000000..8385a80 --- /dev/null +++ b/frontend/ui/overlay.cpp @@ -0,0 +1,103 @@ +#include +#include + +#include "iris.hpp" + +#include "res/IconsMaterialSymbols.h" + +#include "implot.h" + +#define MAX_SAMPLES 100 + +namespace iris { + +std::vector fps_history = { 0 }; +std::vector fps_history_avg = { 0 }; + +ImVec2 pos = ImVec2(10, 10); +const ImVec2 padding = ImVec2(5, 5); +const ImVec2 size = ImVec2(250, 100); +const float opacity = 0.75f; + +float max = 0.0; + +void update_overlay(iris::instance* iris) { + // if (fps_history.size() == MAX_SAMPLES) { + // if (fps_history.front() >= max) { + // max = 0.0; + + // for (int i = 1; i < MAX_SAMPLES; i++) { + // if (fps_history[i] > max) { + // max = fps_history[i]; + // } + // } + // } + + // fps_history.pop_front(); + // } + + float sample = 1.0 / ImGui::GetIO().DeltaTime; + + if (!iris->pause) { + if (fps_history.size() == MAX_SAMPLES) + fps_history.erase(fps_history.begin()); + + fps_history.push_back(sample); + + if (fps_history_avg.size() == MAX_SAMPLES) + fps_history_avg.erase(fps_history_avg.begin()); + + fps_history_avg.push_back(std::roundf(ImGui::GetIO().Framerate)); + } +} + +void show_overlay(iris::instance* iris) { + using namespace ImGui; + using namespace ImPlot; + + SetNextWindowBgAlpha(0.5f); + SetNextWindowPos(ImVec2(10.0, 10.0 + iris->menubar_height), ImGuiCond_Always); + + if (Begin("Overlay", nullptr, + ImGuiWindowFlags_NoDecoration | + ImGuiWindowFlags_NoMove | + ImGuiWindowFlags_NoSavedSettings | + ImGuiWindowFlags_NoFocusOnAppearing | + ImGuiWindowFlags_NoNav | + ImGuiWindowFlags_NoDocking)) { + update_overlay(iris); + + ImPlotFlags flags = + ImPlotFlags_NoTitle | + ImPlotFlags_NoLegend | + ImPlotFlags_NoMouseText | + ImPlotFlags_NoBoxSelect | + ImPlotFlags_NoFrame | + ImPlotFlags_NoMenus | + ImPlotFlags_CanvasOnly | + ImPlotFlags_NoInputs; + + ImPlotAxisFlags axis_flags = + ImPlotAxisFlags_NoTickLabels | + ImPlotAxisFlags_NoGridLines; + + if (BeginPlot("##overlay_plot", ImVec2(0, 0), flags)) { + SetupAxes(nullptr, nullptr, axis_flags, axis_flags); + SetupAxesLimits(0, (double)MAX_SAMPLES - 1, 0, 60, ImGuiCond_Always); + PlotLine("FPS", fps_history.data(), (int)fps_history.size()); + + EndPlot(); + } + + renderer_stats* stats = renderer_get_debug_stats(iris->ctx); + + PushFont(iris->font_black); + Text("%d fps", (int)std::roundf(1.0 / ImGui::GetIO().DeltaTime)); + PopFont(); + Text("Primitives: %d", stats->primitives); + Text("Texture uploads: %d", stats->texture_uploads); + Text("Texture blits: %d", stats->texture_blits); + } End(); +} + +} \ No newline at end of file diff --git a/frontend/ui/statusbar.cpp b/frontend/ui/statusbar.cpp index a354aaa..382092e 100644 --- a/frontend/ui/statusbar.cpp +++ b/frontend/ui/statusbar.cpp @@ -77,8 +77,11 @@ void show_status_bar(iris::instance* iris) { vp_w, vp_h, mode == 3 ? "Interlaced" : "Progressive", get_format_bpp(disp_fmt), - iris->fps * 2.0f + GetIO().Framerate ); + + // iris->avg_frames++; + // iris->avg_fps += iris->fps; } else { Text(ICON_MS_MONITOR " %s | No image", renderer_get_name(iris->ctx) diff --git a/implot b/implot new file mode 160000 index 0000000..3da8bd3 --- /dev/null +++ b/implot @@ -0,0 +1 @@ +Subproject commit 3da8bd34299965d3b0ab124df743fe3e076fa222 diff --git a/main.cpp b/main.cpp index 9547500..a1f894c 100644 --- a/main.cpp +++ b/main.cpp @@ -15,6 +15,7 @@ #include "imgui.h" #include "imgui_impl_sdl3.h" #include "imgui_impl_sdlgpu3.h" +#include "implot.h" // SDL3 includes #include @@ -29,6 +30,7 @@ #include "incbin.h" INCBIN(roboto, "../res/Roboto-Regular.ttf"); +INCBIN(roboto_black, "../res/Roboto-Black.ttf"); INCBIN(symbols, "../res/MaterialSymbolsRounded.ttf"); INCBIN(firacode, "../res/FiraCode-Regular.ttf"); INCBIN(ps1_memory_card_icon, "../res/ps1_mcd.png"); @@ -196,9 +198,10 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char** argv) { /* SDL_OpenAudioDeviceStream starts the device paused. You have to tell it to start! */ SDL_ResumeAudioStreamDevice(iris->stream); - // Setup Dear ImGui context + // Setup Dear ImGui/ImPlot context IMGUI_CHECKVERSION(); ImGui::CreateContext(); + ImPlot::CreateContext(); ImGuiIO& io = ImGui::GetIO(); (void)io; io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls @@ -231,6 +234,7 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char** argv) { iris->font_body = io.Fonts->AddFontFromMemoryTTF((void*)g_roboto_data, g_roboto_size, 16.0F, &config_no_own); iris->font_icons = io.Fonts->AddFontFromMemoryTTF((void*)g_symbols_data, g_symbols_size, 20.0F, &config, g_icon_range); iris->font_icons_big = io.Fonts->AddFontFromMemoryTTF((void*)g_symbols_data, g_symbols_size, 50.0F, &config_no_own, g_icon_range); + iris->font_black = io.Fonts->AddFontFromMemoryTTF((void*)g_roboto_black_data, g_roboto_black_size, 30.0F, &config_no_own); IM_ASSERT(iris->font_small_code != nullptr); IM_ASSERT(iris->font_code != nullptr); @@ -239,6 +243,7 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char** argv) { IM_ASSERT(iris->font_body != nullptr); IM_ASSERT(iris->font_icons != nullptr); IM_ASSERT(iris->font_icons_big != nullptr); + IM_ASSERT(iris->font_black != nullptr); io.FontDefault = iris->font_body; @@ -349,6 +354,22 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char** argv) { colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.35f); + ImPlotStyle& pstyle = ImPlot::GetStyle(); + + pstyle.MinorGridSize = ImVec2(0.0f, 0.0f); + pstyle.MajorGridSize = ImVec2(0.0f, 0.0f); + pstyle.MinorTickLen = ImVec2(0.0f, 0.0f); + pstyle.MajorTickLen = ImVec2(0.0f, 0.0f); + pstyle.PlotDefaultSize = ImVec2(250.0f, 150.0f); + pstyle.PlotPadding = ImVec2(0.0f, 0.0f); + pstyle.LegendPadding = ImVec2(0.0f, 0.0f); + pstyle.LegendInnerPadding = ImVec2(0.0f, 0.0f); + pstyle.LineWeight = 2.0f; + + pstyle.Colors[ImPlotCol_Line] = ImVec4(0.0f, 1.0f, 0.2f, 1.0f); + pstyle.Colors[ImPlotCol_FrameBg] = ImVec4(0.0f, 0.0f, 0.0f, 0.0f); + pstyle.Colors[ImPlotCol_PlotBg] = ImVec4(0.0f, 0.0f, 0.0f, 0.0f); + iris->open = true; // Initialize our emulator state @@ -424,6 +445,8 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char** argv) { // Initialize appstate *appstate = iris; + SDL_SetWindowSize(iris->window, iris->window_width, iris->window_height); + return SDL_APP_CONTINUE; } @@ -504,6 +527,14 @@ SDL_AppResult SDL_AppIterate(void* appstate) { } } + float p = ((float)iris->ps2->ee->eenull_counter / (float)(4920115)) * 100.0f; + + // printf("ee: Time spent idling: %ld cycles (%.2f%%) INTC reads: %d CSR reads: %d (%.1f fps)\n", iris->ps2->ee->eenull_counter, p, iris->ps2->ee->intc_reads, iris->ps2->ee->csr_reads, 1.0f / ImGui::GetIO().DeltaTime); + + iris->ps2->ee->eenull_counter = 0; + iris->ps2->ee->intc_reads = 0; + iris->ps2->ee->csr_reads = 0; + return SDL_APP_CONTINUE; } @@ -572,6 +603,7 @@ void SDL_AppQuit(void* appstate, SDL_AppResult result) { SDL_WaitForGPUIdle(iris->device); ImGui_ImplSDL3_Shutdown(); ImGui_ImplSDLGPU3_Shutdown(); + ImPlot::DestroyContext(); ImGui::DestroyContext(); // Release resources diff --git a/res/Roboto-Black.ttf b/res/Roboto-Black.ttf new file mode 100644 index 0000000..86ec2b2 Binary files /dev/null and b/res/Roboto-Black.ttf differ diff --git a/src/ee/bus.c b/src/ee/bus.c index 5ac75da..f6afd15 100644 --- a/src/ee/bus.c +++ b/src/ee/bus.c @@ -159,8 +159,11 @@ uint64_t ee_bus_read8(void* udata, uint32_t addr) { MAP_REG_READ(8, 0x1F402004, 0x1F402018, cdvd, cdvd); MAP_MEM_READ(8, 0x1E000000, 0x1E3FFFFF, bios, rom1); MAP_MEM_READ(8, 0x1E400000, 0x1E7FFFFF, bios, rom2); + MAP_REG_READ(64, 0x12000000, 0x12001FFF, gs, gs); // Reuse 64-bit function + + if ((addr >> 16) == 0x1f80) return 0; - printf("bus: Unhandled 8-bit read from physical address 0x%08x\n", addr); + // printf("bus: Unhandled 8-bit read from physical address 0x%08x\n", addr); // *(int*)0 = 0; return 0; } @@ -322,7 +325,7 @@ uint128_t ee_bus_read128(void* udata, uint32_t addr) { printf("bus: Unhandled 128-bit read from physical address 0x%08x\n", addr); // exit(1); - *(int*)0 = 0; + // *(int*)0 = 0; return (uint128_t){ .u64[0] = 0, .u64[1] = 0 }; } @@ -352,7 +355,7 @@ void ee_bus_write8(void* udata, uint32_t addr, uint64_t data) { if (addr == 0x1000f180) { bus->kputchar(bus->kputchar_udata, data & 0xff); return; } - printf("bus: Unhandled 8-bit write to physical address 0x%08x (0x%02lx)\n", addr, data); + // printf("bus: Unhandled 8-bit write to physical address 0x%08x (0x%02lx)\n", addr, data); } void ee_bus_write16(void* udata, uint32_t addr, uint64_t data) { @@ -384,7 +387,7 @@ void ee_bus_write16(void* udata, uint32_t addr, uint64_t data) { case 0x1f801472: return; } - printf("bus: Unhandled 16-bit write to physical address 0x%08x (0x%04lx)\n", addr, data); + // printf("bus: Unhandled 16-bit write to physical address 0x%08x (0x%04lx)\n", addr, data); } void ee_bus_write32(void* udata, uint32_t addr, uint64_t data) { @@ -473,6 +476,7 @@ void ee_bus_write64(void* udata, uint32_t addr, uint64_t data) { MAP_REG_WRITE(64, 0x10007000, 0x1000701F, ipu, ipu); MAP_REG_WRITE(32, 0x10008000, 0x1000EFFF, dmac, dmac); MAP_REG_WRITE(32, 0x1000F520, 0x1000F5FF, dmac, dmac); + MAP_REG_WRITE(32, 0x10000000, 0x10001FFF, ee_timers, timers); // Reuse 32-bit function MAP_MEM_WRITE(64, 0x11000000, 0x11007FFF, vu, vu0); MAP_MEM_WRITE(64, 0x11008000, 0x1100FFFF, vu, vu1); MAP_MEM_WRITE(64, 0x1000F000, 0x1000F01F, intc, intc); diff --git a/src/ee/dmac.c b/src/ee/dmac.c index 600ac36..d602547 100644 --- a/src/ee/dmac.c +++ b/src/ee/dmac.c @@ -7,8 +7,8 @@ #define printf(fmt, ...)(0) -static inline uint128_t dmac_read_qword(struct ps2_dmac* dmac, uint32_t addr, int mem) { - int spr = mem || (addr & 0x80000000); +static inline uint128_t dmac_read_qword(struct ps2_dmac* dmac, uint32_t addr) { + int spr = addr & 0x80000000; if (!spr) return ee_bus_read128(dmac->bus, addr & 0xfffffff0); @@ -131,19 +131,18 @@ static inline void dmac_process_source_tag(struct ps2_dmac* dmac, struct dmac_ch c->tag.id = TAG_ID(tag); c->tag.irq = TAG_IRQ(tag); c->tag.addr = TAG_ADDR(tag); - c->tag.mem = TAG_MEM(tag); c->tag.data = TAG_DATA(tag); - if (dmac->mfifo_drain) - printf("ee: dmac tag %016lx %016lx qwc=%08x id=%d irq=%d addr=%08x mem=%d data=%016lx\n", - tag.u64[1], tag.u64[0], - c->tag.qwc, - c->tag.id, - c->tag.irq, - c->tag.addr, - c->tag.mem, - c->tag.data - ); + // if (dmac->mfifo_drain) + // printf("ee: dmac tag %016lx %016lx qwc=%08x id=%d irq=%d addr=%08x mem=%d data=%016lx\n", + // tag.u64[1], tag.u64[0], + // c->tag.qwc, + // c->tag.id, + // c->tag.irq, + // c->tag.addr, + // c->tag.mem, + // c->tag.data + // ); c->tag.end = 0; c->qwc = c->tag.qwc; @@ -227,7 +226,6 @@ static inline void dmac_process_dest_tag(struct ps2_dmac* dmac, struct dmac_chan c->tag.id = TAG_ID(tag); c->tag.irq = TAG_IRQ(tag); c->tag.addr = TAG_ADDR(tag); - c->tag.mem = TAG_MEM(tag); c->tag.data = TAG_DATA(tag); c->qwc = c->tag.qwc; @@ -278,7 +276,7 @@ void dmac_handle_vif0_transfer(struct ps2_dmac* dmac) { int mode = (dmac->vif0.chcr >> 2) & 3; for (int i = 0; i < dmac->vif0.qwc; i++) { - uint128_t q = dmac_read_qword(dmac, dmac->vif0.madr, 0); + uint128_t q = dmac_read_qword(dmac, dmac->vif0.madr); // VIF0 FIFO address ee_bus_write128(dmac->bus, 0x10004000, q); @@ -297,7 +295,7 @@ void dmac_handle_vif0_transfer(struct ps2_dmac* dmac) { // Chain mode do { - uint128_t tag = dmac_read_qword(dmac, dmac->vif0.tadr, 0); + uint128_t tag = dmac_read_qword(dmac, dmac->vif0.tadr); dmac_process_source_tag(dmac, &dmac->vif0, tag); @@ -316,7 +314,7 @@ void dmac_handle_vif0_transfer(struct ps2_dmac* dmac) { } for (int i = 0; i < dmac->vif0.qwc; i++) { - uint128_t q = dmac_read_qword(dmac, dmac->vif0.madr, dmac->vif0.tag.mem); + uint128_t q = dmac_read_qword(dmac, dmac->vif0.madr); // printf("ee: Sending %016lx%016lx from %08x to VIF0 FIFO\n", // q.u64[1], q.u64[0], @@ -354,11 +352,11 @@ void mfifo_write_qword(struct ps2_dmac* dmac, uint128_t q) { struct dmac_channel* c = dmac->mfifo_drain; if (c->qwc) { - uint128_t q = dmac_read_qword(dmac, c->madr, c->tag.mem); + uint128_t q = dmac_read_qword(dmac, c->madr); if (c == &dmac->vif1) { // VIF1 FIFO - ee_bus_write128(dmac->bus, 0x10007010, q); + ee_bus_write128(dmac->bus, 0x10005000, q); } else { // GIF FIFO ee_bus_write128(dmac->bus, 0x10006000, q); @@ -367,35 +365,35 @@ void mfifo_write_qword(struct ps2_dmac* dmac, uint128_t q) { c->madr += 16; c->qwc--; - printf("dmac: mfifo channel qwc=%d\n", c->qwc); + // printf("dmac: mfifo channel qwc=%d\n", c->qwc); - if (channel_is_done(c)) { - printf("dmac: mfifo channel done end=%d tte-irq=%d\n", c->tag.end, c->tag.irq && (c->chcr & 0x80)); - dmac_set_irq(dmac, c == &dmac->vif1 ? DMAC_VIF1 : DMAC_GIF); + if (c->qwc == 0) { + if (channel_is_done(c)) { + printf("dmac: mfifo channel done end=%d tte-irq=%d\n", c->tag.end, c->tag.irq && (c->chcr & 0x80)); + dmac_set_irq(dmac, c == &dmac->vif1 ? DMAC_VIF1 : DMAC_GIF); - c->chcr &= ~0x100; - c->qwc = 0; + c->chcr &= ~0x100; - return; + return; + } + + if (c->tag.id == 1) { + c->tadr = dmac->rbor | (c->madr & dmac->rbsr); + } } return; } - if (channel_is_done(c)) { - printf("dmac: mfifo channel done end=%d tte-irq=%d\n", c->tag.end, c->tag.irq && (c->chcr & 0x80)); - dmac_set_irq(dmac, c == &dmac->vif1 ? DMAC_VIF1 : DMAC_GIF); + uint128_t tag = dmac_read_qword(dmac, c->tadr); - c->chcr &= ~0x100; - c->qwc = 0; + dmac_process_source_tag(dmac, c, tag); - return; + if ((c->chcr >> 6) & 1) { + ee_bus_write32(dmac->bus, 0x10005000, c->tag.data & 0xffffffff); + ee_bus_write32(dmac->bus, 0x10005000, c->tag.data >> 32); } - uint128_t tag = dmac_read_qword(dmac, c->tadr, 0); - - dmac_process_source_tag(dmac, c, tag); - c->tadr = dmac->rbor | (c->tadr & dmac->rbsr); switch (c->tag.id) { @@ -408,34 +406,42 @@ void mfifo_write_qword(struct ps2_dmac* dmac, uint128_t q) { } break; } - printf("dmac: tadr=%08x madr=%08x\n", c->tadr, c->madr); + printf("dmac: tadr=%08x madr=%08x qwc=%d tagid=%d end=%d\n", c->tadr, c->madr, c->qwc, c->tag.id, c->tag.end); + + if (c->qwc == 0) { + if (channel_is_done(c)) { + printf("dmac: mfifo channel done end=%d tte-irq=%d\n", c->tag.end, c->tag.irq && (c->chcr & 0x80)); + dmac_set_irq(dmac, c == &dmac->vif1 ? DMAC_VIF1 : DMAC_GIF); + + c->chcr &= ~0x100; + + return; + } + } if (c->tadr == dmac->spr_from.madr) { - printf("dmac: MFIFO empty\n"); + fprintf(stdout, "dmac: MFIFO empty\n"); - exit(1); + dmac_set_irq(dmac, DMAC_MEIS); } } void dmac_handle_vif1_transfer(struct ps2_dmac* dmac) { - printf("dmac: VIF1 DMA dir=%d mode=%d tte=%d tie=%d qwc=%d madr=%08x tadr=%08x rbor=%08x rbsr=%08x sprfrom.madr=%08x\n", - dmac->vif1.chcr & 1, - (dmac->vif1.chcr >> 2) & 3, - (dmac->vif1.chcr >> 6) & 1, - (dmac->vif1.chcr >> 7) & 1, - dmac->vif1.qwc, - dmac->vif1.madr, - dmac->vif1.tadr, - dmac->rbor, - dmac->rbsr, - dmac->spr_from.madr - ); + // fprintf(stdout, "dmac: VIF1 DMA dir=%d mode=%d tte=%d tie=%d qwc=%d madr=%08x tadr=%08x end=%d\n", + // dmac->vif1.chcr & 1, + // (dmac->vif1.chcr >> 2) & 3, + // (dmac->vif1.chcr >> 6) & 1, + // (dmac->vif1.chcr >> 7) & 1, + // dmac->vif1.qwc, + // dmac->vif1.madr, + // dmac->vif1.tadr, + // dmac->vif1.tag.end + // ); int mfifo_drain = (dmac->ctrl >> 2) & 3; - if (mfifo_drain == 2) { + if (mfifo_drain == 2) return; - } int tte = (dmac->vif1.chcr >> 6) & 1; int mode = (dmac->vif1.chcr >> 2) & 3; @@ -466,7 +472,7 @@ void dmac_handle_vif1_transfer(struct ps2_dmac* dmac) { } for (int i = 0; i < dmac->vif1.qwc; i++) { - uint128_t q = dmac_read_qword(dmac, dmac->vif1.madr, 0); + uint128_t q = dmac_read_qword(dmac, dmac->vif1.madr); // VIF1 FIFO address ee_bus_write32(dmac->bus, 0x10005000, q.u32[0]); @@ -485,26 +491,22 @@ void dmac_handle_vif1_transfer(struct ps2_dmac* dmac) { return; } - int id = (dmac->vif1.chcr >> 28) & 7; - - if (mode == 1 && (id == 0 || id == 7) && dmac->vif1.qwc) { - sched_schedule(dmac->sched, event); - - return; - } - // Chain mode do { - uint128_t tag = dmac_read_qword(dmac, dmac->vif1.tadr, 0); + uint128_t tag = dmac_read_qword(dmac, dmac->vif1.tadr); dmac_process_source_tag(dmac, &dmac->vif1, tag); - // printf("ee: vif1 tag qwc=%08x madr=%08x tadr=%08x id=%d addr=%08x\n", + // fprintf(stdout, "ee: vif1 tag qwc=%08x madr=%08x tadr=%08x id=%d addr=%08x data=%08x %08x tte=%d mem=%d\n", // dmac->vif1.tag.qwc, // dmac->vif1.madr, // dmac->vif1.tadr, // dmac->vif1.tag.id, - // dmac->vif1.tag.addr + // dmac->vif1.tag.addr, + // dmac->vif1.tag.data & 0xffffffff, + // dmac->vif1.tag.data >> 32, + // (dmac->vif1.chcr >> 6) & 1, + // dmac->vif1.tag.mem // ); // CHCR.TTE: Transfer tag DATA field @@ -514,12 +516,7 @@ void dmac_handle_vif1_transfer(struct ps2_dmac* dmac) { } for (int i = 0; i < dmac->vif1.qwc; i++) { - uint128_t q = dmac_read_qword(dmac, dmac->vif1.madr, dmac->vif1.tag.mem); - - // printf("ee: Sending %016lx%016lx from %08x to VIF1 FIFO\n", - // q.u64[1], q.u64[0], - // dmac->vif1.madr - // ); + uint128_t q = dmac_read_qword(dmac, dmac->vif1.madr); ee_bus_write32(dmac->bus, 0x10005000, q.u32[0]); ee_bus_write32(dmac->bus, 0x10005000, q.u32[1]); @@ -549,6 +546,9 @@ void dmac_send_gif_irq(void* udata, int overshoot) { void dmac_handle_gif_transfer(struct ps2_dmac* dmac) { struct sched_event event; + assert(((dmac->gif.chcr >> 6) & 1) == 0); + assert(dmac->gif.qwc == 0); + int mode = (dmac->gif.chcr >> 2) & 3; event.name = "GIF DMA IRQ"; @@ -558,18 +558,18 @@ void dmac_handle_gif_transfer(struct ps2_dmac* dmac) { sched_schedule(dmac->sched, event); - printf("dmac: GIF DMA dir=%d mode=%d tte=%d tie=%d qwc=%d madr=%08x tadr=%08x rbor=%08x rbsr=%08x sprfrom.madr=%08x\n", - dmac->gif.chcr & 1, - (dmac->gif.chcr >> 2) & 3, - (dmac->gif.chcr >> 6) & 1, - (dmac->gif.chcr >> 7) & 1, - dmac->gif.qwc, - dmac->gif.madr, - dmac->gif.tadr, - dmac->rbor, - dmac->rbsr, - dmac->spr_from.madr - ); + // printf("dmac: GIF DMA dir=%d mode=%d tte=%d tie=%d qwc=%d madr=%08x tadr=%08x rbor=%08x rbsr=%08x sprfrom.madr=%08x\n", + // dmac->gif.chcr & 1, + // (dmac->gif.chcr >> 2) & 3, + // (dmac->gif.chcr >> 6) & 1, + // (dmac->gif.chcr >> 7) & 1, + // dmac->gif.qwc, + // dmac->gif.madr, + // dmac->gif.tadr, + // dmac->rbor, + // dmac->rbsr, + // dmac->spr_from.madr + // ); int mfifo_drain = (dmac->ctrl >> 2) & 3; @@ -587,7 +587,7 @@ void dmac_handle_gif_transfer(struct ps2_dmac* dmac) { // ); for (int i = 0; i < dmac->gif.qwc; i++) { - uint128_t q = dmac_read_qword(dmac, dmac->gif.madr, 0); + uint128_t q = dmac_read_qword(dmac, dmac->gif.madr); // fprintf(file, "ee: Sending %016lx%016lx from %08x to GIF FIFO (burst)\n", // q.u64[1], q.u64[0], @@ -612,14 +612,14 @@ void dmac_handle_gif_transfer(struct ps2_dmac* dmac) { // Chain mode do { - uint128_t tag = dmac_read_qword(dmac, dmac->gif.tadr, 0); + uint128_t tag = dmac_read_qword(dmac, dmac->gif.tadr); dmac_process_source_tag(dmac, &dmac->gif, tag); // printf("ee: gif tag qwc=%08x madr=%08x tadr=%08x mem=%d\n", dmac->gif.qwc, dmac->gif.madr, dmac->gif.tadr, dmac->gif.tag.mem); for (int i = 0; i < dmac->gif.qwc; i++) { - uint128_t q = dmac_read_qword(dmac, dmac->gif.madr, dmac->gif.tag.mem); + uint128_t q = dmac_read_qword(dmac, dmac->gif.madr); // fprintf(file, "ee: Sending %016lx%016lx from %08x to GIF FIFO (chain)\n", // q.u64[1], q.u64[0], @@ -696,7 +696,7 @@ int dmac_transfer_ipu_to_qword(struct ps2_dmac* dmac) { } if (dmac->ipu_to.qwc) { - uint128_t q = dmac_read_qword(dmac, dmac->ipu_to.madr, dmac->ipu_to.tag.mem); + uint128_t q = dmac_read_qword(dmac, dmac->ipu_to.madr); ee_bus_write128(dmac->bus, 0x10007010, q); @@ -715,7 +715,13 @@ int dmac_transfer_ipu_to_qword(struct ps2_dmac* dmac) { return 0; } - uint128_t tag = dmac_read_qword(dmac, dmac->ipu_to.tadr, 0); + if (dmac->ipu_to.tag.id == 1) { + dmac->ipu_to.tadr = dmac->ipu_to.madr; + printf("dmac: ipu_to tag id=1, setting tadr to %08x\n", dmac->ipu_to.tadr); + exit(1); + } + + uint128_t tag = dmac_read_qword(dmac, dmac->ipu_to.tadr); dmac_process_source_tag(dmac, &dmac->ipu_to, tag); @@ -764,6 +770,15 @@ void dmac_handle_sif0_transfer(struct ps2_dmac* dmac) { if (!(dmac->sif0.chcr & 0x100)) { return; } + // fprintf(stdout, "dmac: sif0 start data=%08x dir=%d mod=%d tte=%d madr=%08x qwc=%08x tadr=%08x\n", + // dmac->sif0.chcr, + // dmac->sif0.chcr & 1, + // (dmac->sif0.chcr >> 2) & 3, + // !!(dmac->sif0.chcr & 0x40), + // dmac->sif0.madr, + // dmac->sif0.qwc, + // dmac->sif0.tadr + // ); while (!ps2_sif0_is_empty(dmac->sif)) { uint128_t tag = ps2_sif0_read(dmac->sif); @@ -815,7 +830,7 @@ void dmac_handle_sif0_transfer(struct ps2_dmac* dmac) { // printf("ee: Writing %016lx %016lx to %08x\n", q.u64[1], q.u64[0], dmac->sif0.madr); - dmac_write_qword(dmac, dmac->sif0.madr, dmac->sif0.tag.mem, q); + dmac_write_qword(dmac, dmac->sif0.madr, 0, q); dmac->sif0.madr += 16; } @@ -843,6 +858,7 @@ void dmac_handle_sif0_transfer(struct ps2_dmac* dmac) { } void dmac_handle_sif1_transfer(struct ps2_dmac* dmac) { assert(!dmac->sif1.qwc); + assert(((dmac->sif1.chcr >> 2) & 3) == 1); // This should be ok? // if (!ps2_sif_fifo_is_empty(dmac->sif)) { @@ -850,7 +866,7 @@ void dmac_handle_sif1_transfer(struct ps2_dmac* dmac) { // } do { - uint128_t tag = dmac_read_qword(dmac, dmac->sif1.tadr, 0); + uint128_t tag = dmac_read_qword(dmac, dmac->sif1.tadr); dmac_process_source_tag(dmac, &dmac->sif1, tag); @@ -867,7 +883,7 @@ void dmac_handle_sif1_transfer(struct ps2_dmac* dmac) { // printf("ee: SIF1 tag madr=%08x\n", dmac->sif1.madr); for (int i = 0; i < dmac->sif1.qwc; i++) { - uint128_t q = dmac_read_qword(dmac, dmac->sif1.madr, dmac->sif1.tag.mem); + uint128_t q = dmac_read_qword(dmac, dmac->sif1.madr); // printf("%08x: ", dmac->sif1.madr); @@ -887,6 +903,14 @@ void dmac_handle_sif1_transfer(struct ps2_dmac* dmac) { dmac->sif1.madr += 16; } + + if (dmac->sif1.tag.id == 1) { + dmac->sif1.tadr = dmac->sif1.madr; + + printf("dmac: SIF1 tag id=1, setting TADR to MADR=%08x\n", dmac->sif1.madr); + + exit(1); + } } while (!channel_is_done(&dmac->sif1)); iop_dma_handle_sif1_transfer(dmac->iop_dma); @@ -928,18 +952,20 @@ void dmac_handle_spr_from_transfer(struct ps2_dmac* dmac) { dmac->spr_from.chcr &= ~0x100; - printf("dmac: spr_from start data=%08x dir=%d mod=%d tte=%d madr=%08x qwc=%08x tadr=%08x sadr=%08x rbor=%08x rbsr=%08x\n", - dmac->spr_from.chcr, - dmac->spr_from.chcr & 1, - (dmac->spr_from.chcr >> 2) & 3, - !!(dmac->spr_from.chcr & 0x40), - dmac->spr_from.madr, - dmac->spr_from.qwc, - dmac->spr_from.tadr, - dmac->spr_from.sadr, - dmac->rbor, - dmac->rbsr - ); + // fprintf(stdout, "dmac: spr_from start data=%08x dir=%d mod=%d tte=%d madr=%08x qwc=%08x tadr=%08x sadr=%08x rbor=%08x rbsr=%08x\n", + // dmac->spr_from.chcr, + // dmac->spr_from.chcr & 1, + // (dmac->spr_from.chcr >> 2) & 3, + // !!(dmac->spr_from.chcr & 0x40), + // dmac->spr_from.madr, + // dmac->spr_from.qwc, + // dmac->spr_from.tadr, + // dmac->spr_from.sadr, + // dmac->rbor, + // dmac->rbsr + // ); + + // exit(1); int mode = (dmac->spr_from.chcr >> 2) & 3; @@ -949,7 +975,7 @@ void dmac_handle_spr_from_transfer(struct ps2_dmac* dmac) { dmac->spr_from.madr = dmac->rbor | (dmac->spr_from.madr & dmac->rbsr); for (int i = 0; i < dmac->spr_from.qwc; i++) { - uint128_t q = dmac_read_qword(dmac, dmac->spr_from.sadr, 1); + uint128_t q = ps2_ram_read128(dmac->spr, dmac->spr_from.sadr & 0x3ff0); ee_bus_write128(dmac->bus, dmac->spr_from.madr, q); @@ -972,7 +998,7 @@ void dmac_handle_spr_from_transfer(struct ps2_dmac* dmac) { } for (int i = 0; i < dmac->spr_from.qwc; i++) { - uint128_t q = dmac_read_qword(dmac, dmac->spr_from.sadr, 1); + uint128_t q = ps2_ram_read128(dmac->spr, dmac->spr_from.sadr & 0x3ff0); ee_bus_write128(dmac->bus, dmac->spr_from.madr, q); @@ -988,9 +1014,8 @@ void dmac_handle_spr_from_transfer(struct ps2_dmac* dmac) { } // Chain mode - int loop = 0; do { - uint128_t tag = dmac_read_qword(dmac, dmac->spr_from.sadr, 1); + uint128_t tag = ps2_ram_read128(dmac->spr, dmac->spr_from.sadr & 0x3ff0); dmac->spr_from.sadr += 0x10; dmac->spr_from.sadr &= 0x3ff0; @@ -1016,7 +1041,7 @@ void dmac_handle_spr_from_transfer(struct ps2_dmac* dmac) { // ); for (int i = 0; i < dmac->spr_from.qwc; i++) { - uint128_t q = dmac_read_qword(dmac, dmac->spr_from.sadr, 1); + uint128_t q = ps2_ram_read128(dmac->spr, dmac->spr_from.sadr & 0x3ff0); ee_bus_write128(dmac->bus, dmac->spr_from.madr, q); @@ -1037,7 +1062,7 @@ void dmac_spr_to_interleave(struct ps2_dmac* dmac) { while (dmac->spr_to.qwc) { for (int i = 0; i < tqwc && dmac->spr_to.qwc; i++) { - uint128_t q = dmac_read_qword(dmac, dmac->spr_to.madr, 0); + uint128_t q = dmac_read_qword(dmac, dmac->spr_to.madr); ps2_ram_write128(dmac->spr, dmac->spr_to.sadr, q); @@ -1075,7 +1100,7 @@ void dmac_handle_spr_to_transfer(struct ps2_dmac* dmac) { } for (int i = 0; i < dmac->spr_to.qwc; i++) { - uint128_t q = dmac_read_qword(dmac, dmac->spr_to.madr, 0); + uint128_t q = dmac_read_qword(dmac, dmac->spr_to.madr); ps2_ram_write128(dmac->spr, dmac->spr_to.sadr, q); @@ -1087,36 +1112,34 @@ void dmac_handle_spr_to_transfer(struct ps2_dmac* dmac) { dmac->spr_to.qwc = 0; // We're done - if (mode == 0) { + if (dmac->spr_to.tag.end) return; - } // Chain mode do { - uint128_t tag = dmac_read_qword(dmac, dmac->spr_to.tadr, 0); - - dmac_process_source_tag(dmac, &dmac->spr_to, tag); + uint128_t tag = dmac_read_qword(dmac, dmac->spr_to.tadr); if ((dmac->spr_to.chcr >> 6) & 1) { ps2_ram_write128(dmac->spr, dmac->spr_to.sadr, tag); - dmac->spr_to.madr += 0x10; + dmac->spr_to.sadr += 0x10; } - // printf("ee: spr_to tag qwc=%08lx madr=%08lx tadr=%08lx id=%ld addr=%08lx mem=%ld data=%016lx end=%d tte=%d\n", + dmac_process_source_tag(dmac, &dmac->spr_to, tag); + + // printf("ee: spr_to tag qwc=%08lx madr=%08lx tadr=%08lx id=%ld addr=%08lx mem=%ld end=%d data=%08x%08x\n", // dmac->spr_to.tag.qwc, // dmac->spr_to.madr, // dmac->spr_to.tadr, // dmac->spr_to.tag.id, // dmac->spr_to.tag.addr, // dmac->spr_to.tag.mem, - // dmac->spr_to.tag.data, // dmac->spr_to.tag.end, - // (dmac->spr_to.chcr >> 7) & 1 + // tag.u32[1], tag.u32[0] // ); for (int i = 0; i < dmac->spr_to.qwc; i++) { - uint128_t q = dmac_read_qword(dmac, dmac->spr_to.madr, dmac->spr_to.tag.mem); + uint128_t q = dmac_read_qword(dmac, dmac->spr_to.madr); ps2_ram_write128(dmac->spr, dmac->spr_to.sadr, q); @@ -1377,11 +1400,17 @@ void ps2_dmac_write8(struct ps2_dmac* dmac, uint32_t addr, uint64_t data) { } } } return; + + // ENABLEW (byte 2) + case 0x1000f592: { + dmac->enable &= 0xff00ffff; + dmac->enable |= (data & 0xff) << 16; + } return; } printf("dmac: 8-bit write to %08x (%02x)\n", addr, data); - exit(1); + // exit(1); return; } diff --git a/src/ee/dmac.h b/src/ee/dmac.h index dfcd199..98d800d 100644 --- a/src/ee/dmac.h +++ b/src/ee/dmac.h @@ -20,8 +20,7 @@ extern "C" { #define TAG_PCT(d) ((d.u64[0] >> 26) & 3) #define TAG_ID(d) ((d.u64[0] >> 28) & 7) #define TAG_IRQ(d) ((d.u64[0] >> 31) & 1) -#define TAG_ADDR(d) ((d.u64[0] >> 32) & 0x7fffffff) -#define TAG_MEM(d) ((d.u64[0] >> 63) & 1) +#define TAG_ADDR(d) ((d.u64[0] >> 32) & 0xfffffff0) #define TAG_DATA(d) (d.u64[1]) #define DMAC_VIF0 0 @@ -42,7 +41,6 @@ struct dmac_tag { uint64_t id; uint64_t irq; uint64_t addr; - uint64_t mem; uint64_t data; int end; }; diff --git a/src/ee/ee.h b/src/ee/ee.h index 77d29fa..86ca501 100644 --- a/src/ee/ee.h +++ b/src/ee/ee.h @@ -143,6 +143,8 @@ uint32_t ee_get_pc(struct ee_state* ee); struct ps2_ram* ee_get_spr(struct ee_state* ee); int ee_run_block(struct ee_state* ee, int cycles); void ee_set_fmv_skip(struct ee_state* ee, int v); +void ee_reset_intc_reads(struct ee_state* ee); +void ee_reset_csr_reads(struct ee_state* ee); #undef EE_ALIGNED16 diff --git a/src/ee/ee_cached.cpp b/src/ee/ee_cached.cpp index 0d58b9c..ce8bdcd 100644 --- a/src/ee/ee_cached.cpp +++ b/src/ee/ee_cached.cpp @@ -2,8 +2,9 @@ #include #include #include -#include #include +#include +#include #include #ifdef _EE_USE_INTRINSICS @@ -34,8 +35,8 @@ #endif // file = fopen("vu.dump", "a"); fprintf(file, #ins "\n"); fclose(file); -#define VU_LOWER(ins) { ee->vu0->lower = i.opcode; vu_i_ ## ins(ee->vu0); } -#define VU_UPPER(ins) { ee->vu0->upper = i.opcode; vu_i_ ## ins(ee->vu0); } +#define VU_LOWER(ins) { ps2_vu_decode_lower(ee->vu0, i.opcode); vu_i_ ## ins(ee->vu0, &ee->vu0->lower); } +#define VU_UPPER(ins) { ps2_vu_decode_upper(ee->vu0, i.opcode); vu_i_ ## ins(ee->vu0, &ee->vu0->upper); } static inline int fast_abs32(int a) { uint32_t m = a >> 31; @@ -59,6 +60,16 @@ static inline int16_t saturate16(int32_t word) { } } +static inline int32_t saturate32(int64_t word) { + if (word > (int32_t)0x7FFFFFFF) { + return 0x7FFFFFFF; + } else if (word < (int32_t)0x80000000) { + return 0x80000000; + } else { + return (int32_t)word; + } +} + #ifdef _EE_USE_INTRINSICS static inline __m128i _mm_adds_epi32(__m128i a, __m128i b) { const __m128i m = _mm_set1_epi32(0x7fffffff); @@ -346,11 +357,9 @@ static inline int ee_translate_virt(struct ee_state* ee, uint32_t virt, uint32_t if ((addr & 0xf0000000) == 0x70000000) \ return ps2_ram_read ## b(ee->scratchpad, addr & 0x3fff); \ uint32_t phys; \ - if (ee_translate_virt(ee, addr, &phys)) { \ - printf("ee: TLB mapping error\n"); \ - exit(1); \ - return 0; \ - } \ + ee_translate_virt(ee, addr, &phys); \ + if (phys == 0x1000f000) ee->intc_reads++; \ + if (phys == 0x12001000) ee->csr_reads++; \ return ee->bus.read ## b(ee->bus.udata, phys); \ } @@ -359,11 +368,7 @@ static inline int ee_translate_virt(struct ee_state* ee, uint32_t virt, uint32_t if ((addr & 0xf0000000) == 0x70000000) \ { ps2_ram_write ## b(ee->scratchpad, addr & 0x3fff, data); return; } \ uint32_t phys; \ - if (ee_translate_virt(ee, addr, &phys)) { \ - printf("ee: TLB mapping error\n"); \ - exit(1); \ - return; \ - } \ + ee_translate_virt(ee, addr, &phys); \ ee->bus.write ## b(ee->bus.udata, phys, data); \ } @@ -532,6 +537,8 @@ static inline int ee_check_irq(struct ee_state* ee) { // ee->delay_slot // ); + ee->intc_reads = 0; + ee_exception_level1(ee, CAUSE_EXC1_INT); return 1; @@ -631,16 +638,16 @@ static inline void ee_i_bc0tl(struct ee_state* ee, const ee_instruction& i) { BRANCH_LIKELY(ee->cpcond0, EE_D_SI16); } static inline void ee_i_bc1f(struct ee_state* ee, const ee_instruction& i) { - BRANCH((ee->fcr & (1 << 23)) == 0, EE_D_SI16); + BRANCH((ee->fcr & FPU_FLG_C) == 0, EE_D_SI16); } static inline void ee_i_bc1fl(struct ee_state* ee, const ee_instruction& i) { - BRANCH_LIKELY((ee->fcr & (1 << 23)) == 0, EE_D_SI16); + BRANCH_LIKELY((ee->fcr & FPU_FLG_C) == 0, EE_D_SI16); } static inline void ee_i_bc1t(struct ee_state* ee, const ee_instruction& i) { - BRANCH((ee->fcr & (1 << 23)) != 0, EE_D_SI16); + BRANCH((ee->fcr & FPU_FLG_C) != 0, EE_D_SI16); } static inline void ee_i_bc1tl(struct ee_state* ee, const ee_instruction& i) { - BRANCH_LIKELY((ee->fcr & (1 << 23)) != 0, EE_D_SI16); + BRANCH_LIKELY((ee->fcr & FPU_FLG_C) != 0, EE_D_SI16); } static inline void ee_i_bc2f(struct ee_state* ee, const ee_instruction& i) { BRANCH(1, EE_D_SI16); } static inline void ee_i_bc2fl(struct ee_state* ee, const ee_instruction& i) { BRANCH_LIKELY(1, EE_D_SI16); } @@ -710,39 +717,39 @@ static inline void ee_i_cache(struct ee_state* ee, const ee_instruction& i) { } static inline void ee_i_ceq(struct ee_state* ee, const ee_instruction& i) { if (EE_FS == EE_FT) { - ee->fcr |= 1 << 23; + ee->fcr |= FPU_FLG_C; } else { - ee->fcr &= ~(1 << 23); + ee->fcr &= ~FPU_FLG_C; } } static inline void ee_i_cf(struct ee_state* ee, const ee_instruction& i) { - ee->fcr &= ~(1 << 23); + ee->fcr &= ~FPU_FLG_C; } static inline void ee_i_cfc1(struct ee_state* ee, const ee_instruction& i) { - EE_RT = (EE_D_FS >= 16) ? ee->fcr : 0x2e30; + EE_RT = SE6432((EE_D_FS >= 16) ? ee->fcr : 0x2e30); } static inline void ee_i_cfc2(struct ee_state* ee, const ee_instruction& i) { EE_RT = SE6432(ps2_vu_read_vi(ee->vu0, EE_D_RD)); } static inline void ee_i_cle(struct ee_state* ee, const ee_instruction& i) { if (EE_FS <= EE_FT) { - ee->fcr |= 1 << 23; + ee->fcr |= FPU_FLG_C; } else { - ee->fcr &= ~(1 << 23); + ee->fcr &= ~FPU_FLG_C; } } static inline void ee_i_clt(struct ee_state* ee, const ee_instruction& i) { if (EE_FS < EE_FT) { - ee->fcr |= 1 << 23; + ee->fcr |= FPU_FLG_C; } else { - ee->fcr &= ~(1 << 23); + ee->fcr &= ~FPU_FLG_C; } } static inline void ee_i_ctc1(struct ee_state* ee, const ee_instruction& i) { if (EE_D_FS < 16) return; - ee->fcr = (ee->fcr & ~(0x83c078)) | (EE_RT & 0x83c078); + ee->fcr = EE_RT32; // (ee->fcr & ~(0x83c078)) | (EE_RT & 0x83c078); } static inline void ee_i_ctc2(struct ee_state* ee, const ee_instruction& i) { // To-do: Handle FBRST, VPU_STAT, CMSAR1 @@ -1682,9 +1689,78 @@ static inline void ee_i_pcpyud(struct ee_state* ee, const ee_instruction& i) { ee->r[d].u64[0] = rs.u64[1]; ee->r[d].u64[1] = rt.u64[1]; } -static inline void ee_i_pdivbw(struct ee_state* ee, const ee_instruction& i) { printf("ee: pdivbw unimplemented\n"); exit(1); } -static inline void ee_i_pdivuw(struct ee_state* ee, const ee_instruction& i) { printf("ee: pdivuw unimplemented\n"); exit(1); } -static inline void ee_i_pdivw(struct ee_state* ee, const ee_instruction& i) { printf("ee: pdivw unimplemented\n"); exit(1); } +static inline void ee_i_pdivbw(struct ee_state* ee, const ee_instruction& i) { + int s = EE_D_RS; + int t = EE_D_RT; + + for (int i = 0; i < 4; i++) { + if (ee->r[s].u32[i] == 0x80000000 && ee->r[t].u16[0] == 0xffff) { + ee->lo.u32[i] = 0x80000000; + ee->hi.u32[i] = 0; + } else if (ee->r[t].u16[0] != 0) { + ee->lo.u32[i] = ee->r[s].s32[i] / ee->r[t].s16[0]; + ee->hi.u32[i] = ee->r[s].s32[i] % ee->r[t].s16[0]; + } else { + if (ee->r[s].s32[i] < 0) { + ee->lo.u32[i] = 1; + } else { + ee->lo.u32[i] = -1; + } + + ee->hi.u32[i] = ee->r[s].s32[i]; + } + } + + // ee->hi.u32[0] = SE3216(ee->r[s].s32[0] % ee->r[t].s16[0]); + // ee->hi.u32[1] = SE3216(ee->r[s].s32[1] % ee->r[t].s16[0]); + // ee->hi.u32[2] = SE3216(ee->r[s].s32[2] % ee->r[t].s16[0]); + // ee->hi.u32[3] = SE3216(ee->r[s].s32[3] % ee->r[t].s16[0]); + // ee->lo.u32[0] = ee->r[s].s32[0] / ee->r[t].s16[0]; + // ee->lo.u32[1] = ee->r[s].s32[1] / ee->r[t].s16[0]; + // ee->lo.u32[2] = ee->r[s].s32[2] / ee->r[t].s16[0]; + // ee->lo.u32[3] = ee->r[s].s32[3] / ee->r[t].s16[0]; +} +static inline void ee_i_pdivuw(struct ee_state* ee, const ee_instruction& i) { + int s = EE_D_RS; + int t = EE_D_RT; + + for (int i = 0; i < 4; i += 2) { + if (ee->r[t].u32[i] != 0) { + ee->lo.u64[i/2] = SE6432(ee->r[s].u32[i] / ee->r[t].u32[i]); + ee->hi.u64[i/2] = SE6432(ee->r[s].u32[i] % ee->r[t].u32[i]); + } else { + ee->lo.u64[i/2] = (int64_t)-1; + ee->hi.u64[i/2] = (int64_t)ee->r[s].s32[i]; + } + } +} +static inline void ee_i_pdivw(struct ee_state* ee, const ee_instruction& i) { + int s = EE_D_RS; + int t = EE_D_RT; + + for (int i = 0; i < 4; i += 2) { + if (ee->r[s].u32[i] == 0x80000000 && ee->r[t].u32[i] == 0xffffffff) { + ee->lo.u64[i/2] = (int64_t)(int32_t)0x80000000; + ee->hi.u64[i/2] = 0; + } else if (ee->r[t].u32[i] != 0) { + ee->lo.u64[i/2] = SE6432(ee->r[s].s32[i] / ee->r[t].s32[i]); + ee->hi.u64[i/2] = SE6432(ee->r[s].s32[i] % ee->r[t].s32[i]); + } else { + if (ee->r[s].s32[i] < 0) { + ee->lo.u64[i/2] = 1; + } else { + ee->lo.u64[i/2] = (int64_t)-1; + } + + ee->hi.u64[i/2] = (int64_t)ee->r[s].s32[i]; + } + } + + // ee->hi.u64[0] = SE6432(ee->r[s].s32[0] % ee->r[t].s32[0]); + // ee->hi.u64[1] = SE6432(ee->r[s].s32[2] % ee->r[t].s32[2]); + // ee->lo.u64[0] = SE6432(ee->r[s].s32[0] / ee->r[t].s32[0]); + // ee->lo.u64[1] = SE6432(ee->r[s].s32[2] / ee->r[t].s32[2]); +} static inline void ee_i_pexch(struct ee_state* ee, const ee_instruction& i) { uint128_t rt = ee->r[EE_D_RT]; int d = EE_D_RD; @@ -1835,16 +1911,47 @@ static inline void ee_i_phmadh(struct ee_state* ee, const ee_instruction& i) { uint128_t rs = ee->r[EE_D_RS]; int d = EE_D_RD; - ee->r[d].u32[0] = ((int16_t)rs.u16[1] * (int16_t)rt.u16[1]) + ((int16_t)rs.u16[0] * (int16_t)rt.u16[0]); - ee->r[d].u32[1] = ((int16_t)rs.u16[3] * (int16_t)rt.u16[3]) + ((int16_t)rs.u16[2] * (int16_t)rt.u16[2]); - ee->r[d].u32[2] = ((int16_t)rs.u16[5] * (int16_t)rt.u16[5]) + ((int16_t)rs.u16[4] * (int16_t)rt.u16[4]); - ee->r[d].u32[3] = ((int16_t)rs.u16[7] * (int16_t)rt.u16[7]) + ((int16_t)rs.u16[6] * (int16_t)rt.u16[6]); + int32_t r0 = (int32_t)(rs.s16[1] * rt.s16[1]); + int32_t r1 = (int32_t)(rs.s16[3] * rt.s16[3]); + int32_t r2 = (int32_t)(rs.s16[5] * rt.s16[5]); + int32_t r3 = (int32_t)(rs.s16[7] * rt.s16[7]); + + ee->r[d].u32[0] = r0 + ((int16_t)rs.u16[0] * (int16_t)rt.u16[0]); + ee->r[d].u32[1] = r1 + ((int16_t)rs.u16[2] * (int16_t)rt.u16[2]); + ee->r[d].u32[2] = r2 + ((int16_t)rs.u16[4] * (int16_t)rt.u16[4]); + ee->r[d].u32[3] = r3 + ((int16_t)rs.u16[6] * (int16_t)rt.u16[6]); + ee->lo.u32[0] = ee->r[d].u32[0]; + ee->lo.u32[1] = r0; + ee->hi.u32[0] = ee->r[d].u32[1]; + ee->hi.u32[1] = r1; + ee->lo.u32[2] = ee->r[d].u32[2]; + ee->lo.u32[3] = r2; + ee->hi.u32[2] = ee->r[d].u32[3]; + ee->hi.u32[3] = r3; +} +static inline void ee_i_phmsbh(struct ee_state* ee, const ee_instruction& i) { + int d = EE_D_RD; + int s = EE_D_RS; + int t = EE_D_RT; + + int32_t r1 = ee->r[s].s16[1] * ee->r[t].s16[1]; + int32_t r3 = ee->r[s].s16[3] * ee->r[t].s16[3]; + int32_t r5 = ee->r[s].s16[5] * ee->r[t].s16[5]; + int32_t r7 = ee->r[s].s16[7] * ee->r[t].s16[7]; + + ee->r[d].u32[0] = (int32_t)(r1 - (ee->r[s].s16[0] * ee->r[t].s16[0])); + ee->r[d].u32[1] = (int32_t)(r3 - (ee->r[s].s16[2] * ee->r[t].s16[2])); + ee->r[d].u32[2] = (int32_t)(r5 - (ee->r[s].s16[4] * ee->r[t].s16[4])); + ee->r[d].u32[3] = (int32_t)(r7 - (ee->r[s].s16[6] * ee->r[t].s16[6])); ee->lo.u32[0] = ee->r[d].u32[0]; + ee->lo.u32[1] = ~r1; ee->hi.u32[0] = ee->r[d].u32[1]; + ee->hi.u32[1] = ~r3; ee->lo.u32[2] = ee->r[d].u32[2]; + ee->lo.u32[3] = ~r5; ee->hi.u32[2] = ee->r[d].u32[3]; + ee->hi.u32[3] = ~r7; } -static inline void ee_i_phmsbh(struct ee_state* ee, const ee_instruction& i) { printf("ee: phmsbh unimplemented\n"); exit(1); } static inline void ee_i_pinteh(struct ee_state* ee, const ee_instruction& i) { uint128_t rt = ee->r[EE_D_RT]; uint128_t rs = ee->r[EE_D_RS]; @@ -1920,8 +2027,36 @@ static inline void ee_i_pmaddh(struct ee_state* ee, const ee_instruction& i) { ee->lo.u32[2] = ee->r[d].u32[2]; ee->hi.u32[2] = ee->r[d].u32[3]; } -static inline void ee_i_pmadduw(struct ee_state* ee, const ee_instruction& i) { printf("ee: pmadduw unimplemented\n"); exit(1); } -static inline void ee_i_pmaddw(struct ee_state* ee, const ee_instruction& i) { printf("ee: pmaddw unimplemented\n"); exit(1); } +static inline void ee_i_pmadduw(struct ee_state* ee, const ee_instruction& i) { + int d = EE_D_RD; + int s = EE_D_RS; + int t = EE_D_RT; + + uint64_t r0 = (uint64_t)ee->r[s].u32[0] * (uint64_t)ee->r[t].u32[0]; + uint64_t r1 = (uint64_t)ee->r[s].u32[2] * (uint64_t)ee->r[t].u32[2]; + + ee->r[d].u64[0] = r0 + ((ee->hi.u64[0] << 32) | (uint64_t)ee->lo.u32[0]); + ee->r[d].u64[1] = r1 + ((ee->hi.u64[1] << 32) | (uint64_t)ee->lo.u32[2]); + ee->lo.u64[0] = SE6432(ee->r[d].u32[0]); + ee->hi.u64[0] = SE6432(ee->r[d].u32[1]); + ee->lo.u64[1] = SE6432(ee->r[d].u32[2]); + ee->hi.u64[1] = SE6432(ee->r[d].u32[3]); +} +static inline void ee_i_pmaddw(struct ee_state* ee, const ee_instruction& i) { + int d = EE_D_RD; + int s = EE_D_RS; + int t = EE_D_RT; + + uint64_t r0 = (int64_t)ee->r[s].s32[0] * (int64_t)ee->r[t].s32[0]; + uint64_t r1 = (int64_t)ee->r[s].s32[2] * (int64_t)ee->r[t].s32[2]; + + ee->r[d].u64[0] = r0 + ((((uint64_t)ee->hi.u32[0]) << 32) | (uint64_t)ee->lo.u32[0]); + ee->r[d].u64[1] = r1 + ((((uint64_t)ee->hi.u32[2]) << 32) | (uint64_t)ee->lo.u32[2]); + ee->lo.u64[0] = SE6432(ee->r[d].u32[0]); + ee->hi.u64[0] = SE6432(ee->r[d].u32[1]); + ee->lo.u64[1] = SE6432(ee->r[d].u32[2]); + ee->hi.u64[1] = SE6432(ee->r[d].u32[3]); +} static inline void ee_i_pmaxh(struct ee_state* ee, const ee_instruction& i) { int d = EE_D_RD; int s = EE_D_RS; @@ -1965,7 +2100,12 @@ static inline void ee_i_pmfhluw(struct ee_state* ee, const ee_instruction& i) { ee->r[d].u32[2] = ee->lo.u32[3]; ee->r[d].u32[3] = ee->hi.u32[3]; } -static inline void ee_i_pmfhlslw(struct ee_state* ee, const ee_instruction& i) { printf("ee: pmfhlslw unimplemented\n"); exit(1); } +static inline void ee_i_pmfhlslw(struct ee_state* ee, const ee_instruction& i) { + int d = EE_D_RD; + + ee->r[d].u64[0] = SE6432(saturate32(((uint64_t)ee->lo.u32[0]) | (ee->hi.u64[0] << 32))); + ee->r[d].u64[1] = SE6432(saturate32(((uint64_t)ee->lo.u32[2]) | (ee->hi.u64[1] << 32))); +} static inline void ee_i_pmfhllh(struct ee_state* ee, const ee_instruction& i) { int d = EE_D_RD; @@ -2013,17 +2153,91 @@ static inline void ee_i_pminw(struct ee_state* ee, const ee_instruction& i) { int s = EE_D_RS; int t = EE_D_RT; - ee->r[d].u32[0] = ((int32_t)ee->r[s].u32[0] < (int32_t)ee->r[t].u32[0]) ? ee->r[s].u32[0] : ee->r[t].u32[0]; - ee->r[d].u32[1] = ((int32_t)ee->r[s].u32[1] < (int32_t)ee->r[t].u32[1]) ? ee->r[s].u32[1] : ee->r[t].u32[1]; - ee->r[d].u32[2] = ((int32_t)ee->r[s].u32[2] < (int32_t)ee->r[t].u32[2]) ? ee->r[s].u32[2] : ee->r[t].u32[2]; - ee->r[d].u32[3] = ((int32_t)ee->r[s].u32[3] < (int32_t)ee->r[t].u32[3]) ? ee->r[s].u32[3] : ee->r[t].u32[3]; + ee->r[d].u32[0] = (ee->r[s].s32[0] < ee->r[t].s32[0]) ? ee->r[s].u32[0] : ee->r[t].u32[0]; + ee->r[d].u32[1] = (ee->r[s].s32[1] < ee->r[t].s32[1]) ? ee->r[s].u32[1] : ee->r[t].u32[1]; + ee->r[d].u32[2] = (ee->r[s].s32[2] < ee->r[t].s32[2]) ? ee->r[s].u32[2] : ee->r[t].u32[2]; + ee->r[d].u32[3] = (ee->r[s].s32[3] < ee->r[t].s32[3]) ? ee->r[s].u32[3] : ee->r[t].u32[3]; +} +static inline void ee_i_pmsubh(struct ee_state* ee, const ee_instruction& i) { + int s = EE_D_RS; + int t = EE_D_RT; + int d = EE_D_RD; + + int32_t r0 = (int32_t)ee->r[s].s16[0] * (int32_t)ee->r[t].s16[0]; + int32_t r1 = (int32_t)ee->r[s].s16[1] * (int32_t)ee->r[t].s16[1]; + int32_t r2 = (int32_t)ee->r[s].s16[2] * (int32_t)ee->r[t].s16[2]; + int32_t r3 = (int32_t)ee->r[s].s16[3] * (int32_t)ee->r[t].s16[3]; + int32_t r4 = (int32_t)ee->r[s].s16[4] * (int32_t)ee->r[t].s16[4]; + int32_t r5 = (int32_t)ee->r[s].s16[5] * (int32_t)ee->r[t].s16[5]; + int32_t r6 = (int32_t)ee->r[s].s16[6] * (int32_t)ee->r[t].s16[6]; + int32_t r7 = (int32_t)ee->r[s].s16[7] * (int32_t)ee->r[t].s16[7]; + + ee->r[d].u32[0] = ee->lo.u32[0] - r0; + ee->r[d].u32[1] = ee->hi.u32[0] - r2; + ee->r[d].u32[2] = ee->lo.u32[2] - r4; + ee->r[d].u32[3] = ee->hi.u32[2] - r6; + ee->lo.u32[0] = ee->r[d].u32[0]; + ee->hi.u32[0] = ee->r[d].u32[1]; + ee->lo.u32[2] = ee->r[d].u32[2]; + ee->hi.u32[2] = ee->r[d].u32[3]; + + ee->lo.u32[1] = ee->lo.u32[1] - r1; + ee->lo.u32[3] = ee->lo.u32[3] - r5; + ee->hi.u32[1] = ee->hi.u32[1] - r3; + ee->hi.u32[3] = ee->hi.u32[3] - r7; +} +static inline void ee_i_pmsubw(struct ee_state* ee, const ee_instruction& i) { + int s = EE_D_RS; + int t = EE_D_RT; + int d = EE_D_RD; + + // int64_t r0 = ee->r[s].s32[0] * ee->r[t].s32[0]; + // int64_t r1 = ee->r[s].s32[2] * ee->r[t].s32[2]; + + // ee->r[d].u64[0] = ((ee->hi.u64[0] << 32) | (uint64_t)ee->lo.u32[0]) - r0; + // ee->r[d].u64[1] = ((ee->hi.u64[1] << 32) | (uint64_t)ee->lo.u32[2]) - r0; + + // ee->lo.u64[0] = SE6432(ee->r[d].u32[0]); + // ee->hi.u64[0] = SE6432(ee->r[d].u32[1]); + // ee->lo.u64[1] = SE6432(ee->r[d].u32[2]); + // ee->hi.u64[1] = SE6432(ee->r[d].u32[3]); + + int64_t op1 = (int64_t)ee->r[s].s32[0]; + int64_t op2 = (int64_t)ee->r[t].s32[0]; + int64_t result = op1 * op2; + int64_t result2 = ((int64_t)ee->hi.s32[0] << 32) - result; + + result2 = (int32_t)(result2 / 4294967295); + + ee->lo.s64[0] = ee->lo.s32[0] - (int32_t)(result & 0xffffffff); + ee->hi.s64[0] = (int32_t)result2; + + op1 = (int64_t)ee->r[s].s32[2]; + op2 = (int64_t)ee->r[t].s32[2]; + result = op1 * op2; + + result2 = ((int64_t)ee->hi.s32[2] << 32) - result; + result2 = (int32_t)(result2 / 4294967295); + + ee->lo.s64[1] = ee->lo.s32[2] - (int32_t)(result & 0xffffffff); + ee->hi.s64[1] = (int32_t)result2; + + ee->r[d].u32[0] = ee->lo.u32[0]; + ee->r[d].u32[1] = ee->hi.u32[0]; + ee->r[d].u32[2] = ee->lo.u32[2]; + ee->r[d].u32[3] = ee->hi.u32[2]; } -static inline void ee_i_pmsubh(struct ee_state* ee, const ee_instruction& i) { printf("ee: pmsubh unimplemented\n"); exit(1); } -static inline void ee_i_pmsubw(struct ee_state* ee, const ee_instruction& i) { printf("ee: pmsubw unimplemented\n"); exit(1); } static inline void ee_i_pmthi(struct ee_state* ee, const ee_instruction& i) { ee->hi = ee->r[EE_D_RS]; } -static inline void ee_i_pmthl(struct ee_state* ee, const ee_instruction& i) { printf("ee: pmthl unimplemented\n"); exit(1); } +static inline void ee_i_pmthl(struct ee_state* ee, const ee_instruction& i) { + int s = EE_D_RS; + + ee->lo.u32[0] = ee->r[s].u32[0]; + ee->lo.u32[2] = ee->r[s].u32[2]; + ee->hi.u32[0] = ee->r[s].u32[1]; + ee->hi.u32[2] = ee->r[s].u32[3]; +} static inline void ee_i_pmtlo(struct ee_state* ee, const ee_instruction& i) { ee->lo = ee->r[EE_D_RS]; } @@ -2225,7 +2439,14 @@ static inline void ee_i_psrah(struct ee_state* ee, const ee_instruction& i) { ee->r[d].u16[6] = ((int16_t)ee->r[t].u16[6]) >> sa; ee->r[d].u16[7] = ((int16_t)ee->r[t].u16[7]) >> sa; } -static inline void ee_i_psravw(struct ee_state* ee, const ee_instruction& i) { printf("ee: psravw unimplemented\n"); exit(1); } +static inline void ee_i_psravw(struct ee_state* ee, const ee_instruction& i) { + int s = EE_D_RS; + int t = EE_D_RT; + int d = EE_D_RD; + + ee->r[d].u64[0] = SE6432((int32_t)ee->r[t].u32[0] >> (ee->r[s].u32[0] & 31)); + ee->r[d].u64[1] = SE6432((int32_t)ee->r[t].u32[2] >> (ee->r[s].u32[2] & 31)); +} static inline void ee_i_psraw(struct ee_state* ee, const ee_instruction& i) { int sa = EE_D_SA; int t = EE_D_RT; @@ -2752,7 +2973,9 @@ static inline void ee_i_teq(struct ee_state* ee, const ee_instruction& i) { static inline void ee_i_teqi(struct ee_state* ee, const ee_instruction& i) { if (EE_RS == SE6416(EE_D_I16)) ee_exception_level1(ee, CAUSE_EXC1_TR); } -static inline void ee_i_tge(struct ee_state* ee, const ee_instruction& i) { printf("ee: tge unimplemented\n"); exit(1); } +static inline void ee_i_tge(struct ee_state* ee, const ee_instruction& i) { + if (EE_RS >= EE_RT) ee_exception_level1(ee, CAUSE_EXC1_TR); +} static inline void ee_i_tgei(struct ee_state* ee, const ee_instruction& i) { printf("ee: tgei unimplemented\n"); exit(1); } static inline void ee_i_tgeiu(struct ee_state* ee, const ee_instruction& i) { printf("ee: tgeiu unimplemented\n"); exit(1); } static inline void ee_i_tgeu(struct ee_state* ee, const ee_instruction& i) { printf("ee: tgeu unimplemented\n"); exit(1); } @@ -2962,6 +3185,8 @@ void ee_reset(struct ee_state* ee) { ee->prid = 0x2e20; ee->pc = EE_VEC_RESET; ee->next_pc = ee->pc + 4; + ee->intc_reads = 0; + ee->csr_reads = 0; ee->block_cache.clear(); @@ -2994,183 +3219,184 @@ ee_instruction ee_decode(uint32_t opcode) { i.i26 = opcode & 0x3ffffff; i.branch = 0; + i.cycles = 0; switch ((opcode & 0xFC000000) >> 26) { case 0x00000000 >> 26: { // special switch (opcode & 0x0000003F) { - case 0x00000000: i.func = ee_i_sll; return i; - case 0x00000002: i.func = ee_i_srl; return i; - case 0x00000003: i.func = ee_i_sra; return i; - case 0x00000004: i.func = ee_i_sllv; return i; - case 0x00000006: i.func = ee_i_srlv; return i; - case 0x00000007: i.func = ee_i_srav; return i; - case 0x00000008: i.branch = 1; i.func = ee_i_jr; return i; - case 0x00000009: i.branch = 1; i.func = ee_i_jalr; return i; - case 0x0000000A: i.func = ee_i_movz; return i; - case 0x0000000B: i.func = ee_i_movn; return i; - case 0x0000000C: i.branch = 2; i.func = ee_i_syscall; return i; - case 0x0000000D: i.branch = 2; i.func = ee_i_break; return i; - case 0x0000000F: i.func = ee_i_sync; return i; - case 0x00000010: i.func = ee_i_mfhi; return i; - case 0x00000011: i.func = ee_i_mthi; return i; - case 0x00000012: i.func = ee_i_mflo; return i; - case 0x00000013: i.func = ee_i_mtlo; return i; - case 0x00000014: i.func = ee_i_dsllv; return i; - case 0x00000016: i.func = ee_i_dsrlv; return i; - case 0x00000017: i.func = ee_i_dsrav; return i; - case 0x00000018: i.func = ee_i_mult; return i; - case 0x00000019: i.func = ee_i_multu; return i; - case 0x0000001A: i.func = ee_i_div; return i; - case 0x0000001B: i.func = ee_i_divu; return i; - case 0x00000020: i.branch = 4; i.func = ee_i_add; return i; - case 0x00000021: i.func = ee_i_addu; return i; - case 0x00000022: i.branch = 4; i.func = ee_i_sub; return i; - case 0x00000023: i.func = ee_i_subu; return i; - case 0x00000024: i.func = ee_i_and; return i; - case 0x00000025: i.func = ee_i_or; return i; - case 0x00000026: i.func = ee_i_xor; return i; - case 0x00000027: i.func = ee_i_nor; return i; - case 0x00000028: i.func = ee_i_mfsa; return i; - case 0x00000029: i.func = ee_i_mtsa; return i; - case 0x0000002A: i.func = ee_i_slt; return i; - case 0x0000002B: i.func = ee_i_sltu; return i; - case 0x0000002C: i.branch = 4; i.func = ee_i_dadd; return i; - case 0x0000002D: i.func = ee_i_daddu; return i; - case 0x0000002E: i.branch = 4; i.func = ee_i_dsub; return i; - case 0x0000002F: i.func = ee_i_dsubu; return i; - case 0x00000030: i.branch = 4; i.func = ee_i_tge; return i; - case 0x00000031: i.branch = 4; i.func = ee_i_tgeu; return i; - case 0x00000032: i.branch = 4; i.func = ee_i_tlt; return i; - case 0x00000033: i.branch = 4; i.func = ee_i_tltu; return i; - case 0x00000034: i.branch = 4; i.func = ee_i_teq; return i; - case 0x00000036: i.branch = 4; i.func = ee_i_tne; return i; - case 0x00000038: i.func = ee_i_dsll; return i; - case 0x0000003A: i.func = ee_i_dsrl; return i; - case 0x0000003B: i.func = ee_i_dsra; return i; - case 0x0000003C: i.func = ee_i_dsll32; return i; - case 0x0000003E: i.func = ee_i_dsrl32; return i; - case 0x0000003F: i.func = ee_i_dsra32; return i; + case 0x00000000: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_sll; return i; + case 0x00000002: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_srl; return i; + case 0x00000003: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_sra; return i; + case 0x00000004: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_sllv; return i; + case 0x00000006: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_srlv; return i; + case 0x00000007: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_srav; return i; + case 0x00000008: i.cycles = EE_CYC_DEFAULT; i.branch = 1; i.func = ee_i_jr; return i; + case 0x00000009: i.cycles = EE_CYC_DEFAULT; i.branch = 1; i.func = ee_i_jalr; return i; + case 0x0000000A: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_movz; return i; + case 0x0000000B: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_movn; return i; + case 0x0000000C: i.cycles = EE_CYC_DEFAULT; i.branch = 2; i.func = ee_i_syscall; return i; + case 0x0000000D: i.cycles = EE_CYC_DEFAULT; i.branch = 2; i.func = ee_i_break; return i; + case 0x0000000F: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_sync; return i; + case 0x00000010: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_mfhi; return i; + case 0x00000011: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_mthi; return i; + case 0x00000012: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_mflo; return i; + case 0x00000013: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_mtlo; return i; + case 0x00000014: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_dsllv; return i; + case 0x00000016: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_dsrlv; return i; + case 0x00000017: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_dsrav; return i; + case 0x00000018: i.cycles = EE_CYC_MULT; i.func = ee_i_mult; return i; + case 0x00000019: i.cycles = EE_CYC_MULT; i.func = ee_i_multu; return i; + case 0x0000001A: i.cycles = EE_CYC_DIV; i.func = ee_i_div; return i; + case 0x0000001B: i.cycles = EE_CYC_DIV; i.func = ee_i_divu; return i; + case 0x00000020: i.cycles = EE_CYC_DEFAULT; i.branch = 4; i.func = ee_i_add; return i; + case 0x00000021: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_addu; return i; + case 0x00000022: i.cycles = EE_CYC_DEFAULT; i.branch = 4; i.func = ee_i_sub; return i; + case 0x00000023: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_subu; return i; + case 0x00000024: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_and; return i; + case 0x00000025: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_or; return i; + case 0x00000026: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_xor; return i; + case 0x00000027: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_nor; return i; + case 0x00000028: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_mfsa; return i; + case 0x00000029: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_mtsa; return i; + case 0x0000002A: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_slt; return i; + case 0x0000002B: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_sltu; return i; + case 0x0000002C: i.cycles = EE_CYC_DEFAULT; i.branch = 4; i.func = ee_i_dadd; return i; + case 0x0000002D: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_daddu; return i; + case 0x0000002E: i.cycles = EE_CYC_DEFAULT; i.branch = 4; i.func = ee_i_dsub; return i; + case 0x0000002F: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_dsubu; return i; + case 0x00000030: i.cycles = EE_CYC_BRANCH; i.branch = 4; i.func = ee_i_tge; return i; + case 0x00000031: i.cycles = EE_CYC_BRANCH; i.branch = 4; i.func = ee_i_tgeu; return i; + case 0x00000032: i.cycles = EE_CYC_BRANCH; i.branch = 4; i.func = ee_i_tlt; return i; + case 0x00000033: i.cycles = EE_CYC_BRANCH; i.branch = 4; i.func = ee_i_tltu; return i; + case 0x00000034: i.cycles = EE_CYC_BRANCH; i.branch = 4; i.func = ee_i_teq; return i; + case 0x00000036: i.cycles = EE_CYC_BRANCH; i.branch = 4; i.func = ee_i_tne; return i; + case 0x00000038: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_dsll; return i; + case 0x0000003A: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_dsrl; return i; + case 0x0000003B: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_dsra; return i; + case 0x0000003C: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_dsll32; return i; + case 0x0000003E: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_dsrl32; return i; + case 0x0000003F: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_dsra32; return i; } } break; case 0x04000000 >> 26: { // regimm switch ((opcode & 0x001F0000) >> 16) { - case 0x00000000 >> 16: i.branch = 1; i.func = ee_i_bltz; return i; - case 0x00010000 >> 16: i.branch = 1; i.func = ee_i_bgez; return i; - case 0x00020000 >> 16: i.branch = 3; i.func = ee_i_bltzl; return i; - case 0x00030000 >> 16: i.branch = 3; i.func = ee_i_bgezl; return i; - case 0x00080000 >> 16: i.branch = 4; i.func = ee_i_tgei; return i; - case 0x00090000 >> 16: i.branch = 4; i.func = ee_i_tgeiu; return i; - case 0x000A0000 >> 16: i.branch = 4; i.func = ee_i_tlti; return i; - case 0x000B0000 >> 16: i.branch = 4; i.func = ee_i_tltiu; return i; - case 0x000C0000 >> 16: i.branch = 4; i.func = ee_i_teqi; return i; - case 0x000E0000 >> 16: i.branch = 4; i.func = ee_i_tnei; return i; - case 0x00100000 >> 16: i.branch = 1; i.func = ee_i_bltzal; return i; - case 0x00110000 >> 16: i.branch = 1; i.func = ee_i_bgezal; return i; - case 0x00120000 >> 16: i.branch = 3; i.func = ee_i_bltzall; return i; - case 0x00130000 >> 16: i.branch = 3; i.func = ee_i_bgezall; return i; - case 0x00180000 >> 16: i.func = ee_i_mtsab; return i; - case 0x00190000 >> 16: i.func = ee_i_mtsah; return i; + case 0x00000000 >> 16: i.cycles = EE_CYC_BRANCH; i.branch = 1; i.func = ee_i_bltz; return i; + case 0x00010000 >> 16: i.cycles = EE_CYC_BRANCH; i.branch = 1; i.func = ee_i_bgez; return i; + case 0x00020000 >> 16: i.cycles = EE_CYC_BRANCH; i.branch = 3; i.func = ee_i_bltzl; return i; + case 0x00030000 >> 16: i.cycles = EE_CYC_BRANCH; i.branch = 3; i.func = ee_i_bgezl; return i; + case 0x00080000 >> 16: i.cycles = EE_CYC_BRANCH; i.branch = 4; i.func = ee_i_tgei; return i; + case 0x00090000 >> 16: i.cycles = EE_CYC_BRANCH; i.branch = 4; i.func = ee_i_tgeiu; return i; + case 0x000A0000 >> 16: i.cycles = EE_CYC_BRANCH; i.branch = 4; i.func = ee_i_tlti; return i; + case 0x000B0000 >> 16: i.cycles = EE_CYC_BRANCH; i.branch = 4; i.func = ee_i_tltiu; return i; + case 0x000C0000 >> 16: i.cycles = EE_CYC_BRANCH; i.branch = 4; i.func = ee_i_teqi; return i; + case 0x000E0000 >> 16: i.cycles = EE_CYC_BRANCH; i.branch = 4; i.func = ee_i_tnei; return i; + case 0x00100000 >> 16: i.cycles = EE_CYC_BRANCH; i.branch = 1; i.func = ee_i_bltzal; return i; + case 0x00110000 >> 16: i.cycles = EE_CYC_BRANCH; i.branch = 1; i.func = ee_i_bgezal; return i; + case 0x00120000 >> 16: i.cycles = EE_CYC_BRANCH; i.branch = 3; i.func = ee_i_bltzall; return i; + case 0x00130000 >> 16: i.cycles = EE_CYC_BRANCH; i.branch = 3; i.func = ee_i_bgezall; return i; + case 0x00180000 >> 16: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_mtsab; return i; + case 0x00190000 >> 16: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_mtsah; return i; } } break; - case 0x08000000 >> 26: i.branch = 1; i.func = ee_i_j; return i; - case 0x0C000000 >> 26: i.branch = 1; i.func = ee_i_jal; return i; - case 0x10000000 >> 26: i.branch = 1; i.func = ee_i_beq; return i; - case 0x14000000 >> 26: i.branch = 1; i.func = ee_i_bne; return i; - case 0x18000000 >> 26: i.branch = 1; i.func = ee_i_blez; return i; - case 0x1C000000 >> 26: i.branch = 1; i.func = ee_i_bgtz; return i; - case 0x20000000 >> 26: i.branch = 4; i.func = ee_i_addi; return i; - case 0x24000000 >> 26: i.func = ee_i_addiu; return i; - case 0x28000000 >> 26: i.func = ee_i_slti; return i; - case 0x2C000000 >> 26: i.func = ee_i_sltiu; return i; - case 0x30000000 >> 26: i.func = ee_i_andi; return i; - case 0x34000000 >> 26: i.func = ee_i_ori; return i; - case 0x38000000 >> 26: i.func = ee_i_xori; return i; - case 0x3C000000 >> 26: i.func = ee_i_lui; return i; + case 0x08000000 >> 26: i.cycles = EE_CYC_DEFAULT; i.branch = 1; i.func = ee_i_j; return i; + case 0x0C000000 >> 26: i.cycles = EE_CYC_DEFAULT; i.branch = 1; i.func = ee_i_jal; return i; + case 0x10000000 >> 26: i.cycles = EE_CYC_BRANCH; i.branch = 1; i.func = ee_i_beq; return i; + case 0x14000000 >> 26: i.cycles = EE_CYC_BRANCH; i.branch = 1; i.func = ee_i_bne; return i; + case 0x18000000 >> 26: i.cycles = EE_CYC_BRANCH; i.branch = 1; i.func = ee_i_blez; return i; + case 0x1C000000 >> 26: i.cycles = EE_CYC_BRANCH; i.branch = 1; i.func = ee_i_bgtz; return i; + case 0x20000000 >> 26: i.cycles = EE_CYC_DEFAULT; i.branch = 4; i.func = ee_i_addi; return i; + case 0x24000000 >> 26: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_addiu; return i; + case 0x28000000 >> 26: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_slti; return i; + case 0x2C000000 >> 26: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_sltiu; return i; + case 0x30000000 >> 26: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_andi; return i; + case 0x34000000 >> 26: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_ori; return i; + case 0x38000000 >> 26: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_xori; return i; + case 0x3C000000 >> 26: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_lui; return i; case 0x40000000 >> 26: { // cop0 switch ((opcode & 0x03E00000) >> 21) { - case 0x00000000 >> 21: i.func = ee_i_mfc0; return i; - case 0x00800000 >> 21: i.func = ee_i_mtc0; return i; + case 0x00000000 >> 21: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_mfc0; return i; + case 0x00800000 >> 21: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_mtc0; return i; case 0x01000000 >> 21: { switch ((opcode & 0x001F0000) >> 16) { - case 0x00000000 >> 16: i.branch = 1; i.func = ee_i_bc0f; return i; - case 0x00010000 >> 16: i.branch = 1; i.func = ee_i_bc0t; return i; - case 0x00020000 >> 16: i.branch = 3; i.func = ee_i_bc0fl; return i; - case 0x00030000 >> 16: i.branch = 3; i.func = ee_i_bc0tl; return i; + case 0x00000000 >> 16: i.cycles = EE_CYC_BRANCH; i.branch = 1; i.func = ee_i_bc0f; return i; + case 0x00010000 >> 16: i.cycles = EE_CYC_BRANCH; i.branch = 1; i.func = ee_i_bc0t; return i; + case 0x00020000 >> 16: i.cycles = EE_CYC_BRANCH; i.branch = 3; i.func = ee_i_bc0fl; return i; + case 0x00030000 >> 16: i.cycles = EE_CYC_BRANCH; i.branch = 3; i.func = ee_i_bc0tl; return i; } } break; case 0x02000000 >> 21: { switch (opcode & 0x0000003F) { - case 0x00000001: i.func = ee_i_tlbr; return i; - case 0x00000002: i.func = ee_i_tlbwi; return i; - case 0x00000006: i.func = ee_i_tlbwr; return i; - case 0x00000008: i.func = ee_i_tlbp; return i; - case 0x00000018: i.branch = 2; i.func = ee_i_eret; return i; - case 0x00000038: i.func = ee_i_ei; return i; - case 0x00000039: i.func = ee_i_di; return i; + case 0x00000001: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_tlbr; return i; + case 0x00000002: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_tlbwi; return i; + case 0x00000006: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_tlbwr; return i; + case 0x00000008: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_tlbp; return i; + case 0x00000018: i.cycles = EE_CYC_COP_DEFAULT; i.branch = 2; i.func = ee_i_eret; return i; + case 0x00000038: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_ei; return i; + case 0x00000039: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_di; return i; } } break; } } break; case 0x44000000 >> 26: { // cop1 switch ((opcode & 0x03E00000) >> 21) { - case 0x00000000 >> 21: i.func = ee_i_mfc1; return i; - case 0x00400000 >> 21: i.func = ee_i_cfc1; return i; - case 0x00800000 >> 21: i.func = ee_i_mtc1; return i; - case 0x00C00000 >> 21: i.func = ee_i_ctc1; return i; + case 0x00000000 >> 21: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_mfc1; return i; + case 0x00400000 >> 21: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_cfc1; return i; + case 0x00800000 >> 21: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_mtc1; return i; + case 0x00C00000 >> 21: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_ctc1; return i; case 0x01000000 >> 21: { switch ((opcode & 0x001F0000) >> 16) { - case 0x00000000 >> 16: i.branch = 1; i.func = ee_i_bc1f; return i; - case 0x00010000 >> 16: i.branch = 1; i.func = ee_i_bc1t; return i; - case 0x00020000 >> 16: i.branch = 3; i.func = ee_i_bc1fl; return i; - case 0x00030000 >> 16: i.branch = 3; i.func = ee_i_bc1tl; return i; + case 0x00000000 >> 16: i.cycles = EE_CYC_BRANCH; i.branch = 1; i.func = ee_i_bc1f; return i; + case 0x00010000 >> 16: i.cycles = EE_CYC_BRANCH; i.branch = 1; i.func = ee_i_bc1t; return i; + case 0x00020000 >> 16: i.cycles = EE_CYC_BRANCH; i.branch = 3; i.func = ee_i_bc1fl; return i; + case 0x00030000 >> 16: i.cycles = EE_CYC_BRANCH; i.branch = 3; i.func = ee_i_bc1tl; return i; } } break; case 0x02000000 >> 21: { switch (opcode & 0x0000003F) { - case 0x00000000: i.func = ee_i_adds; return i; - case 0x00000001: i.func = ee_i_subs; return i; - case 0x00000002: i.func = ee_i_muls; return i; - case 0x00000003: i.func = ee_i_divs; return i; - case 0x00000004: i.func = ee_i_sqrts; return i; - case 0x00000005: i.func = ee_i_abss; return i; - case 0x00000006: i.func = ee_i_movs; return i; - case 0x00000007: i.func = ee_i_negs; return i; - case 0x00000016: i.func = ee_i_rsqrts; return i; - case 0x00000018: i.func = ee_i_addas; return i; - case 0x00000019: i.func = ee_i_subas; return i; - case 0x0000001A: i.func = ee_i_mulas; return i; - case 0x0000001C: i.func = ee_i_madds; return i; - case 0x0000001D: i.func = ee_i_msubs; return i; - case 0x0000001E: i.func = ee_i_maddas; return i; - case 0x0000001F: i.func = ee_i_msubas; return i; - case 0x00000024: i.func = ee_i_cvtw; return i; - case 0x00000028: i.func = ee_i_maxs; return i; - case 0x00000029: i.func = ee_i_mins; return i; - case 0x00000030: i.func = ee_i_cf; return i; - case 0x00000032: i.func = ee_i_ceq; return i; - case 0x00000034: i.func = ee_i_clt; return i; - case 0x00000036: i.func = ee_i_cle; return i; + case 0x00000000: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_adds; return i; + case 0x00000001: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_subs; return i; + case 0x00000002: i.cycles = EE_CYC_FPU_MULT; i.func = ee_i_muls; return i; + case 0x00000003: i.cycles = EE_CYC_FPU_DIV; i.func = ee_i_divs; return i; + case 0x00000004: i.cycles = EE_CYC_FPU_DIV; i.func = ee_i_sqrts; return i; + case 0x00000005: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_abss; return i; + case 0x00000006: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_movs; return i; + case 0x00000007: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_negs; return i; + case 0x00000016: i.cycles = EE_CYC_FPU_DIV; i.func = ee_i_rsqrts; return i; + case 0x00000018: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_addas; return i; + case 0x00000019: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_subas; return i; + case 0x0000001A: i.cycles = EE_CYC_FPU_MULT; i.func = ee_i_mulas; return i; + case 0x0000001C: i.cycles = EE_CYC_FPU_MULT; i.func = ee_i_madds; return i; + case 0x0000001D: i.cycles = EE_CYC_FPU_MULT; i.func = ee_i_msubs; return i; + case 0x0000001E: i.cycles = EE_CYC_FPU_MULT; i.func = ee_i_maddas; return i; + case 0x0000001F: i.cycles = EE_CYC_FPU_MULT; i.func = ee_i_msubas; return i; + case 0x00000024: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_cvtw; return i; + case 0x00000028: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_maxs; return i; + case 0x00000029: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_mins; return i; + case 0x00000030: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_cf; return i; + case 0x00000032: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_ceq; return i; + case 0x00000034: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_clt; return i; + case 0x00000036: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_cle; return i; } } break; case 0x02800000 >> 21: { switch (opcode & 0x0000003F) { - case 0x00000020: i.func = ee_i_cvts; return i; + case 0x00000020: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_cvts; return i; } } break; } } break; case 0x48000000 >> 26: { // cop2 switch ((opcode & 0x03E00000) >> 21) { - case 0x00200000 >> 21: i.func = ee_i_qmfc2; return i; - case 0x00400000 >> 21: i.func = ee_i_cfc2; return i; - case 0x00A00000 >> 21: i.func = ee_i_qmtc2; return i; - case 0x00C00000 >> 21: i.func = ee_i_ctc2; return i; + case 0x00200000 >> 21: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_qmfc2; return i; + case 0x00400000 >> 21: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_cfc2; return i; + case 0x00A00000 >> 21: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_qmtc2; return i; + case 0x00C00000 >> 21: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_ctc2; return i; case 0x01000000 >> 21: { switch ((opcode & 0x001F0000) >> 16) { - case 0x00000000 >> 16: i.branch = 1; i.func = ee_i_bc2f; return i; - case 0x00010000 >> 16: i.branch = 1; i.func = ee_i_bc2t; return i; - case 0x00020000 >> 16: i.branch = 3; i.func = ee_i_bc2fl; return i; - case 0x00030000 >> 16: i.branch = 3; i.func = ee_i_bc2tl; return i; + case 0x00000000 >> 16: i.cycles = EE_CYC_BRANCH; i.branch = 1; i.func = ee_i_bc2f; return i; + case 0x00010000 >> 16: i.cycles = EE_CYC_BRANCH; i.branch = 1; i.func = ee_i_bc2t; return i; + case 0x00020000 >> 16: i.cycles = EE_CYC_BRANCH; i.branch = 3; i.func = ee_i_bc2fl; return i; + case 0x00030000 >> 16: i.cycles = EE_CYC_BRANCH; i.branch = 3; i.func = ee_i_bc2tl; return i; } } break; case 0x02000000 >> 21: @@ -3190,61 +3416,61 @@ ee_instruction ee_decode(uint32_t opcode) { case 0x03C00000 >> 21: case 0x03E00000 >> 21: { switch (opcode & 0x0000003F) { - case 0x00000000: i.func = ee_i_vaddx; return i; - case 0x00000001: i.func = ee_i_vaddy; return i; - case 0x00000002: i.func = ee_i_vaddz; return i; - case 0x00000003: i.func = ee_i_vaddw; return i; - case 0x00000004: i.func = ee_i_vsubx; return i; - case 0x00000005: i.func = ee_i_vsuby; return i; - case 0x00000006: i.func = ee_i_vsubz; return i; - case 0x00000007: i.func = ee_i_vsubw; return i; - case 0x00000008: i.func = ee_i_vmaddx; return i; - case 0x00000009: i.func = ee_i_vmaddy; return i; - case 0x0000000A: i.func = ee_i_vmaddz; return i; - case 0x0000000B: i.func = ee_i_vmaddw; return i; - case 0x0000000C: i.func = ee_i_vmsubx; return i; - case 0x0000000D: i.func = ee_i_vmsuby; return i; - case 0x0000000E: i.func = ee_i_vmsubz; return i; - case 0x0000000F: i.func = ee_i_vmsubw; return i; - case 0x00000010: i.func = ee_i_vmaxx; return i; - case 0x00000011: i.func = ee_i_vmaxy; return i; - case 0x00000012: i.func = ee_i_vmaxz; return i; - case 0x00000013: i.func = ee_i_vmaxw; return i; - case 0x00000014: i.func = ee_i_vminix; return i; - case 0x00000015: i.func = ee_i_vminiy; return i; - case 0x00000016: i.func = ee_i_vminiz; return i; - case 0x00000017: i.func = ee_i_vminiw; return i; - case 0x00000018: i.func = ee_i_vmulx; return i; - case 0x00000019: i.func = ee_i_vmuly; return i; - case 0x0000001A: i.func = ee_i_vmulz; return i; - case 0x0000001B: i.func = ee_i_vmulw; return i; - case 0x0000001C: i.func = ee_i_vmulq; return i; - case 0x0000001D: i.func = ee_i_vmaxi; return i; - case 0x0000001E: i.func = ee_i_vmuli; return i; - case 0x0000001F: i.func = ee_i_vminii; return i; - case 0x00000020: i.func = ee_i_vaddq; return i; - case 0x00000021: i.func = ee_i_vmaddq; return i; - case 0x00000022: i.func = ee_i_vaddi; return i; - case 0x00000023: i.func = ee_i_vmaddi; return i; - case 0x00000024: i.func = ee_i_vsubq; return i; - case 0x00000025: i.func = ee_i_vmsubq; return i; - case 0x00000026: i.func = ee_i_vsubi; return i; - case 0x00000027: i.func = ee_i_vmsubi; return i; - case 0x00000028: i.func = ee_i_vadd; return i; - case 0x00000029: i.func = ee_i_vmadd; return i; - case 0x0000002A: i.func = ee_i_vmul; return i; - case 0x0000002B: i.func = ee_i_vmax; return i; - case 0x0000002C: i.func = ee_i_vsub; return i; - case 0x0000002D: i.func = ee_i_vmsub; return i; - case 0x0000002E: i.func = ee_i_vopmsub; return i; - case 0x0000002F: i.func = ee_i_vmini; return i; - case 0x00000030: i.func = ee_i_viadd; return i; - case 0x00000031: i.func = ee_i_visub; return i; - case 0x00000032: i.func = ee_i_viaddi; return i; - case 0x00000034: i.func = ee_i_viand; return i; - case 0x00000035: i.func = ee_i_vior; return i; - case 0x00000038: i.func = ee_i_vcallms; return i; - case 0x00000039: i.func = ee_i_vcallmsr; return i; + case 0x00000000: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vaddx; return i; + case 0x00000001: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vaddy; return i; + case 0x00000002: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vaddz; return i; + case 0x00000003: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vaddw; return i; + case 0x00000004: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vsubx; return i; + case 0x00000005: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vsuby; return i; + case 0x00000006: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vsubz; return i; + case 0x00000007: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vsubw; return i; + case 0x00000008: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmaddx; return i; + case 0x00000009: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmaddy; return i; + case 0x0000000A: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmaddz; return i; + case 0x0000000B: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmaddw; return i; + case 0x0000000C: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmsubx; return i; + case 0x0000000D: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmsuby; return i; + case 0x0000000E: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmsubz; return i; + case 0x0000000F: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmsubw; return i; + case 0x00000010: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmaxx; return i; + case 0x00000011: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmaxy; return i; + case 0x00000012: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmaxz; return i; + case 0x00000013: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmaxw; return i; + case 0x00000014: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vminix; return i; + case 0x00000015: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vminiy; return i; + case 0x00000016: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vminiz; return i; + case 0x00000017: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vminiw; return i; + case 0x00000018: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmulx; return i; + case 0x00000019: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmuly; return i; + case 0x0000001A: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmulz; return i; + case 0x0000001B: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmulw; return i; + case 0x0000001C: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmulq; return i; + case 0x0000001D: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmaxi; return i; + case 0x0000001E: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmuli; return i; + case 0x0000001F: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vminii; return i; + case 0x00000020: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vaddq; return i; + case 0x00000021: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmaddq; return i; + case 0x00000022: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vaddi; return i; + case 0x00000023: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmaddi; return i; + case 0x00000024: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vsubq; return i; + case 0x00000025: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmsubq; return i; + case 0x00000026: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vsubi; return i; + case 0x00000027: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmsubi; return i; + case 0x00000028: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vadd; return i; + case 0x00000029: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmadd; return i; + case 0x0000002A: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmul; return i; + case 0x0000002B: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmax; return i; + case 0x0000002C: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vsub; return i; + case 0x0000002D: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmsub; return i; + case 0x0000002E: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vopmsub; return i; + case 0x0000002F: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmini; return i; + case 0x00000030: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_viadd; return i; + case 0x00000031: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_visub; return i; + case 0x00000032: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_viaddi; return i; + case 0x00000034: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_viand; return i; + case 0x00000035: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vior; return i; + case 0x00000038: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vcallms; return i; + case 0x00000039: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vcallmsr; return i; case 0x0000003C: case 0x0000003D: case 0x0000003E: @@ -3252,237 +3478,237 @@ ee_instruction ee_decode(uint32_t opcode) { uint32_t func = (opcode & 3) | ((opcode & 0x7c0) >> 4); switch (func) { - case 0x00000000: i.func = ee_i_vaddax; return i; - case 0x00000001: i.func = ee_i_vadday; return i; - case 0x00000002: i.func = ee_i_vaddaz; return i; - case 0x00000003: i.func = ee_i_vaddaw; return i; - case 0x00000004: i.func = ee_i_vsubax; return i; - case 0x00000005: i.func = ee_i_vsubay; return i; - case 0x00000006: i.func = ee_i_vsubaz; return i; - case 0x00000007: i.func = ee_i_vsubaw; return i; - case 0x00000008: i.func = ee_i_vmaddax; return i; - case 0x00000009: i.func = ee_i_vmadday; return i; - case 0x0000000A: i.func = ee_i_vmaddaz; return i; - case 0x0000000B: i.func = ee_i_vmaddaw; return i; - case 0x0000000C: i.func = ee_i_vmsubax; return i; - case 0x0000000D: i.func = ee_i_vmsubay; return i; - case 0x0000000E: i.func = ee_i_vmsubaz; return i; - case 0x0000000F: i.func = ee_i_vmsubaw; return i; - case 0x00000010: i.func = ee_i_vitof0; return i; - case 0x00000011: i.func = ee_i_vitof4; return i; - case 0x00000012: i.func = ee_i_vitof12; return i; - case 0x00000013: i.func = ee_i_vitof15; return i; - case 0x00000014: i.func = ee_i_vftoi0; return i; - case 0x00000015: i.func = ee_i_vftoi4; return i; - case 0x00000016: i.func = ee_i_vftoi12; return i; - case 0x00000017: i.func = ee_i_vftoi15; return i; - case 0x00000018: i.func = ee_i_vmulax; return i; - case 0x00000019: i.func = ee_i_vmulay; return i; - case 0x0000001A: i.func = ee_i_vmulaz; return i; - case 0x0000001B: i.func = ee_i_vmulaw; return i; - case 0x0000001C: i.func = ee_i_vmulaq; return i; - case 0x0000001D: i.func = ee_i_vabs; return i; - case 0x0000001E: i.func = ee_i_vmulai; return i; - case 0x0000001F: i.func = ee_i_vclipw; return i; - case 0x00000020: i.func = ee_i_vaddaq; return i; - case 0x00000021: i.func = ee_i_vmaddaq; return i; - case 0x00000022: i.func = ee_i_vaddai; return i; - case 0x00000023: i.func = ee_i_vmaddai; return i; - case 0x00000024: i.func = ee_i_vsubaq; return i; - case 0x00000025: i.func = ee_i_vmsubaq; return i; - case 0x00000026: i.func = ee_i_vsubai; return i; - case 0x00000027: i.func = ee_i_vmsubai; return i; - case 0x00000028: i.func = ee_i_vadda; return i; - case 0x00000029: i.func = ee_i_vmadda; return i; - case 0x0000002A: i.func = ee_i_vmula; return i; - case 0x0000002C: i.func = ee_i_vsuba; return i; - case 0x0000002D: i.func = ee_i_vmsuba; return i; - case 0x0000002E: i.func = ee_i_vopmula; return i; - case 0x0000002F: i.func = ee_i_vnop; return i; - case 0x00000030: i.func = ee_i_vmove; return i; - case 0x00000031: i.func = ee_i_vmr32; return i; - case 0x00000034: i.func = ee_i_vlqi; return i; - case 0x00000035: i.func = ee_i_vsqi; return i; - case 0x00000036: i.func = ee_i_vlqd; return i; - case 0x00000037: i.func = ee_i_vsqd; return i; - case 0x00000038: i.func = ee_i_vdiv; return i; - case 0x00000039: i.func = ee_i_vsqrt; return i; - case 0x0000003A: i.func = ee_i_vrsqrt; return i; - case 0x0000003B: i.func = ee_i_vwaitq; return i; - case 0x0000003C: i.func = ee_i_vmtir; return i; - case 0x0000003D: i.func = ee_i_vmfir; return i; - case 0x0000003E: i.func = ee_i_vilwr; return i; - case 0x0000003F: i.func = ee_i_viswr; return i; - case 0x00000040: i.func = ee_i_vrnext; return i; - case 0x00000041: i.func = ee_i_vrget; return i; - case 0x00000042: i.func = ee_i_vrinit; return i; - case 0x00000043: i.func = ee_i_vrxor; return i; + case 0x00000000: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vaddax; return i; + case 0x00000001: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vadday; return i; + case 0x00000002: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vaddaz; return i; + case 0x00000003: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vaddaw; return i; + case 0x00000004: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vsubax; return i; + case 0x00000005: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vsubay; return i; + case 0x00000006: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vsubaz; return i; + case 0x00000007: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vsubaw; return i; + case 0x00000008: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmaddax; return i; + case 0x00000009: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmadday; return i; + case 0x0000000A: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmaddaz; return i; + case 0x0000000B: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmaddaw; return i; + case 0x0000000C: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmsubax; return i; + case 0x0000000D: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmsubay; return i; + case 0x0000000E: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmsubaz; return i; + case 0x0000000F: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmsubaw; return i; + case 0x00000010: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vitof0; return i; + case 0x00000011: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vitof4; return i; + case 0x00000012: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vitof12; return i; + case 0x00000013: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vitof15; return i; + case 0x00000014: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vftoi0; return i; + case 0x00000015: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vftoi4; return i; + case 0x00000016: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vftoi12; return i; + case 0x00000017: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vftoi15; return i; + case 0x00000018: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmulax; return i; + case 0x00000019: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmulay; return i; + case 0x0000001A: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmulaz; return i; + case 0x0000001B: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmulaw; return i; + case 0x0000001C: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmulaq; return i; + case 0x0000001D: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vabs; return i; + case 0x0000001E: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmulai; return i; + case 0x0000001F: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vclipw; return i; + case 0x00000020: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vaddaq; return i; + case 0x00000021: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmaddaq; return i; + case 0x00000022: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vaddai; return i; + case 0x00000023: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmaddai; return i; + case 0x00000024: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vsubaq; return i; + case 0x00000025: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmsubaq; return i; + case 0x00000026: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vsubai; return i; + case 0x00000027: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmsubai; return i; + case 0x00000028: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vadda; return i; + case 0x00000029: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmadda; return i; + case 0x0000002A: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmula; return i; + case 0x0000002C: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vsuba; return i; + case 0x0000002D: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmsuba; return i; + case 0x0000002E: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vopmula; return i; + case 0x0000002F: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vnop; return i; + case 0x00000030: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmove; return i; + case 0x00000031: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmr32; return i; + case 0x00000034: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vlqi; return i; + case 0x00000035: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vsqi; return i; + case 0x00000036: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vlqd; return i; + case 0x00000037: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vsqd; return i; + case 0x00000038: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vdiv; return i; + case 0x00000039: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vsqrt; return i; + case 0x0000003A: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vrsqrt; return i; + case 0x0000003B: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vwaitq; return i; + case 0x0000003C: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmtir; return i; + case 0x0000003D: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vmfir; return i; + case 0x0000003E: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vilwr; return i; + case 0x0000003F: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_viswr; return i; + case 0x00000040: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vrnext; return i; + case 0x00000041: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vrget; return i; + case 0x00000042: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vrinit; return i; + case 0x00000043: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_vrxor; return i; } } break; } } break; } } break; - case 0x50000000 >> 26: i.branch = 3; i.func = ee_i_beql; return i; - case 0x54000000 >> 26: i.branch = 3; i.func = ee_i_bnel; return i; - case 0x58000000 >> 26: i.branch = 3; i.func = ee_i_blezl; return i; - case 0x5C000000 >> 26: i.branch = 3; i.func = ee_i_bgtzl; return i; - case 0x60000000 >> 26: i.branch = 4; i.func = ee_i_daddi; return i; - case 0x64000000 >> 26: i.func = ee_i_daddiu; return i; - case 0x68000000 >> 26: i.func = ee_i_ldl; return i; - case 0x6C000000 >> 26: i.func = ee_i_ldr; return i; + case 0x50000000 >> 26: i.cycles = EE_CYC_BRANCH; i.branch = 3; i.func = ee_i_beql; return i; + case 0x54000000 >> 26: i.cycles = EE_CYC_BRANCH; i.branch = 3; i.func = ee_i_bnel; return i; + case 0x58000000 >> 26: i.cycles = EE_CYC_BRANCH; i.branch = 3; i.func = ee_i_blezl; return i; + case 0x5C000000 >> 26: i.cycles = EE_CYC_BRANCH; i.branch = 3; i.func = ee_i_bgtzl; return i; + case 0x60000000 >> 26: i.cycles = EE_CYC_DEFAULT; i.branch = 4; i.func = ee_i_daddi; return i; + case 0x64000000 >> 26: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_daddiu; return i; + case 0x68000000 >> 26: i.cycles = EE_CYC_LOAD; i.func = ee_i_ldl; return i; + case 0x6C000000 >> 26: i.cycles = EE_CYC_LOAD; i.func = ee_i_ldr; return i; case 0x70000000 >> 26: { // mmi switch (opcode & 0x0000003F) { - case 0x00000000: i.func = ee_i_madd; return i; - case 0x00000001: i.func = ee_i_maddu; return i; - case 0x00000004: i.func = ee_i_plzcw; return i; + case 0x00000000: i.cycles = EE_CYC_MULT; i.func = ee_i_madd; return i; + case 0x00000001: i.cycles = EE_CYC_MULT; i.func = ee_i_maddu; return i; + case 0x00000004: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_plzcw; return i; case 0x00000008: { switch ((opcode & 0x000007C0) >> 6) { - case 0x00000000 >> 6: i.func = ee_i_paddw; return i; - case 0x00000040 >> 6: i.func = ee_i_psubw; return i; - case 0x00000080 >> 6: i.func = ee_i_pcgtw; return i; - case 0x000000C0 >> 6: i.func = ee_i_pmaxw; return i; - case 0x00000100 >> 6: i.func = ee_i_paddh; return i; - case 0x00000140 >> 6: i.func = ee_i_psubh; return i; - case 0x00000180 >> 6: i.func = ee_i_pcgth; return i; - case 0x000001C0 >> 6: i.func = ee_i_pmaxh; return i; - case 0x00000200 >> 6: i.func = ee_i_paddb; return i; - case 0x00000240 >> 6: i.func = ee_i_psubb; return i; - case 0x00000280 >> 6: i.func = ee_i_pcgtb; return i; - case 0x00000400 >> 6: i.func = ee_i_paddsw; return i; - case 0x00000440 >> 6: i.func = ee_i_psubsw; return i; - case 0x00000480 >> 6: i.func = ee_i_pextlw; return i; - case 0x000004C0 >> 6: i.func = ee_i_ppacw; return i; - case 0x00000500 >> 6: i.func = ee_i_paddsh; return i; - case 0x00000540 >> 6: i.func = ee_i_psubsh; return i; - case 0x00000580 >> 6: i.func = ee_i_pextlh; return i; - case 0x000005C0 >> 6: i.func = ee_i_ppach; return i; - case 0x00000600 >> 6: i.func = ee_i_paddsb; return i; - case 0x00000640 >> 6: i.func = ee_i_psubsb; return i; - case 0x00000680 >> 6: i.func = ee_i_pextlb; return i; - case 0x000006C0 >> 6: i.func = ee_i_ppacb; return i; - case 0x00000780 >> 6: i.func = ee_i_pext5; return i; - case 0x000007C0 >> 6: i.func = ee_i_ppac5; return i; + case 0x00000000 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_paddw; return i; + case 0x00000040 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_psubw; return i; + case 0x00000080 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pcgtw; return i; + case 0x000000C0 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pmaxw; return i; + case 0x00000100 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_paddh; return i; + case 0x00000140 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_psubh; return i; + case 0x00000180 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pcgth; return i; + case 0x000001C0 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pmaxh; return i; + case 0x00000200 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_paddb; return i; + case 0x00000240 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_psubb; return i; + case 0x00000280 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pcgtb; return i; + case 0x00000400 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_paddsw; return i; + case 0x00000440 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_psubsw; return i; + case 0x00000480 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pextlw; return i; + case 0x000004C0 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_ppacw; return i; + case 0x00000500 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_paddsh; return i; + case 0x00000540 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_psubsh; return i; + case 0x00000580 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pextlh; return i; + case 0x000005C0 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_ppach; return i; + case 0x00000600 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_paddsb; return i; + case 0x00000640 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_psubsb; return i; + case 0x00000680 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pextlb; return i; + case 0x000006C0 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_ppacb; return i; + case 0x00000780 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pext5; return i; + case 0x000007C0 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_ppac5; return i; } } break; case 0x00000009: { switch ((opcode & 0x000007C0) >> 6) { - case 0x00000000 >> 6: i.func = ee_i_pmaddw; return i; - case 0x00000080 >> 6: i.func = ee_i_psllvw; return i; - case 0x000000C0 >> 6: i.func = ee_i_psrlvw; return i; - case 0x00000100 >> 6: i.func = ee_i_pmsubw; return i; - case 0x00000200 >> 6: i.func = ee_i_pmfhi; return i; - case 0x00000240 >> 6: i.func = ee_i_pmflo; return i; - case 0x00000280 >> 6: i.func = ee_i_pinth; return i; - case 0x00000300 >> 6: i.func = ee_i_pmultw; return i; - case 0x00000340 >> 6: i.func = ee_i_pdivw; return i; - case 0x00000380 >> 6: i.func = ee_i_pcpyld; return i; - case 0x00000400 >> 6: i.func = ee_i_pmaddh; return i; - case 0x00000440 >> 6: i.func = ee_i_phmadh; return i; - case 0x00000480 >> 6: i.func = ee_i_pand; return i; - case 0x000004C0 >> 6: i.func = ee_i_pxor; return i; - case 0x00000500 >> 6: i.func = ee_i_pmsubh; return i; - case 0x00000540 >> 6: i.func = ee_i_phmsbh; return i; - case 0x00000680 >> 6: i.func = ee_i_pexeh; return i; - case 0x000006C0 >> 6: i.func = ee_i_prevh; return i; - case 0x00000700 >> 6: i.func = ee_i_pmulth; return i; - case 0x00000740 >> 6: i.func = ee_i_pdivbw; return i; - case 0x00000780 >> 6: i.func = ee_i_pexew; return i; - case 0x000007C0 >> 6: i.func = ee_i_prot3w; return i; + case 0x00000000 >> 6: i.cycles = EE_CYC_MMI_MULT; i.func = ee_i_pmaddw; return i; + case 0x00000080 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_psllvw; return i; + case 0x000000C0 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_psrlvw; return i; + case 0x00000100 >> 6: i.cycles = EE_CYC_MMI_MULT; i.func = ee_i_pmsubw; return i; + case 0x00000200 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pmfhi; return i; + case 0x00000240 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pmflo; return i; + case 0x00000280 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pinth; return i; + case 0x00000300 >> 6: i.cycles = EE_CYC_MMI_MULT; i.func = ee_i_pmultw; return i; + case 0x00000340 >> 6: i.cycles = EE_CYC_MMI_DIV; i.func = ee_i_pdivw; return i; + case 0x00000380 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pcpyld; return i; + case 0x00000400 >> 6: i.cycles = EE_CYC_MMI_MULT; i.func = ee_i_pmaddh; return i; + case 0x00000440 >> 6: i.cycles = EE_CYC_MMI_MULT; i.func = ee_i_phmadh; return i; + case 0x00000480 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pand; return i; + case 0x000004C0 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pxor; return i; + case 0x00000500 >> 6: i.cycles = EE_CYC_MMI_MULT; i.func = ee_i_pmsubh; return i; + case 0x00000540 >> 6: i.cycles = EE_CYC_MMI_MULT; i.func = ee_i_phmsbh; return i; + case 0x00000680 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pexeh; return i; + case 0x000006C0 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_prevh; return i; + case 0x00000700 >> 6: i.cycles = EE_CYC_MMI_MULT; i.func = ee_i_pmulth; return i; + case 0x00000740 >> 6: i.cycles = EE_CYC_MMI_DIV; i.func = ee_i_pdivbw; return i; + case 0x00000780 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pexew; return i; + case 0x000007C0 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_prot3w; return i; } } break; - case 0x00000010: i.func = ee_i_mfhi1; return i; - case 0x00000011: i.func = ee_i_mthi1; return i; - case 0x00000012: i.func = ee_i_mflo1; return i; - case 0x00000013: i.func = ee_i_mtlo1; return i; - case 0x00000018: i.func = ee_i_mult1; return i; - case 0x00000019: i.func = ee_i_multu1; return i; - case 0x0000001A: i.func = ee_i_div1; return i; - case 0x0000001B: i.func = ee_i_divu1; return i; - case 0x00000020: i.func = ee_i_madd1; return i; - case 0x00000021: i.func = ee_i_maddu1; return i; + case 0x00000010: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_mfhi1; return i; + case 0x00000011: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_mthi1; return i; + case 0x00000012: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_mflo1; return i; + case 0x00000013: i.cycles = EE_CYC_COP_DEFAULT; i.func = ee_i_mtlo1; return i; + case 0x00000018: i.cycles = EE_CYC_MULT; i.func = ee_i_mult1; return i; + case 0x00000019: i.cycles = EE_CYC_MULT; i.func = ee_i_multu1; return i; + case 0x0000001A: i.cycles = EE_CYC_DIV; i.func = ee_i_div1; return i; + case 0x0000001B: i.cycles = EE_CYC_DIV; i.func = ee_i_divu1; return i; + case 0x00000020: i.cycles = EE_CYC_MULT; i.func = ee_i_madd1; return i; + case 0x00000021: i.cycles = EE_CYC_MULT; i.func = ee_i_maddu1; return i; case 0x00000028: { switch ((opcode & 0x000007C0) >> 6) { - case 0x00000040 >> 6: i.func = ee_i_pabsw; return i; - case 0x00000080 >> 6: i.func = ee_i_pceqw; return i; - case 0x000000C0 >> 6: i.func = ee_i_pminw; return i; - case 0x00000100 >> 6: i.func = ee_i_padsbh; return i; - case 0x00000140 >> 6: i.func = ee_i_pabsh; return i; - case 0x00000180 >> 6: i.func = ee_i_pceqh; return i; - case 0x000001C0 >> 6: i.func = ee_i_pminh; return i; - case 0x00000280 >> 6: i.func = ee_i_pceqb; return i; - case 0x00000400 >> 6: i.func = ee_i_padduw; return i; - case 0x00000440 >> 6: i.func = ee_i_psubuw; return i; - case 0x00000480 >> 6: i.func = ee_i_pextuw; return i; - case 0x00000500 >> 6: i.func = ee_i_padduh; return i; - case 0x00000540 >> 6: i.func = ee_i_psubuh; return i; - case 0x00000580 >> 6: i.func = ee_i_pextuh; return i; - case 0x00000600 >> 6: i.func = ee_i_paddub; return i; - case 0x00000640 >> 6: i.func = ee_i_psubub; return i; - case 0x00000680 >> 6: i.func = ee_i_pextub; return i; - case 0x000006C0 >> 6: i.func = ee_i_qfsrv; return i; + case 0x00000040 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pabsw; return i; + case 0x00000080 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pceqw; return i; + case 0x000000C0 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pminw; return i; + case 0x00000100 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_padsbh; return i; + case 0x00000140 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pabsh; return i; + case 0x00000180 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pceqh; return i; + case 0x000001C0 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pminh; return i; + case 0x00000280 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pceqb; return i; + case 0x00000400 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_padduw; return i; + case 0x00000440 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_psubuw; return i; + case 0x00000480 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pextuw; return i; + case 0x00000500 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_padduh; return i; + case 0x00000540 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_psubuh; return i; + case 0x00000580 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pextuh; return i; + case 0x00000600 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_paddub; return i; + case 0x00000640 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_psubub; return i; + case 0x00000680 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pextub; return i; + case 0x000006C0 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_qfsrv; return i; } } break; case 0x00000029: { switch ((opcode & 0x000007C0) >> 6) { - case 0x00000000 >> 6: i.func = ee_i_pmadduw; return i; - case 0x000000C0 >> 6: i.func = ee_i_psravw; return i; - case 0x00000200 >> 6: i.func = ee_i_pmthi; return i; - case 0x00000240 >> 6: i.func = ee_i_pmtlo; return i; - case 0x00000280 >> 6: i.func = ee_i_pinteh; return i; - case 0x00000300 >> 6: i.func = ee_i_pmultuw; return i; - case 0x00000340 >> 6: i.func = ee_i_pdivuw; return i; - case 0x00000380 >> 6: i.func = ee_i_pcpyud; return i; - case 0x00000480 >> 6: i.func = ee_i_por; return i; - case 0x000004C0 >> 6: i.func = ee_i_pnor; return i; - case 0x00000680 >> 6: i.func = ee_i_pexch; return i; - case 0x000006C0 >> 6: i.func = ee_i_pcpyh; return i; - case 0x00000780 >> 6: i.func = ee_i_pexcw; return i; + case 0x00000000 >> 6: i.cycles = EE_CYC_MMI_MULT; i.func = ee_i_pmadduw; return i; + case 0x000000C0 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_psravw; return i; + case 0x00000200 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pmthi; return i; + case 0x00000240 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pmtlo; return i; + case 0x00000280 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pinteh; return i; + case 0x00000300 >> 6: i.cycles = EE_CYC_MMI_MULT; i.func = ee_i_pmultuw; return i; + case 0x00000340 >> 6: i.cycles = EE_CYC_MMI_DIV; i.func = ee_i_pdivuw; return i; + case 0x00000380 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pcpyud; return i; + case 0x00000480 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_por; return i; + case 0x000004C0 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pnor; return i; + case 0x00000680 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pexch; return i; + case 0x000006C0 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pcpyh; return i; + case 0x00000780 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pexcw; return i; } } break; case 0x00000030: { switch ((opcode & 0x000007C0) >> 6) { - case 0x00000000 >> 6: i.func = ee_i_pmfhllw; return i; - case 0x00000040 >> 6: i.func = ee_i_pmfhluw; return i; - case 0x00000080 >> 6: i.func = ee_i_pmfhlslw; return i; - case 0x000000c0 >> 6: i.func = ee_i_pmfhllh; return i; - case 0x00000100 >> 6: i.func = ee_i_pmfhlsh; return i; + case 0x00000000 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pmfhllw; return i; + case 0x00000040 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pmfhluw; return i; + case 0x00000080 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pmfhlslw; return i; + case 0x000000c0 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pmfhllh; return i; + case 0x00000100 >> 6: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pmfhlsh; return i; } } break; - case 0x00000031: i.func = ee_i_pmthl; return i; - case 0x00000034: i.func = ee_i_psllh; return i; - case 0x00000036: i.func = ee_i_psrlh; return i; - case 0x00000037: i.func = ee_i_psrah; return i; - case 0x0000003C: i.func = ee_i_psllw; return i; - case 0x0000003E: i.func = ee_i_psrlw; return i; - case 0x0000003F: i.func = ee_i_psraw; return i; + case 0x00000031: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_pmthl; return i; + case 0x00000034: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_psllh; return i; + case 0x00000036: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_psrlh; return i; + case 0x00000037: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_psrah; return i; + case 0x0000003C: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_psllw; return i; + case 0x0000003E: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_psrlw; return i; + case 0x0000003F: i.cycles = EE_CYC_MMI_DEFAULT; i.func = ee_i_psraw; return i; } } break; - case 0x78000000 >> 26: i.func = ee_i_lq; return i; - case 0x7C000000 >> 26: i.func = ee_i_sq; return i; - case 0x80000000 >> 26: i.func = ee_i_lb; return i; - case 0x84000000 >> 26: i.func = ee_i_lh; return i; - case 0x88000000 >> 26: i.func = ee_i_lwl; return i; - case 0x8C000000 >> 26: i.func = ee_i_lw; return i; - case 0x90000000 >> 26: i.func = ee_i_lbu; return i; - case 0x94000000 >> 26: i.func = ee_i_lhu; return i; - case 0x98000000 >> 26: i.func = ee_i_lwr; return i; - case 0x9C000000 >> 26: i.func = ee_i_lwu; return i; - case 0xA0000000 >> 26: i.func = ee_i_sb; return i; - case 0xA4000000 >> 26: i.func = ee_i_sh; return i; - case 0xA8000000 >> 26: i.func = ee_i_swl; return i; - case 0xAC000000 >> 26: i.func = ee_i_sw; return i; - case 0xB0000000 >> 26: i.func = ee_i_sdl; return i; - case 0xB4000000 >> 26: i.func = ee_i_sdr; return i; - case 0xB8000000 >> 26: i.func = ee_i_swr; return i; - case 0xBC000000 >> 26: i.func = ee_i_cache; return i; - case 0xC4000000 >> 26: i.func = ee_i_lwc1; return i; - case 0xCC000000 >> 26: i.func = ee_i_pref; return i; - case 0xD8000000 >> 26: i.func = ee_i_lqc2; return i; - case 0xDC000000 >> 26: i.func = ee_i_ld; return i; - case 0xE4000000 >> 26: i.func = ee_i_swc1; return i; - case 0xF8000000 >> 26: i.func = ee_i_sqc2; return i; - case 0xFC000000 >> 26: i.func = ee_i_sd; return i; + case 0x78000000 >> 26: i.cycles = EE_CYC_LOAD; i.func = ee_i_lq; return i; + case 0x7C000000 >> 26: i.cycles = EE_CYC_LOAD; i.func = ee_i_sq; return i; + case 0x80000000 >> 26: i.cycles = EE_CYC_LOAD; i.func = ee_i_lb; return i; + case 0x84000000 >> 26: i.cycles = EE_CYC_LOAD; i.func = ee_i_lh; return i; + case 0x88000000 >> 26: i.cycles = EE_CYC_LOAD; i.func = ee_i_lwl; return i; + case 0x8C000000 >> 26: i.cycles = EE_CYC_LOAD; i.func = ee_i_lw; return i; + case 0x90000000 >> 26: i.cycles = EE_CYC_LOAD; i.func = ee_i_lbu; return i; + case 0x94000000 >> 26: i.cycles = EE_CYC_LOAD; i.func = ee_i_lhu; return i; + case 0x98000000 >> 26: i.cycles = EE_CYC_LOAD; i.func = ee_i_lwr; return i; + case 0x9C000000 >> 26: i.cycles = EE_CYC_LOAD; i.func = ee_i_lwu; return i; + case 0xA0000000 >> 26: i.cycles = EE_CYC_STORE; i.func = ee_i_sb; return i; + case 0xA4000000 >> 26: i.cycles = EE_CYC_STORE; i.func = ee_i_sh; return i; + case 0xA8000000 >> 26: i.cycles = EE_CYC_STORE; i.func = ee_i_swl; return i; + case 0xAC000000 >> 26: i.cycles = EE_CYC_STORE; i.func = ee_i_sw; return i; + case 0xB0000000 >> 26: i.cycles = EE_CYC_STORE; i.func = ee_i_sdl; return i; + case 0xB4000000 >> 26: i.cycles = EE_CYC_STORE; i.func = ee_i_sdr; return i; + case 0xB8000000 >> 26: i.cycles = EE_CYC_STORE; i.func = ee_i_swr; return i; + case 0xBC000000 >> 26: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_cache; return i; + case 0xC4000000 >> 26: i.cycles = EE_CYC_LOAD; i.func = ee_i_lwc1; return i; + case 0xCC000000 >> 26: i.cycles = EE_CYC_DEFAULT; i.func = ee_i_pref; return i; + case 0xD8000000 >> 26: i.cycles = EE_CYC_LOAD; i.func = ee_i_lqc2; return i; + case 0xDC000000 >> 26: i.cycles = EE_CYC_LOAD; i.func = ee_i_ld; return i; + case 0xE4000000 >> 26: i.cycles = EE_CYC_STORE; i.func = ee_i_swc1; return i; + case 0xF8000000 >> 26: i.cycles = EE_CYC_STORE; i.func = ee_i_sqc2; return i; + case 0xFC000000 >> 26: i.cycles = EE_CYC_STORE; i.func = ee_i_sd; return i; } i.func = ee_i_invalid; @@ -3491,14 +3717,27 @@ ee_instruction ee_decode(uint32_t opcode) { } int ee_run_block(struct ee_state* ee, int max_cycles) { - // This is the entrypoint to the EENULL process. + // This is the entrypoint to the EENULL thread. // If we hit this address, the program is basically idling // so we "fast-forward" 1024 cycles if (ee->pc == 0x81fc0) { ee_check_irq(ee); - ee->total_cycles += 1024; - ee->count += 1024; + ee->total_cycles += 8 * 128; + ee->count += 8 * 128; + // ee->eenull_counter += 8 * 64; + + return 8 * 128; + } + + if (ee->intc_reads >= 10000) { + ee_check_irq(ee); + + return 1024; + } + + if (ee->csr_reads >= 1000) { + ee_check_irq(ee); return 1024; } @@ -3510,7 +3749,7 @@ int ee_run_block(struct ee_state* ee, int max_cycles) { int cycles = 0; - for (const auto& i : block) { + for (const auto& i : block.instructions) { ee->delay_slot = ee->branch; ee->branch = 0; @@ -3518,17 +3757,19 @@ int ee_run_block(struct ee_state* ee, int max_cycles) { if (ee_check_irq(ee)) break; - cycles++; + // if (ee->pc >= 0x81fc0 && ee->pc <= 0x81fdc) { + // ee->eenull_counter++; + // } ee->pc = ee->next_pc; ee->next_pc += 4; i.func(ee, i); + ee->count++; ee->r[0] = { 0 }; - ++ee->total_cycles; - ++ee->count; + cycles++; // An exception occurred or likely branch was taken // break immediately and clear the exception flag @@ -3546,14 +3787,11 @@ int ee_run_block(struct ee_state* ee, int max_cycles) { uint32_t pc = ee->pc; uint32_t block_pc = ee->pc; - - std::vector block; - - block.reserve(max_cycles); - - int prev_branch = 0; - ee_instruction i; + ee_block block; + + block.cycles = 0; + block.instructions.reserve(max_cycles); while (max_cycles) { ee->opcode = bus_read32(ee, pc); @@ -3561,14 +3799,16 @@ int ee_run_block(struct ee_state* ee, int max_cycles) { if (ee->opcode != 0) { i = ee_decode(ee->opcode); - block.push_back(i); + block.instructions.push_back(i); } else { i.func = ee_i_nop; i.branch = 0; - block.push_back(i); + block.instructions.push_back(i); } + block.cycles += i.cycles; + if (i.branch == 1 || i.branch == 3) { max_cycles = 2; } else if (i.branch != 0) { @@ -3595,4 +3835,12 @@ struct ps2_ram* ee_get_spr(struct ee_state* ee) { void ee_set_fmv_skip(struct ee_state* ee, int v) { ee->fmv_skip = v; +} + +void ee_reset_intc_reads(struct ee_state* ee) { + ee->intc_reads = 0; +} + +void ee_reset_csr_reads(struct ee_state* ee) { + ee->csr_reads = 0; } \ No newline at end of file diff --git a/src/ee/ee_def.hpp b/src/ee/ee_def.hpp index 5b8fbe7..07d4482 100644 --- a/src/ee/ee_def.hpp +++ b/src/ee/ee_def.hpp @@ -21,6 +21,19 @@ #define EE_ALIGNED16 #endif +#define EE_CYC_DEFAULT 9 +#define EE_CYC_BRANCH 11 +#define EE_CYC_COP_DEFAULT 7 +#define EE_CYC_MULT 2*8 +#define EE_CYC_DIV 14*8 +#define EE_CYC_MMI_MULT 3*8 +#define EE_CYC_MMI_DIV 22*8 +#define EE_CYC_MMI_DEFAULT 14 +#define EE_CYC_FPU_MULT 4*8 +#define EE_CYC_FPU_DIV 6*8 +#define EE_CYC_STORE 14 +#define EE_CYC_LOAD 14 + struct ee_instruction { uint32_t opcode; int32_t rs; @@ -37,16 +50,22 @@ struct ee_instruction { // 3 - likely branch // 4 - conditional exception int branch; + int cycles; void (*func)(struct ee_state*, const ee_instruction&); }; +struct ee_block { + std::vector instructions; + uint32_t cycles; +}; + struct ee_state { struct ee_bus_s bus; uint32_t block_pc; - std::unordered_map > block_cache; + std::unordered_map block_cache; uint128_t r[32] EE_ALIGNED16; uint128_t hi EE_ALIGNED16; @@ -119,6 +138,10 @@ struct ee_state { struct vu_state* vu1; struct ee_vtlb_entry vtlb[48]; + + int eenull_counter; + int csr_reads; + int intc_reads; }; #define THS_RUN 0x01 diff --git a/src/ee/gif.c b/src/ee/gif.c index 9dc9e9e..a797d95 100644 --- a/src/ee/gif.c +++ b/src/ee/gif.c @@ -109,7 +109,13 @@ uint64_t ps2_gif_read32(struct ps2_gif* gif, uint32_t addr) { void ps2_gif_write32(struct ps2_gif* gif, uint32_t addr, uint64_t data) { switch (addr) { - case 0x10003000: gif->ctrl = data; return; + case 0x10003000: { + if (data & 1) { + ps2_gif_init(gif, gif->vu1, gif->gs); + } + + printf("gif: ctrl=%08x\n", data); + } return; case 0x10003010: gif->mode = data; return; } } @@ -191,8 +197,8 @@ void gif_handle_tag(struct ps2_gif* gif, uint128_t data) { } break; } - // printf("giftag: nloop=%04lx eop=%d prim=%d fmt=%d nregs=%d reg=%016lx\n", - // gif->tag.nloop, gif->tag.eop, gif->tag.prim, gif->tag.fmt, gif->tag.nregs, gif->tag.reg + // printf("giftag: nloop=%04lx eop=%d prim=%04x (pre=%d) fmt=%d nregs=%d reg=%08x%08x\n", + // gif->tag.nloop, gif->tag.eop, gif->tag.prim, gif->tag.pre, gif->tag.fmt, gif->tag.nregs, gif->tag.reg >> 32, gif->tag.reg & 0xffffffff // ); if (gif->tag.pre) { @@ -213,7 +219,7 @@ void gif_handle_packed(struct ps2_gif* gif, uint128_t data) { case 0x01: /* printf("gif: RGBAQ <- %016lx\n", data.u64[0]); */ gif_write_rgbaq(gif, data); break; case 0x02: /* printf("gif: STQ <- %016lx\n", data.u64[0]); */ gif_write_stq(gif, data); break; case 0x03: /* printf("gif: UV <- %016lx\n", data.u64[0]); */ gif_write_uv(gif, data); break; - case 0x04: /* printf("gif: XYZF23 <- %016lx\n", data.u64[0]); */ gif_write_xyzf23(gif, data); break; + case 0x04: /* printf("gif: XYZF23 <- %08x%08x %08x%08x\n", data.u32[3], data.u32[2], data.u32[1], data.u32[0]); */ gif_write_xyzf23(gif, data); break; case 0x05: /* printf("gif: XYZ23 <- %016lx\n", data.u64[0]); */ gif_write_xyz23(gif, data); break; case 0x06: /* printf("gif: TEX0_1 <- %016lx\n", data.u64[0]); */ ps2_gs_write_internal(gif->gs, GS_TEX0_1, data.u64[0]); break; case 0x07: /* printf("gif: TEX0_2 <- %016lx\n", data.u64[0]); */ ps2_gs_write_internal(gif->gs, GS_TEX0_2, data.u64[0]); break; @@ -273,11 +279,8 @@ void gif_handle_reglist(struct ps2_gif* gif, uint128_t data) { } // Note: This handles odd NREGS*NLOOP case - if (gif->tag.index == gif->tag.remaining) { - gif->state = GIF_STATE_RECV_TAG; - + if (gif->tag.index == gif->tag.remaining) break; - } } gif->tag.qwc--; diff --git a/src/ee/intc.c b/src/ee/intc.c index 42f1975..1de9bd9 100644 --- a/src/ee/intc.c +++ b/src/ee/intc.c @@ -101,6 +101,24 @@ void ps2_intc_write64(struct ps2_intc* intc, uint32_t addr, uint64_t data) { void ps2_intc_irq(struct ps2_intc* intc, int dev) { intc->stat |= 1 << dev; + static const char* dev_names[] = { + "GS", + "SBUS", + "VBLANK_IN", + "VBLANK_OUT", + "VIF0", + "VIF1", + "VU0", + "VU1", + "IPU", + "TIMER0", + "TIMER1", + "TIMER2", + "TIMER3", + "SFIFO", + "VU0_WD" + }; + struct sched_event event; event.callback = intc_check_irq_event; @@ -108,5 +126,8 @@ void ps2_intc_irq(struct ps2_intc* intc, int dev) { event.name = "INTC IRQ check"; event.udata = intc; + // Notify EE that an interrupt has occurred + ee_reset_intc_reads(intc->ee); + sched_schedule(intc->sched, event); } \ No newline at end of file diff --git a/src/ee/timers.c b/src/ee/timers.c index 6f549ef..4ceb61b 100644 --- a/src/ee/timers.c +++ b/src/ee/timers.c @@ -113,6 +113,9 @@ static inline void ee_timers_write_mode(struct ps2_ee_timers* timers, int t, uin timer->cmpe = (data >> 8) & 1; timer->ovfe = (data >> 9) & 1; + if (!timer->cue) + return; + if (timer->gate) { printf("timers: Timer %d gate write %08x\n", t, data); diff --git a/src/ee/vif.c b/src/ee/vif.c index d6e315d..4e3c93d 100644 --- a/src/ee/vif.c +++ b/src/ee/vif.c @@ -6,7 +6,7 @@ #include "vif.h" -// #define printf(fmt, ...)(0) +#define printf(fmt, ...)(0) struct ps2_vif* ps2_vif_create(void) { return malloc(sizeof(struct ps2_vif)); @@ -185,6 +185,18 @@ static inline void vif_handle_fifo_write(struct ps2_vif* vif, uint32_t data) { // printf("vif%d: FLUSHE\n", vif->id); } break; case VIF_CMD_FLUSH: { + // Note: MASSIVE GRAN TURISMO HACK! + // GT3/4 expect IBT and stall bits to be set when a + // VIF IRQ occurs, CODE also needs to be set to the + // last command that caused a stall. + // This is admittedly a huge hack, but we can't really + // emulate any of this without properly implementing + // DMA timings. + if (data & 0x80000000) { + vif->stat |= 0x00000c02; + vif->stat ^= 0x0f000000; + vif->code = data; + } // printf("vif%d: FLUSH\n", vif->id); } break; case VIF_CMD_FLUSHA: { @@ -269,7 +281,7 @@ static inline void vif_handle_fifo_write(struct ps2_vif* vif, uint32_t data) { vif->shift = 0; } break; case VIF_CMD_DIRECT: { - //printf("vif%d: DIRECT(%04x)\n", vif->id, data & 0xffff); + // fprintf(stdout, "vif%d: DIRECT(%04x)\n", vif->id, data & 0xffff); int imm = data & 0xffff; @@ -282,7 +294,7 @@ static inline void vif_handle_fifo_write(struct ps2_vif* vif, uint32_t data) { vif->shift = 0; } break; case VIF_CMD_DIRECTHL: { - // printf("vif%d: DIRECTHL(%04x)\n", vif->id, data & 0xffff); + // fprintf(stdout, "vif%d: DIRECTHL(%04x)\n", vif->id, data & 0xffff); int imm = data & 0xffff; @@ -346,7 +358,7 @@ static inline void vif_handle_fifo_write(struct ps2_vif* vif, uint32_t data) { vif->shift = 0; vif->addr = addr; - // printf("vif%d: UNPACK %02x fmt=%02x flg=%d num=%02x addr=%08x tops=%08x usn=%d wr=%d mode=%d\n", vif->id, data >> 24, vif->unpack_fmt, flg, vif->unpack_num, addr, vif->tops, vif->unpack_usn, vif->pending_words, vif->mode); + // fprintf(stdout, "vif%d: UNPACK %02x fmt=%02x flg=%d num=%02x addr=%08x tops=%08x usn=%d wr=%d mode=%d\n", vif->id, data >> 24, vif->unpack_fmt, flg, vif->unpack_num, addr, vif->tops, vif->unpack_usn, vif->pending_words, vif->mode); } break; default: { // printf("vif%d: Unhandled command %02x\n", vif->id, vif->cmd); @@ -375,12 +387,13 @@ static inline void vif_handle_fifo_write(struct ps2_vif* vif, uint32_t data) { } } break; case VIF_CMD_MPG: { - // printf("vif%d: Writing %08x to MicroMem\n", vif->id, data); - if (!vif->shift) { vif->data.u32[vif->shift++] = data; } else { vif->data.u32[1] = data; + + // fprintf(stdout, "vif%d: Writing %08x %08x to MicroMem addr=%04x\n", vif->id, vif->data.u32[0], vif->data.u32[1], vif->addr); + vif->vu->micro_mem[(vif->addr++) & 0x7ff] = vif->data.u64[0]; vif->shift = 0; } @@ -393,13 +406,18 @@ static inline void vif_handle_fifo_write(struct ps2_vif* vif, uint32_t data) { case VIF_CMD_DIRECT: { vif->data.u32[vif->shift++] = data; + vif->pending_words--; + if (vif->shift == 4) { + // fprintf(stdout, "vif%d: Writing %08x %08x %08x %08x to GIF FIFO pending=%d\n", vif->id, vif->data.u32[3], vif->data.u32[2], vif->data.u32[1], vif->data.u32[0], vif->pending_words); ee_bus_write128(vif->bus, 0x10006000, vif->data); vif->shift = 0; } - if (!(--vif->pending_words)) { + if (!vif->pending_words) { + // fprintf(stdout, "vif%d: DIRECT complete\n", vif->id); + vif->state = VIF_IDLE; } } break; @@ -805,7 +823,11 @@ uint64_t ps2_vif_read32(struct ps2_vif* vif, uint32_t addr) { case 0x10003970: return vif->c[3]; // VIF1 registers - case 0x10003c00: return vif->stat; + case 0x10003c00: { + uint32_t stat = vif->stat; vif->stat = 0; + + return stat; + } break; case 0x10003c10: return vif->fbrst; case 0x10003c20: return vif->err; case 0x10003c30: return vif->mark; @@ -877,15 +899,15 @@ void ps2_vif_write32(struct ps2_vif* vif, uint32_t addr, uint64_t data) { default: { printf("vif%d: Unhandled 32-bit write to %08x\n", vif->id, addr); - exit(1); + // exit(1); } break; } } uint128_t ps2_vif_read128(struct ps2_vif* vif, uint32_t addr) { switch (addr) { - case 0x10004000: // printf("vif%d: 128-bit FIFO read\n", vif->id); exit(1); break; - case 0x10005000: // printf("vif%d: 128-bit FIFO read\n", vif->id); exit(1); break; + case 0x10004000: break; // printf("vif%d: 128-bit FIFO read\n", vif->id); exit(1); break; + case 0x10005000: break; // printf("vif%d: 128-bit FIFO read\n", vif->id); exit(1); break; default: { printf("vif%d: Unhandled 128-bit read to %08x\n", vif->id, addr); diff --git a/src/ee/vu.c b/src/ee/vu.c index d59eac9..fcd80d3 100644 --- a/src/ee/vu.c +++ b/src/ee/vu.c @@ -9,34 +9,24 @@ // #define printf(fmt, ...)(0) -#define VU_LD_DEST ((vu->lower >> 21) & 0xf) -#define VU_LD_DI(i) (vu->lower & (1 << (24 - i))) -#define VU_LD_DX ((vu->lower >> 24) & 1) -#define VU_LD_DY ((vu->lower >> 23) & 1) -#define VU_LD_DZ ((vu->lower >> 22) & 1) -#define VU_LD_DW ((vu->lower >> 21) & 1) -#define VU_LD_D ((vu->lower >> 6) & 0x1f) -#define VU_LD_S ((vu->lower >> 11) & 0x1f) -#define VU_LD_T ((vu->lower >> 16) & 0x1f) -#define VU_LD_SF ((vu->lower >> 21) & 3) -#define VU_LD_TF ((vu->lower >> 23) & 3) -#define VU_LD_IMM5 (((int32_t)(VU_LD_D << 27)) >> 27) -#define VU_LD_IMM11 (((int32_t)((vu->lower & 0x7ff) << 21)) >> 21) -#define VU_LD_IMM12 ((((vu->lower >> 21) & 0x1) << 11) | (vu->lower & 0x7ff)) -#define VU_LD_IMM15 ((vu->lower & 0x7ff) | ((vu->lower & 0x1e00000) >> 10)) -#define VU_LD_IMM24 (vu->lower & 0xffffff) +#define VU_LD_DI(i) (ins->ld_di[i]) +#define VU_LD_D (ins->ld_d) +#define VU_LD_S (ins->ld_s) +#define VU_LD_T (ins->ld_t) +#define VU_LD_SF (ins->ld_sf) +#define VU_LD_TF (ins->ld_tf) +#define VU_LD_IMM5 (ins->ld_imm5) +#define VU_LD_IMM11 (ins->ld_imm11) +#define VU_LD_IMM12 (ins->ld_imm12) +#define VU_LD_IMM15 (ins->ld_imm15) +#define VU_LD_IMM24 (ins->ld_imm24) #define VU_ID vu->vi[VU_LD_D] #define VU_IS vu->vi[VU_LD_S] #define VU_IT vu->vi[VU_LD_T] -#define VU_UD_DEST ((vu->upper >> 21) & 0xf) -#define VU_UD_DI(i) (vu->upper & (1 << (24 - i))) -#define VU_UD_DX ((vu->upper >> 24) & 1) -#define VU_UD_DY ((vu->upper >> 23) & 1) -#define VU_UD_DZ ((vu->upper >> 22) & 1) -#define VU_UD_DW ((vu->upper >> 21) & 1) -#define VU_UD_D ((vu->upper >> 6) & 0x1f) -#define VU_UD_S ((vu->upper >> 11) & 0x1f) -#define VU_UD_T ((vu->upper >> 16) & 0x1f) +#define VU_UD_DI(i) (ins->ud_di[i]) +#define VU_UD_D (ins->ud_d) +#define VU_UD_S (ins->ud_s) +#define VU_UD_T (ins->ud_t) struct vu_state* vu_create(void) { return (struct vu_state*)malloc(sizeof(struct vu_state)); @@ -262,12 +252,14 @@ static inline void vu_mem_write(struct vu_state* vu, uint32_t addr, uint32_t dat } else if (addr == 0x43a) { vu->vu1->tpc = data; } else { - printf("vu: oob write\n"); + // printf("vu: oob write\n"); - exit(1); + // exit(1); } } } else { + // if (addr == 0x0000013d) *(int*)0 = 0; + vu->vu_mem[addr & 0x3ff].u32[i] = data; } } @@ -314,7 +306,7 @@ static inline uint128_t vu_mem_read(struct vu_state* vu, uint32_t addr) { } // Upper pipeline -void vu_i_abs(struct vu_state* vu) { +void vu_i_abs(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -322,7 +314,7 @@ void vu_i_abs(struct vu_state* vu) { if (VU_UD_DI(i)) vu_set_vf(vu, t, i, fabsf(vu_vf_i(vu, s, i))); } } -void vu_i_add(struct vu_state* vu) { +void vu_i_add(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int d = VU_UD_D; int t = VU_UD_T; @@ -339,7 +331,7 @@ void vu_i_add(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_addi(struct vu_state* vu) { +void vu_i_addi(struct vu_state* vu, const struct vu_instruction* ins) { int d = VU_UD_D; int s = VU_UD_S; @@ -355,7 +347,7 @@ void vu_i_addi(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_addq(struct vu_state* vu) { +void vu_i_addq(struct vu_state* vu, const struct vu_instruction* ins) { int d = VU_UD_D; int s = VU_UD_S; @@ -371,7 +363,7 @@ void vu_i_addq(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_addx(struct vu_state* vu) { +void vu_i_addx(struct vu_state* vu, const struct vu_instruction* ins) { int d = VU_UD_D; int s = VU_UD_S; int t = VU_UD_T; @@ -390,7 +382,7 @@ void vu_i_addx(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_addy(struct vu_state* vu) { +void vu_i_addy(struct vu_state* vu, const struct vu_instruction* ins) { int d = VU_UD_D; int s = VU_UD_S; int t = VU_UD_T; @@ -409,7 +401,7 @@ void vu_i_addy(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_addz(struct vu_state* vu) { +void vu_i_addz(struct vu_state* vu, const struct vu_instruction* ins) { int d = VU_UD_D; int s = VU_UD_S; int t = VU_UD_T; @@ -428,7 +420,7 @@ void vu_i_addz(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_addw(struct vu_state* vu) { +void vu_i_addw(struct vu_state* vu, const struct vu_instruction* ins) { int d = VU_UD_D; int s = VU_UD_S; int t = VU_UD_T; @@ -447,7 +439,7 @@ void vu_i_addw(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_adda(struct vu_state* vu) { +void vu_i_adda(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -463,7 +455,7 @@ void vu_i_adda(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_addai(struct vu_state* vu) { +void vu_i_addai(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; for (int i = 0; i < 4; i++) { @@ -478,9 +470,8 @@ void vu_i_addai(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_addaq(struct vu_state* vu) { +void vu_i_addaq(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; - int t = VU_UD_T; for (int i = 0; i < 4; i++) { if (VU_UD_DI(i)) { @@ -494,7 +485,7 @@ void vu_i_addaq(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_addax(struct vu_state* vu) { +void vu_i_addax(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -512,7 +503,7 @@ void vu_i_addax(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_adday(struct vu_state* vu) { +void vu_i_adday(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -530,7 +521,7 @@ void vu_i_adday(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_addaz(struct vu_state* vu) { +void vu_i_addaz(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -548,7 +539,7 @@ void vu_i_addaz(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_addaw(struct vu_state* vu) { +void vu_i_addaw(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -566,7 +557,7 @@ void vu_i_addaw(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_sub(struct vu_state* vu) { +void vu_i_sub(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int d = VU_UD_D; int t = VU_UD_T; @@ -583,7 +574,7 @@ void vu_i_sub(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_subi(struct vu_state* vu) { +void vu_i_subi(struct vu_state* vu, const struct vu_instruction* ins) { int d = VU_UD_D; int s = VU_UD_S; @@ -599,7 +590,7 @@ void vu_i_subi(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_subq(struct vu_state* vu) { +void vu_i_subq(struct vu_state* vu, const struct vu_instruction* ins) { int d = VU_UD_D; int s = VU_UD_S; @@ -615,7 +606,7 @@ void vu_i_subq(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_subx(struct vu_state* vu) { +void vu_i_subx(struct vu_state* vu, const struct vu_instruction* ins) { int d = VU_UD_D; int s = VU_UD_S; int t = VU_UD_T; @@ -634,7 +625,7 @@ void vu_i_subx(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_suby(struct vu_state* vu) { +void vu_i_suby(struct vu_state* vu, const struct vu_instruction* ins) { int d = VU_UD_D; int s = VU_UD_S; int t = VU_UD_T; @@ -653,7 +644,7 @@ void vu_i_suby(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_subz(struct vu_state* vu) { +void vu_i_subz(struct vu_state* vu, const struct vu_instruction* ins) { int d = VU_UD_D; int s = VU_UD_S; int t = VU_UD_T; @@ -672,7 +663,7 @@ void vu_i_subz(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_subw(struct vu_state* vu) { +void vu_i_subw(struct vu_state* vu, const struct vu_instruction* ins) { int d = VU_UD_D; int s = VU_UD_S; int t = VU_UD_T; @@ -691,7 +682,7 @@ void vu_i_subw(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_suba(struct vu_state* vu) { +void vu_i_suba(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -707,7 +698,7 @@ void vu_i_suba(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_subai(struct vu_state* vu) { +void vu_i_subai(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; for (int i = 0; i < 4; i++) { @@ -722,9 +713,8 @@ void vu_i_subai(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_subaq(struct vu_state* vu) { +void vu_i_subaq(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; - int t = VU_UD_T; for (int i = 0; i < 4; i++) { if (VU_UD_DI(i)) { @@ -738,7 +728,7 @@ void vu_i_subaq(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_subax(struct vu_state* vu) { +void vu_i_subax(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -756,7 +746,7 @@ void vu_i_subax(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_subay(struct vu_state* vu) { +void vu_i_subay(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -774,7 +764,7 @@ void vu_i_subay(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_subaz(struct vu_state* vu) { +void vu_i_subaz(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -792,7 +782,7 @@ void vu_i_subaz(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_subaw(struct vu_state* vu) { +void vu_i_subaw(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -810,7 +800,7 @@ void vu_i_subaw(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_mul(struct vu_state* vu) { +void vu_i_mul(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int d = VU_UD_D; int t = VU_UD_T; @@ -827,7 +817,7 @@ void vu_i_mul(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_muli(struct vu_state* vu) { +void vu_i_muli(struct vu_state* vu, const struct vu_instruction* ins) { int d = VU_UD_D; int s = VU_UD_S; @@ -843,7 +833,7 @@ void vu_i_muli(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_mulq(struct vu_state* vu) { +void vu_i_mulq(struct vu_state* vu, const struct vu_instruction* ins) { int d = VU_UD_D; int s = VU_UD_S; @@ -859,7 +849,7 @@ void vu_i_mulq(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_mulx(struct vu_state* vu) { +void vu_i_mulx(struct vu_state* vu, const struct vu_instruction* ins) { int d = VU_UD_D; int s = VU_UD_S; int t = VU_UD_T; @@ -878,7 +868,7 @@ void vu_i_mulx(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_muly(struct vu_state* vu) { +void vu_i_muly(struct vu_state* vu, const struct vu_instruction* ins) { int d = VU_UD_D; int s = VU_UD_S; int t = VU_UD_T; @@ -897,7 +887,7 @@ void vu_i_muly(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_mulz(struct vu_state* vu) { +void vu_i_mulz(struct vu_state* vu, const struct vu_instruction* ins) { int d = VU_UD_D; int s = VU_UD_S; int t = VU_UD_T; @@ -916,7 +906,7 @@ void vu_i_mulz(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_mulw(struct vu_state* vu) { +void vu_i_mulw(struct vu_state* vu, const struct vu_instruction* ins) { int d = VU_UD_D; int s = VU_UD_S; int t = VU_UD_T; @@ -935,7 +925,7 @@ void vu_i_mulw(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_mula(struct vu_state* vu) { +void vu_i_mula(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -951,7 +941,7 @@ void vu_i_mula(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_mulai(struct vu_state* vu) { +void vu_i_mulai(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; for (int i = 0; i < 4; i++) { @@ -966,9 +956,8 @@ void vu_i_mulai(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_mulaq(struct vu_state* vu) { +void vu_i_mulaq(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; - int t = VU_UD_T; for (int i = 0; i < 4; i++) { if (VU_UD_DI(i)) { @@ -982,7 +971,7 @@ void vu_i_mulaq(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_mulax(struct vu_state* vu) { +void vu_i_mulax(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -1000,7 +989,7 @@ void vu_i_mulax(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_mulay(struct vu_state* vu) { +void vu_i_mulay(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -1018,7 +1007,7 @@ void vu_i_mulay(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_mulaz(struct vu_state* vu) { +void vu_i_mulaz(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -1036,7 +1025,7 @@ void vu_i_mulaz(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_mulaw(struct vu_state* vu) { +void vu_i_mulaw(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -1054,7 +1043,7 @@ void vu_i_mulaw(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_madd(struct vu_state* vu) { +void vu_i_madd(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; int d = VU_UD_D; @@ -1071,7 +1060,7 @@ void vu_i_madd(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_maddi(struct vu_state* vu) { +void vu_i_maddi(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int d = VU_UD_D; @@ -1087,7 +1076,7 @@ void vu_i_maddi(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_maddq(struct vu_state* vu) { +void vu_i_maddq(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int d = VU_UD_D; @@ -1103,7 +1092,7 @@ void vu_i_maddq(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_maddx(struct vu_state* vu) { +void vu_i_maddx(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; int d = VU_UD_D; @@ -1122,7 +1111,7 @@ void vu_i_maddx(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_maddy(struct vu_state* vu) { +void vu_i_maddy(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; int d = VU_UD_D; @@ -1141,7 +1130,7 @@ void vu_i_maddy(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_maddz(struct vu_state* vu) { +void vu_i_maddz(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; int d = VU_UD_D; @@ -1160,7 +1149,7 @@ void vu_i_maddz(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_maddw(struct vu_state* vu) { +void vu_i_maddw(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; int d = VU_UD_D; @@ -1179,7 +1168,7 @@ void vu_i_maddw(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_madda(struct vu_state* vu) { +void vu_i_madda(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -1195,7 +1184,7 @@ void vu_i_madda(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_maddai(struct vu_state* vu) { +void vu_i_maddai(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; for (int i = 0; i < 4; i++) { @@ -1210,9 +1199,8 @@ void vu_i_maddai(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_maddaq(struct vu_state* vu) { +void vu_i_maddaq(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; - int t = VU_UD_T; for (int i = 0; i < 4; i++) { if (VU_UD_DI(i)) { @@ -1226,7 +1214,7 @@ void vu_i_maddaq(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_maddax(struct vu_state* vu) { +void vu_i_maddax(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -1244,7 +1232,7 @@ void vu_i_maddax(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_madday(struct vu_state* vu) { +void vu_i_madday(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -1262,7 +1250,7 @@ void vu_i_madday(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_maddaz(struct vu_state* vu) { +void vu_i_maddaz(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -1280,7 +1268,7 @@ void vu_i_maddaz(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_maddaw(struct vu_state* vu) { +void vu_i_maddaw(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -1298,7 +1286,7 @@ void vu_i_maddaw(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_msub(struct vu_state* vu) { +void vu_i_msub(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; int d = VU_UD_D; @@ -1315,7 +1303,7 @@ void vu_i_msub(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_msubi(struct vu_state* vu) { +void vu_i_msubi(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int d = VU_UD_D; @@ -1331,7 +1319,7 @@ void vu_i_msubi(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_msubq(struct vu_state* vu) { +void vu_i_msubq(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int d = VU_UD_D; @@ -1347,7 +1335,7 @@ void vu_i_msubq(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_msubx(struct vu_state* vu) { +void vu_i_msubx(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; int d = VU_UD_D; @@ -1366,7 +1354,7 @@ void vu_i_msubx(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_msuby(struct vu_state* vu) { +void vu_i_msuby(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; int d = VU_UD_D; @@ -1385,7 +1373,7 @@ void vu_i_msuby(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_msubz(struct vu_state* vu) { +void vu_i_msubz(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; int d = VU_UD_D; @@ -1404,7 +1392,7 @@ void vu_i_msubz(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_msubw(struct vu_state* vu) { +void vu_i_msubw(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; int d = VU_UD_D; @@ -1423,7 +1411,7 @@ void vu_i_msubw(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_msuba(struct vu_state* vu) { +void vu_i_msuba(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -1439,7 +1427,7 @@ void vu_i_msuba(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_msubai(struct vu_state* vu) { +void vu_i_msubai(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; for (int i = 0; i < 4; i++) { @@ -1454,9 +1442,8 @@ void vu_i_msubai(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_msubaq(struct vu_state* vu) { +void vu_i_msubaq(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; - int t = VU_UD_T; for (int i = 0; i < 4; i++) { if (VU_UD_DI(i)) { @@ -1470,7 +1457,7 @@ void vu_i_msubaq(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_msubax(struct vu_state* vu) { +void vu_i_msubax(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -1488,7 +1475,7 @@ void vu_i_msubax(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_msubay(struct vu_state* vu) { +void vu_i_msubay(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -1506,7 +1493,7 @@ void vu_i_msubay(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_msubaz(struct vu_state* vu) { +void vu_i_msubaz(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -1524,7 +1511,7 @@ void vu_i_msubaz(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_msubaw(struct vu_state* vu) { +void vu_i_msubaw(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -1542,7 +1529,7 @@ void vu_i_msubaw(struct vu_state* vu) { vu_update_status(vu); } -void vu_i_max(struct vu_state* vu) { +void vu_i_max(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; int d = VU_UD_D; @@ -1555,7 +1542,7 @@ void vu_i_max(struct vu_state* vu) { } } } -void vu_i_maxi(struct vu_state* vu) { +void vu_i_maxi(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int d = VU_UD_D; @@ -1567,7 +1554,7 @@ void vu_i_maxi(struct vu_state* vu) { } } } -void vu_i_maxx(struct vu_state* vu) { +void vu_i_maxx(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; int d = VU_UD_D; @@ -1584,7 +1571,7 @@ void vu_i_maxx(struct vu_state* vu) { } } } -void vu_i_maxy(struct vu_state* vu) { +void vu_i_maxy(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; int d = VU_UD_D; @@ -1601,7 +1588,7 @@ void vu_i_maxy(struct vu_state* vu) { } } } -void vu_i_maxz(struct vu_state* vu) { +void vu_i_maxz(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; int d = VU_UD_D; @@ -1618,7 +1605,7 @@ void vu_i_maxz(struct vu_state* vu) { } } } -void vu_i_maxw(struct vu_state* vu) { +void vu_i_maxw(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; int d = VU_UD_D; @@ -1635,7 +1622,7 @@ void vu_i_maxw(struct vu_state* vu) { } } } -void vu_i_mini(struct vu_state* vu) { +void vu_i_mini(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; int d = VU_UD_D; @@ -1648,7 +1635,7 @@ void vu_i_mini(struct vu_state* vu) { } } } -void vu_i_minii(struct vu_state* vu) { +void vu_i_minii(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int d = VU_UD_D; @@ -1660,7 +1647,7 @@ void vu_i_minii(struct vu_state* vu) { } } } -void vu_i_minix(struct vu_state* vu) { +void vu_i_minix(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; int d = VU_UD_D; @@ -1675,7 +1662,7 @@ void vu_i_minix(struct vu_state* vu) { } } } -void vu_i_miniy(struct vu_state* vu) { +void vu_i_miniy(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; int d = VU_UD_D; @@ -1690,7 +1677,7 @@ void vu_i_miniy(struct vu_state* vu) { } } } -void vu_i_miniz(struct vu_state* vu) { +void vu_i_miniz(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; int d = VU_UD_D; @@ -1705,7 +1692,7 @@ void vu_i_miniz(struct vu_state* vu) { } } } -void vu_i_miniw(struct vu_state* vu) { +void vu_i_miniw(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; int d = VU_UD_D; @@ -1720,7 +1707,7 @@ void vu_i_miniw(struct vu_state* vu) { } } } -void vu_i_opmula(struct vu_state* vu) { +void vu_i_opmula(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -1756,7 +1743,7 @@ void vu_i_opmula(struct vu_state* vu) { vu_clear_flags(vu, 3); vu_update_status(vu); } -void vu_i_opmsub(struct vu_state* vu) { +void vu_i_opmsub(struct vu_state* vu, const struct vu_instruction* ins) { int d = VU_UD_D; int s = VU_UD_S; int t = VU_UD_T; @@ -1791,10 +1778,10 @@ void vu_i_opmsub(struct vu_state* vu) { vu_clear_flags(vu, 3); vu_update_status(vu); } -void vu_i_nop(struct vu_state* vu) { +void vu_i_nop(struct vu_state* vu, const struct vu_instruction* ins) { // No operation } -void vu_i_ftoi0(struct vu_state* vu) { +void vu_i_ftoi0(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -1802,7 +1789,7 @@ void vu_i_ftoi0(struct vu_state* vu) { if (VU_UD_DI(i)) vu_set_vfu(vu, t, i, vu_cvti(vu_vf_i(vu, s, i))); } } -void vu_i_ftoi4(struct vu_state* vu) { +void vu_i_ftoi4(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -1810,7 +1797,7 @@ void vu_i_ftoi4(struct vu_state* vu) { if (VU_UD_DI(i)) vu_set_vfu(vu, t, i, vu_cvti(vu_vf_i(vu, s, i) * (1.0f / 0.0625f))); } } -void vu_i_ftoi12(struct vu_state* vu) { +void vu_i_ftoi12(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -1818,7 +1805,7 @@ void vu_i_ftoi12(struct vu_state* vu) { if (VU_UD_DI(i)) vu_set_vfu(vu, t, i, vu_cvti(vu_vf_i(vu, s, i) * (1.0f / 0.000244140625f))); } } -void vu_i_ftoi15(struct vu_state* vu) { +void vu_i_ftoi15(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -1826,7 +1813,7 @@ void vu_i_ftoi15(struct vu_state* vu) { if (VU_UD_DI(i)) vu_set_vfu(vu, t, i, vu_cvti(vu_vf_i(vu, s, i) * (1.0f / 0.000030517578125f))); } } -void vu_i_itof0(struct vu_state* vu) { +void vu_i_itof0(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -1834,7 +1821,7 @@ void vu_i_itof0(struct vu_state* vu) { if (VU_UD_DI(i)) vu_set_vf(vu, t, i, (float)vu->vf[s].s32[i]); } } -void vu_i_itof4(struct vu_state* vu) { +void vu_i_itof4(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -1842,7 +1829,7 @@ void vu_i_itof4(struct vu_state* vu) { if (VU_UD_DI(i)) vu_set_vf(vu, t, i, (float)((float)(vu->vf[s].s32[i]) * 0.0625f)); } } -void vu_i_itof12(struct vu_state* vu) { +void vu_i_itof12(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -1850,7 +1837,7 @@ void vu_i_itof12(struct vu_state* vu) { if (VU_UD_DI(i)) vu_set_vf(vu, t, i, (float)((float)(vu->vf[s].s32[i]) * 0.000244140625f)); } } -void vu_i_itof15(struct vu_state* vu) { +void vu_i_itof15(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_UD_S; int t = VU_UD_T; @@ -1858,7 +1845,7 @@ void vu_i_itof15(struct vu_state* vu) { if (VU_UD_DI(i)) vu_set_vf(vu, t, i, (float)((float)(vu->vf[s].s32[i]) * 0.000030517578125f)); } } -void vu_i_clip(struct vu_state* vu) { +void vu_i_clip(struct vu_state* vu, const struct vu_instruction* ins) { int t = VU_UD_T; int s = VU_UD_S; @@ -1879,16 +1866,16 @@ void vu_i_clip(struct vu_state* vu) { } // Lower pipeline -void vu_i_b(struct vu_state* vu) { +void vu_i_b(struct vu_state* vu, const struct vu_instruction* ins) { vu->next_tpc = vu->tpc + VU_LD_IMM11; } -void vu_i_bal(struct vu_state* vu) { +void vu_i_bal(struct vu_state* vu, const struct vu_instruction* ins) { // Instruction next to the delay slot VU_IT = vu->tpc + 1; vu->next_tpc = vu->tpc + VU_LD_IMM11; } -void vu_i_div(struct vu_state* vu) { +void vu_i_div(struct vu_state* vu, const struct vu_instruction* ins) { int t = VU_LD_T; int s = VU_LD_S; int tf = VU_LD_TF; @@ -1897,7 +1884,7 @@ void vu_i_div(struct vu_state* vu) { vu->q.f = vu_vf_i(vu, s, sf) / vu_vf_i(vu, t, tf); vu->q.f = vu_cvtf(vu->q.u32); } -void vu_i_eatan(struct vu_state* vu) { +void vu_i_eatan(struct vu_state* vu, const struct vu_instruction* ins) { float x = vu_vf_i(vu, VU_LD_S, VU_LD_SF); if (x == -1.0f) { @@ -1908,7 +1895,7 @@ void vu_i_eatan(struct vu_state* vu) { vu->p.f = vu_atan(x); } } -void vu_i_eatanxy(struct vu_state* vu) { +void vu_i_eatanxy(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_LD_S; float x = vu_vf_x(vu, s); float y = vu_vf_y(vu, s); @@ -1921,7 +1908,7 @@ void vu_i_eatanxy(struct vu_state* vu) { vu->p.f = vu_atan(x); } } -void vu_i_eatanxz(struct vu_state* vu) { +void vu_i_eatanxz(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_LD_S; float x = vu_vf_x(vu, s); float z = vu_vf_z(vu, s); @@ -1935,7 +1922,7 @@ void vu_i_eatanxz(struct vu_state* vu) { vu->p.f = vu_atan(x); } } -void vu_i_eexp(struct vu_state* vu) { +void vu_i_eexp(struct vu_state* vu, const struct vu_instruction* ins) { const static float coeffs[] = { 0.249998688697815f, 0.031257584691048f, 0.002591371303424f, 0.000171562001924f, @@ -1959,7 +1946,7 @@ void vu_i_eexp(struct vu_state* vu) { vu->p.f = 1.0 / value; } -void vu_i_eleng(struct vu_state* vu) { +void vu_i_eleng(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_LD_S; float x2 = vu_vf_x(vu, s) * vu_vf_x(vu, s); @@ -1968,10 +1955,10 @@ void vu_i_eleng(struct vu_state* vu) { vu->p.f = sqrtf(x2 + y2 + z2); } -void vu_i_ercpr(struct vu_state* vu) { +void vu_i_ercpr(struct vu_state* vu, const struct vu_instruction* ins) { vu->p.f = 1.0f / vu_vf_i(vu, VU_LD_S, VU_LD_SF); } -void vu_i_erleng(struct vu_state* vu) { +void vu_i_erleng(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_LD_S; float x2 = vu_vf_x(vu, s) * vu_vf_x(vu, s); @@ -1980,7 +1967,7 @@ void vu_i_erleng(struct vu_state* vu) { vu->p.f = 1.0f / sqrtf(x2 + y2 + z2); } -void vu_i_ersadd(struct vu_state* vu) { +void vu_i_ersadd(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_LD_S; float x2 = vu_vf_x(vu, s) * vu_vf_x(vu, s); @@ -1989,10 +1976,10 @@ void vu_i_ersadd(struct vu_state* vu) { vu->p.f = 1.0f / (x2 + y2 + z2); } -void vu_i_ersqrt(struct vu_state* vu) { +void vu_i_ersqrt(struct vu_state* vu, const struct vu_instruction* ins) { vu->p.f = 1.0f / sqrtf(vu_vf_i(vu, VU_LD_S, VU_LD_SF)); } -void vu_i_esadd(struct vu_state* vu) { +void vu_i_esadd(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_LD_S; float x2 = vu_vf_x(vu, s) * vu_vf_x(vu, s); @@ -2001,105 +1988,105 @@ void vu_i_esadd(struct vu_state* vu) { vu->p.f = x2 + y2 + z2; } -void vu_i_esin(struct vu_state* vu) { +void vu_i_esin(struct vu_state* vu, const struct vu_instruction* ins) { vu->p.f = sinf(vu_vf_i(vu, VU_LD_S, VU_LD_SF)); } -void vu_i_esqrt(struct vu_state* vu) { +void vu_i_esqrt(struct vu_state* vu, const struct vu_instruction* ins) { vu->p.f = sqrtf(vu_vf_i(vu, VU_LD_S, VU_LD_SF)); } -void vu_i_esum(struct vu_state* vu) { +void vu_i_esum(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_LD_S; vu->p.f = vu_vf_x(vu, s) + vu_vf_y(vu, s) + vu_vf_z(vu, s) + vu_vf_w(vu, s); } -void vu_i_fcand(struct vu_state* vu) { +void vu_i_fcand(struct vu_state* vu, const struct vu_instruction* ins) { vu->vi[1] = ((vu->clip & 0xffffff) & VU_LD_IMM24) != 0; } -void vu_i_fceq(struct vu_state* vu) { +void vu_i_fceq(struct vu_state* vu, const struct vu_instruction* ins) { vu->vi[1] = (vu->clip & 0xffffff) == VU_LD_IMM24; } -void vu_i_fcget(struct vu_state* vu) { +void vu_i_fcget(struct vu_state* vu, const struct vu_instruction* ins) { int t = VU_LD_T; if (!t) return; vu->vi[VU_LD_T] = vu->clip & 0xfff; } -void vu_i_fcor(struct vu_state* vu) { +void vu_i_fcor(struct vu_state* vu, const struct vu_instruction* ins) { vu->vi[1] = ((vu->clip & 0xffffff) | VU_LD_IMM24) == 0xffffff; } -void vu_i_fcset(struct vu_state* vu) { +void vu_i_fcset(struct vu_state* vu, const struct vu_instruction* ins) { vu->clip = VU_LD_IMM24; } -void vu_i_fmand(struct vu_state* vu) { +void vu_i_fmand(struct vu_state* vu, const struct vu_instruction* ins) { vu_set_vi(vu, VU_LD_T, vu->mac_pipeline[3] & VU_IS); } -void vu_i_fmeq(struct vu_state* vu) { +void vu_i_fmeq(struct vu_state* vu, const struct vu_instruction* ins) { vu_set_vi(vu, VU_LD_T, (VU_IS & 0xffff) == (vu->mac_pipeline[3] & 0xffff)); } -void vu_i_fmor(struct vu_state* vu) { +void vu_i_fmor(struct vu_state* vu, const struct vu_instruction* ins) { vu_set_vi(vu, VU_LD_T, (VU_IS & 0xffff) | (vu->mac_pipeline[3] & 0xffff)); } -void vu_i_fsand(struct vu_state* vu) { +void vu_i_fsand(struct vu_state* vu, const struct vu_instruction* ins) { vu_set_vi(vu, VU_LD_T, vu->status & VU_LD_IMM12); } -void vu_i_fseq(struct vu_state* vu) { +void vu_i_fseq(struct vu_state* vu, const struct vu_instruction* ins) { vu_set_vi(vu, VU_LD_T, (vu->status & 0xfff) == VU_LD_IMM12); } -void vu_i_fsor(struct vu_state* vu) { +void vu_i_fsor(struct vu_state* vu, const struct vu_instruction* ins) { vu_set_vi(vu, VU_LD_T, (vu->status & 0xfff) | VU_LD_IMM12); } -void vu_i_fsset(struct vu_state* vu) { +void vu_i_fsset(struct vu_state* vu, const struct vu_instruction* ins) { vu->status &= 0x3f; vu->status |= VU_LD_IMM12 & 0xfc0; } -void vu_i_iadd(struct vu_state* vu) { +void vu_i_iadd(struct vu_state* vu, const struct vu_instruction* ins) { // printf("iadd vi%02u, vi%02u (%04x), vi%02u (%04x)\n", VU_LD_D, VU_LD_S, VU_IS, VU_LD_T, VU_IT); vu_set_vi(vu, VU_LD_D, VU_IS + VU_IT); } -void vu_i_iaddi(struct vu_state* vu) { +void vu_i_iaddi(struct vu_state* vu, const struct vu_instruction* ins) { vu_set_vi(vu, VU_LD_T, VU_IS + VU_LD_IMM5); } -void vu_i_iaddiu(struct vu_state* vu) { +void vu_i_iaddiu(struct vu_state* vu, const struct vu_instruction* ins) { vu_set_vi(vu, VU_LD_T, VU_IS + VU_LD_IMM15); } -void vu_i_iand(struct vu_state* vu) { +void vu_i_iand(struct vu_state* vu, const struct vu_instruction* ins) { vu_set_vi(vu, VU_LD_D, VU_IS & VU_IT); } -void vu_i_ibeq(struct vu_state* vu) { +void vu_i_ibeq(struct vu_state* vu, const struct vu_instruction* ins) { if (VU_IT == VU_IS) { vu->next_tpc = vu->tpc + VU_LD_IMM11; } } -void vu_i_ibgez(struct vu_state* vu) { +void vu_i_ibgez(struct vu_state* vu, const struct vu_instruction* ins) { if ((int16_t)VU_IS >= 0) { vu->next_tpc = vu->tpc + VU_LD_IMM11; } } -void vu_i_ibgtz(struct vu_state* vu) { +void vu_i_ibgtz(struct vu_state* vu, const struct vu_instruction* ins) { if ((int16_t)VU_IS > 0) { vu->next_tpc = vu->tpc + VU_LD_IMM11; } } -void vu_i_iblez(struct vu_state* vu) { +void vu_i_iblez(struct vu_state* vu, const struct vu_instruction* ins) { if ((int16_t)VU_IS <= 0) { vu->next_tpc = vu->tpc + VU_LD_IMM11; } } -void vu_i_ibltz(struct vu_state* vu) { +void vu_i_ibltz(struct vu_state* vu, const struct vu_instruction* ins) { if ((int16_t)VU_IS < 0) { vu->next_tpc = vu->tpc + VU_LD_IMM11; } } -void vu_i_ibne(struct vu_state* vu) { +void vu_i_ibne(struct vu_state* vu, const struct vu_instruction* ins) { // printf("ibne vi%02u (%04x), vi%02u (%04x), 0x%08x\n", VU_LD_T, VU_IT, VU_LD_S, VU_IS, vu->tpc + VU_LD_IMM11); if (VU_IT != VU_IS) { vu->next_tpc = vu->tpc + VU_LD_IMM11; } } -void vu_i_ilw(struct vu_state* vu) { +void vu_i_ilw(struct vu_state* vu, const struct vu_instruction* ins) { int t = VU_LD_T; if (!t) return; @@ -2111,7 +2098,7 @@ void vu_i_ilw(struct vu_state* vu) { if (VU_LD_DI(i)) vu->vi[t] = data.u32[i]; } } -void vu_i_ilwr(struct vu_state* vu) { +void vu_i_ilwr(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_LD_S; int t = VU_LD_T; @@ -2124,16 +2111,16 @@ void vu_i_ilwr(struct vu_state* vu) { if (VU_LD_DI(i)) vu->vi[t] = data.u32[i]; } } -void vu_i_ior(struct vu_state* vu) { +void vu_i_ior(struct vu_state* vu, const struct vu_instruction* ins) { vu_set_vi(vu, VU_LD_D, VU_IS | VU_IT); } -void vu_i_isub(struct vu_state* vu) { +void vu_i_isub(struct vu_state* vu, const struct vu_instruction* ins) { vu_set_vi(vu, VU_LD_D, VU_IS - VU_IT); } -void vu_i_isubiu(struct vu_state* vu) { +void vu_i_isubiu(struct vu_state* vu, const struct vu_instruction* ins) { vu_set_vi(vu, VU_LD_T, VU_IS - VU_LD_IMM15); } -void vu_i_isw(struct vu_state* vu) { +void vu_i_isw(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_LD_S; int t = VU_LD_T; @@ -2143,7 +2130,7 @@ void vu_i_isw(struct vu_state* vu) { if (VU_LD_DI(i)) vu_mem_write(vu, addr, vu->vi[t], i); } } -void vu_i_iswr(struct vu_state* vu) { +void vu_i_iswr(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_LD_S; int t = VU_LD_T; @@ -2153,17 +2140,17 @@ void vu_i_iswr(struct vu_state* vu) { if (VU_LD_DI(i)) vu_mem_write(vu, addr, vu->vi[t], i); } } -void vu_i_jalr(struct vu_state* vu) { +void vu_i_jalr(struct vu_state* vu, const struct vu_instruction* ins) { uint16_t s = VU_IS; VU_IT = vu->tpc + 1; vu->next_tpc = s; } -void vu_i_jr(struct vu_state* vu) { +void vu_i_jr(struct vu_state* vu, const struct vu_instruction* ins) { vu->next_tpc = VU_IS; } -void vu_i_lq(struct vu_state* vu) { +void vu_i_lq(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_LD_S; int t = VU_LD_T; @@ -2176,7 +2163,7 @@ void vu_i_lq(struct vu_state* vu) { if (VU_LD_DI(i)) vu->vf[t].u32[i] = data.u32[i]; } } -void vu_i_lqd(struct vu_state* vu) { +void vu_i_lqd(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_LD_S; int t = VU_LD_T; @@ -2191,15 +2178,17 @@ void vu_i_lqd(struct vu_state* vu) { if (VU_LD_DI(i)) vu->vf[t].u32[i] = data.u32[i]; } } -void vu_i_lqi(struct vu_state* vu) { +void vu_i_lqi(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_LD_S; int t = VU_LD_T; - uint32_t addr = vu->vi[s]; - uint128_t data = vu_mem_read(vu, addr); + if (t) { + uint32_t addr = vu->vi[s]; + uint128_t data = vu_mem_read(vu, addr); - for (int i = 0; i < 4; i++) { - if (VU_LD_DI(i)) if (t) vu->vf[t].u32[i] = data.u32[i]; + for (int i = 0; i < 4; i++) { + if (VU_LD_DI(i)) vu->vf[t].u32[i] = data.u32[i]; + } } // printf(" vf%02u, (vi%02u++) (%04x) (%f %f %f %f)\n", @@ -2214,16 +2203,16 @@ void vu_i_lqi(struct vu_state* vu) { if (s) vu->vi[s]++; } -void vu_i_mfir(struct vu_state* vu) { +void vu_i_mfir(struct vu_state* vu, const struct vu_instruction* ins) { int t = VU_LD_T; if (!t) return; for (int i = 0; i < 4; i++) { - if (VU_LD_DI(i)) vu->vf[t].u32[i] = (int32_t)(*((int16_t*)&VU_IS)); + if (VU_LD_DI(i)) vu->vf[t].u32[i] = (int32_t)(int16_t)VU_IS; } } -void vu_i_mfp(struct vu_state* vu) { +void vu_i_mfp(struct vu_state* vu, const struct vu_instruction* ins) { int t = VU_LD_T; if (!t) return; @@ -2232,7 +2221,7 @@ void vu_i_mfp(struct vu_state* vu) { if (VU_LD_DI(i)) vu->vf[t].u32[i] = vu->p.f; } } -void vu_i_move(struct vu_state* vu) { +void vu_i_move(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_LD_S; int t = VU_LD_T; @@ -2242,7 +2231,7 @@ void vu_i_move(struct vu_state* vu) { if (VU_LD_DI(i)) vu->vf[t].u32[i] = vu->vf[s].u32[i]; } } -void vu_i_mr32(struct vu_state* vu) { +void vu_i_mr32(struct vu_state* vu, const struct vu_instruction* ins) { int t = VU_LD_T; if (!t) return; @@ -2260,10 +2249,10 @@ void vu_i_mr32(struct vu_state* vu) { if (VU_LD_DI(2)) vu->vf[t].u32[2] = vu->vf[s].u32[3]; if (VU_LD_DI(3)) vu->vf[t].u32[3] = x; } -void vu_i_mtir(struct vu_state* vu) { +void vu_i_mtir(struct vu_state* vu, const struct vu_instruction* ins) { vu_set_vi(vu, VU_LD_T, vu->vf[VU_LD_S].u32[VU_LD_SF] & 0xffff); } -void vu_i_rget(struct vu_state* vu) { +void vu_i_rget(struct vu_state* vu, const struct vu_instruction* ins) { int t = VU_LD_T; if (!t) return; @@ -2272,7 +2261,7 @@ void vu_i_rget(struct vu_state* vu) { if (VU_LD_DI(i)) vu->vf[t].u32[i] = vu->r.u32; } } -void vu_i_rinit(struct vu_state* vu) { +void vu_i_rinit(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_LD_S; vu->r.u32 = 0x3f800000; @@ -2281,7 +2270,7 @@ void vu_i_rinit(struct vu_state* vu) { vu->r.u32 |= vu->vf[s].u32[VU_LD_SF] & 0x007fffff; } -void vu_i_rnext(struct vu_state* vu) { +void vu_i_rnext(struct vu_state* vu, const struct vu_instruction* ins) { int t = VU_LD_T; if (!t) return; @@ -2297,24 +2286,26 @@ void vu_i_rnext(struct vu_state* vu) { if (VU_LD_DI(i)) vu->vf[t].u32[i] = vu->r.u32; } } -void vu_i_rsqrt(struct vu_state* vu) { +void vu_i_rsqrt(struct vu_state* vu, const struct vu_instruction* ins) { vu->q.f = vu_vf_i(vu, VU_LD_S, VU_LD_SF) / sqrtf(vu_vf_i(vu, VU_LD_T, VU_LD_TF)); vu->q.f = vu_cvtf(vu->q.u32); } -void vu_i_rxor(struct vu_state* vu) { +void vu_i_rxor(struct vu_state* vu, const struct vu_instruction* ins) { vu->r.u32 = 0x3F800000 | ((vu->r.u32 ^ vu->vf[VU_LD_S].u32[VU_LD_SF]) & 0x007FFFFF); } -void vu_i_sq(struct vu_state* vu) { +void vu_i_sq(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_LD_S; int t = VU_LD_T; uint32_t addr = vu->vi[t] + VU_LD_IMM11; + // printf("vu: sq addr=%08x vf%02d=%08x %08x %08x %08x\n", addr, s, vu->vf[s].u32[3], vu->vf[s].u32[2], vu->vf[s].u32[1], vu->vf[s].u32[0]); + for (int i = 0; i < 4; i++) { if (VU_LD_DI(i)) vu_mem_write(vu, addr, vu->vf[s].u32[i], i); } } -void vu_i_sqd(struct vu_state* vu) { +void vu_i_sqd(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_LD_S; int t = VU_LD_T; @@ -2326,7 +2317,7 @@ void vu_i_sqd(struct vu_state* vu) { if (VU_LD_DI(i)) vu_mem_write(vu, addr, vu->vf[s].u32[i], i); } } -void vu_i_sqi(struct vu_state* vu) { +void vu_i_sqi(struct vu_state* vu, const struct vu_instruction* ins) { int s = VU_LD_S; int t = VU_LD_T; @@ -2338,19 +2329,19 @@ void vu_i_sqi(struct vu_state* vu) { vu_set_vi(vu, t, vu->vi[t] + 1); } -void vu_i_sqrt(struct vu_state* vu) { +void vu_i_sqrt(struct vu_state* vu, const struct vu_instruction* ins) { vu->q.f = sqrtf(vu_vf_i(vu, VU_LD_T, VU_LD_TF)); vu->q.f = vu_cvtf(vu->q.u32); } -void vu_i_waitp(struct vu_state* vu) { +void vu_i_waitp(struct vu_state* vu, const struct vu_instruction* ins) { // No operation } -void vu_i_waitq(struct vu_state* vu) { +void vu_i_waitq(struct vu_state* vu, const struct vu_instruction* ins) { // No operation vu->q_delay = 0; } -void vu_i_xgkick(struct vu_state* vu) { +void vu_i_xgkick(struct vu_state* vu, const struct vu_instruction* ins) { uint16_t addr = VU_IS; int eop = 1; @@ -2360,6 +2351,8 @@ void vu_i_xgkick(struct vu_state* vu) { addr &= 0x7ff; + if (addr == 0) break; + // printf("tag: addr=%08x %08x %08x %08x %08x\n", addr - 1, tag.u32[3], tag.u32[2], tag.u32[1], tag.u32[0]); ps2_gif_write128(vu->gif, 0, tag); @@ -2373,8 +2366,8 @@ void vu_i_xgkick(struct vu_state* vu) { if (!nloop) continue; - // if (!nregs) - // nregs = 16; + if (!nregs) + nregs = 16; int qwc = 0; @@ -2391,6 +2384,9 @@ void vu_i_xgkick(struct vu_state* vu) { } break; } + if (qwc >= 0x7ff) + continue; + // printf("vu: nloop=%d nregs=%d eop=%d flg=%d qwc=%d\n", // nloop, // nregs, @@ -2411,13 +2407,18 @@ void vu_i_xgkick(struct vu_state* vu) { ps2_gif_write128(vu->gif, 0, vu_mem_read(vu, addr++)); addr &= 0x7ff; + + if (addr == 0) { + eop = 1; + break; + } } } while (!eop); } -void vu_i_xitop(struct vu_state* vu) { +void vu_i_xitop(struct vu_state* vu, const struct vu_instruction* ins) { vu_set_vi(vu, VU_LD_T, vu->vif->itop); } -void vu_i_xtop(struct vu_state* vu) { +void vu_i_xtop(struct vu_state* vu, const struct vu_instruction* ins) { if (vu->id == 0) { printf("vu: xtop used in VU0\n"); @@ -2538,7 +2539,224 @@ void ps2_vu_write128(struct vu_state* vu, uint32_t addr, uint128_t data) { } } -static inline void vu_execute_upper(struct vu_state* vu, uint32_t opcode) { +#define VU_FLD_X 1 +#define VU_FLD_Y 2 +#define VU_FLD_Z 4 +#define VU_FLD_W 8 + +#define VU_DEC_UD_S_SRC_T_BROADCAST(bc, f) \ + vu->upper.src[0].reg = vu->upper.ud_s; \ + vu->upper.src[0].field = (opcode >> 21) & 0xf; \ + vu->upper.src[1].reg = vu->upper.ud_t; \ + vu->upper.src[1].field = bc; \ + vu->upper.func = f; + +#define VU_DEC_UD_D_DST_S_SRC_T_BROADCAST(bc, f) \ + vu->upper.dst.reg = vu->upper.ud_d; \ + vu->upper.dst.field = (opcode >> 21) & 0xf; \ + vu->upper.src[0].reg = vu->upper.ud_s; \ + vu->upper.src[0].field = vu->upper.dst.field; \ + vu->upper.src[1].reg = vu->upper.ud_t; \ + vu->upper.src[1].field = bc; \ + vu->upper.func = f; + +#define VU_DEC_UD_D_DST_S_SRC_T_SRC(f) \ + vu->upper.dst.reg = vu->upper.ud_d; \ + vu->upper.dst.field = (opcode >> 21) & 0xf; \ + vu->upper.src[0].reg = vu->upper.ud_s; \ + vu->upper.src[0].field = vu->upper.dst.field; \ + vu->upper.src[1].reg = vu->upper.ud_t; \ + vu->upper.src[1].field = vu->upper.dst.field; \ + vu->upper.func = f; + +#define VU_DEC_UD_D_DST_S_SRC(f) \ + vu->upper.dst.reg = vu->upper.ud_d; \ + vu->upper.dst.field = (opcode >> 21) & 0xf; \ + vu->upper.src[0].reg = vu->upper.ud_s; \ + vu->upper.src[0].field = vu->upper.dst.field; \ + vu->upper.func = f; + +#define VU_DEC_UD_T_DST_S_SRC(f) \ + vu->upper.dst.reg = vu->upper.ud_t; \ + vu->upper.dst.field = (opcode >> 21) & 0xf; \ + vu->upper.src[0].reg = vu->upper.ud_s; \ + vu->upper.src[0].field = vu->upper.dst.field; \ + vu->upper.func = f; + +#define VU_DEC_UD_S_SRC_T_SRC(f) \ + vu->upper.src[0].reg = vu->upper.ud_s; \ + vu->upper.src[0].field = (opcode >> 21) & 0xf; \ + vu->upper.src[1].reg = vu->upper.ud_t; \ + vu->upper.src[1].field = vu->upper.src[0].field; \ + vu->upper.func = f; + +#define VU_DEC_UD_S_SRC(f) \ + vu->upper.src[0].reg = vu->upper.ud_s; \ + vu->upper.src[0].field = (opcode >> 21) & 0xf; \ + vu->upper.func = f; + +#define VU_DEC_OPMULA() \ + vu->upper.src[0].reg = vu->upper.ud_s; \ + vu->upper.src[0].field = VU_FLD_X | VU_FLD_Y | VU_FLD_Z; \ + vu->upper.src[1].reg = vu->upper.ud_t; \ + vu->upper.src[1].field = vu->upper.src[0].field; \ + vu->upper.func = vu_i_opmula; + +#define VU_DEC_OPMSUB() \ + vu->upper.dst.reg = vu->upper.ud_d; \ + vu->upper.dst.field = VU_FLD_X | VU_FLD_Y | VU_FLD_Z; \ + vu->upper.src[0].reg = vu->upper.ud_s; \ + vu->upper.src[0].field = vu->upper.dst.field; \ + vu->upper.src[1].reg = vu->upper.ud_t; \ + vu->upper.src[1].field = vu->upper.dst.field; \ + vu->upper.func = vu_i_opmsub; + +#define VU_DEC_CLIP() \ + vu->upper.src[0].reg = vu->upper.ud_s; \ + vu->upper.src[0].field = VU_FLD_X | VU_FLD_Y | VU_FLD_Z; \ + vu->upper.src[1].reg = vu->upper.ud_t; \ + vu->upper.src[1].field = VU_FLD_W; \ + vu->upper.func = vu_i_clip; + +#define VU_DEC_LD_NONE(f) \ + vu->lower.func = f; + +#define VU_DEC_UD_NONE(f) \ + vu->upper.func = f; + +#define VU_DEC_LD_T_DST_S_VISRC(f) \ + vu->lower.dst.reg = vu->lower.ld_t; \ + vu->lower.dst.field = (opcode >> 21) & 0xf; \ + vu->lower.vi_src[0] = vu->lower.ld_s; \ + vu->lower.func = f; + +#define VU_DEC_LD_T_DST_S_VISRC_S_VIDST(f) \ + vu->lower.dst.reg = vu->lower.ld_t; \ + vu->lower.dst.field = (opcode >> 21) & 0xf; \ + vu->lower.vi_dst = vu->lower.ld_s; \ + vu->lower.vi_src[0] = vu->lower.vi_dst; \ + vu->lower.func = f; + +#define VU_DEC_LD_S_SRC_T_VISRC_T_VIDST(f) \ + vu->lower.src[0].reg = vu->lower.ld_s; \ + vu->lower.src[0].field = (opcode >> 21) & 0xf; \ + vu->lower.vi_dst = vu->lower.ld_t; \ + vu->lower.vi_src[0] = vu->lower.vi_dst; \ + vu->lower.func = f; + +#define VU_DEC_LD_S_SF_SRC_T_TF_SRC(f) \ + vu->lower.src[0].reg = vu->lower.ld_s; \ + vu->lower.src[0].field = vu->lower.ld_sf; \ + vu->lower.src[1].reg = vu->lower.ld_t; \ + vu->lower.src[1].field = vu->lower.ld_tf; \ + vu->lower.func = f; + +#define VU_DEC_LD_T_VIDST_S_SF_SRC(f) \ + vu->lower.vi_dst = vu->lower.ld_t; \ + vu->lower.src[0].reg = vu->lower.ld_s; \ + vu->lower.src[0].field = vu->lower.ld_sf; \ + vu->lower.func = f; + +#define VU_DEC_LD_T_DST_S_VISRC(f) \ + vu->lower.dst.reg = vu->lower.ld_t; \ + vu->lower.dst.field = (opcode >> 21) & 0xf; \ + vu->lower.vi_src[0] = vu->lower.ld_s; \ + vu->lower.func = f; + +#define VU_DEC_LD_T_TF_SRC(f) \ + vu->lower.src[0].reg = vu->lower.ld_t; \ + vu->lower.src[0].field = vu->lower.ld_tf; \ + vu->lower.func = f; + +#define VU_DEC_LD_S_SRC_T_VISRC(f) \ + vu->lower.src[0].reg = vu->lower.ld_s; \ + vu->lower.src[0].field = (opcode >> 21) & 0xf; \ + vu->lower.vi_src[0] = vu->lower.ld_t; \ + vu->lower.func = f; + +#define VU_DEC_LD_T_VIDST_S_VISRC(f) \ + vu->lower.vi_dst = vu->lower.ld_t; \ + vu->lower.vi_src[0] = vu->lower.ld_s; \ + vu->lower.func = f; + +#define VU_DEC_LD_S_VISRC_T_VISRC(f) \ + vu->lower.vi_src[0] = vu->lower.ld_s; \ + vu->lower.vi_src[1] = vu->lower.ld_t; \ + vu->lower.func = f; + +#define VU_DEC_LD_T_VIDST_S_VISRC(f) \ + vu->lower.vi_dst = vu->lower.ld_t; \ + vu->lower.vi_src[0] = vu->lower.ld_s; \ + vu->lower.func = f; + +#define VU_DEC_LD_T_VISRC_S_VISRC(f) \ + vu->lower.vi_src[0] = vu->lower.ld_t; \ + vu->lower.vi_src[1] = vu->lower.ld_s; \ + vu->lower.func = f; + +#define VU_DEC_LD_VIDST(v, f) \ + vu->lower.vi_dst = v; \ + vu->lower.func = f; + +#define VU_DEC_LD_T_VIDST(f) \ + vu->lower.vi_dst = vu->lower.ld_t; \ + vu->lower.func = f; + +#define VU_DEC_LD_S_VISRC(f) \ + vu->lower.vi_src[0] = vu->lower.ld_s; \ + vu->lower.func = f; + +#define VU_DEC_LD_S_FLD_SRC(fld, f) \ + vu->lower.src[0].reg = vu->lower.ld_s; \ + vu->lower.src[0].field = fld; \ + vu->lower.func = f; + +#define VU_DEC_LD_D_VIDST_S_VISRC_T_VISRC(f) \ + vu->lower.vi_dst = vu->lower.ld_d; \ + vu->lower.vi_src[0] = vu->lower.ld_s; \ + vu->lower.vi_src[1] = vu->lower.ld_t; \ + vu->lower.func = f; + +#define VU_DEC_LD_T_DST_S_SRC(f) \ + vu->lower.dst.reg = vu->lower.ld_t; \ + vu->lower.dst.field = (opcode >> 21) & 0xf; \ + vu->lower.src[0].reg = vu->lower.ld_s; \ + vu->lower.src[0].field = vu->lower.dst.field; \ + vu->lower.func = f; + +#define VU_DEC_LD_T_DST(f) \ + vu->lower.dst.reg = vu->lower.ld_t; \ + vu->lower.dst.field = (opcode >> 21) & 0xf; \ + vu->lower.func = f; + +#define VU_DEC_LD_S_SF_SRC(f) \ + vu->lower.src[0].reg = vu->lower.ld_s; \ + vu->lower.src[0].field = vu->lower.ld_sf; \ + vu->lower.func = f; + +#define VU_DEC_MR32() \ + vu->lower.dst.reg = vu->lower.ld_t; \ + vu->lower.dst.field = (opcode >> 21) & 0xf; \ + vu->lower.src[0].reg = vu->lower.ld_s; \ + vu->lower.src[0].field = (vu->lower.dst.field >> 1) | ((vu->lower.dst.field & 1) << 3); \ + vu->lower.func = vu_i_mr32; + +void vu_decode_upper(struct vu_state* vu, uint32_t opcode) { + vu->upper.ud_d = (opcode >> 6) & 0x1f; + vu->upper.ud_s = (opcode >> 11) & 0x1f; + vu->upper.ud_t = (opcode >> 16) & 0x1f; + + for (int i = 0; i < 4; i++) + vu->upper.ud_di[i] = opcode & (1 << (24 - i)); + + vu->upper.func = NULL; + vu->upper.dst.reg = 0; + vu->upper.dst.field = 0; + vu->upper.src[0].reg = 0; + vu->upper.src[0].field = 0; + vu->upper.src[1].reg = 0; + vu->upper.src[1].field = 0; + // Decode 000007FF style instruction if ((opcode & 0x3c) == 0x3c) { // 0EEEE 1111 EE @@ -2550,186 +2768,211 @@ static inline void vu_execute_upper(struct vu_state* vu, uint32_t opcode) { // bits 0-1 and bits 6-9 (6 bits) are enough to decode // all of the following switch (((opcode & 0x3c0) >> 4) | (opcode & 3)) { - case 0x00: vu_i_addax(vu); return; - case 0x01: vu_i_adday(vu); return; - case 0x02: vu_i_addaz(vu); return; - case 0x03: vu_i_addaw(vu); return; - case 0x04: vu_i_subax(vu); return; - case 0x05: vu_i_subay(vu); return; - case 0x06: vu_i_subaz(vu); return; - case 0x07: vu_i_subaw(vu); return; - case 0x08: vu_i_maddax(vu); return; - case 0x09: vu_i_madday(vu); return; - case 0x0A: vu_i_maddaz(vu); return; - case 0x0B: vu_i_maddaw(vu); return; - case 0x0C: vu_i_msubax(vu); return; - case 0x0D: vu_i_msubay(vu); return; - case 0x0E: vu_i_msubaz(vu); return; - case 0x0F: vu_i_msubaw(vu); return; - case 0x10: vu_i_itof0(vu); return; - case 0x11: vu_i_itof4(vu); return; - case 0x12: vu_i_itof12(vu); return; - case 0x13: vu_i_itof15(vu); return; - case 0x14: vu_i_ftoi0(vu); return; - case 0x15: vu_i_ftoi4(vu); return; - case 0x16: vu_i_ftoi12(vu); return; - case 0x17: vu_i_ftoi15(vu); return; - case 0x18: vu_i_mulax(vu); return; - case 0x19: vu_i_mulay(vu); return; - case 0x1A: vu_i_mulaz(vu); return; - case 0x1B: vu_i_mulaw(vu); return; - case 0x1C: vu_i_mulaq(vu); return; - case 0x1D: vu_i_abs(vu); return; - case 0x1E: vu_i_mulai(vu); return; - case 0x1F: vu_i_clip(vu); return; - case 0x20: vu_i_addaq(vu); return; - case 0x21: vu_i_maddaq(vu); return; - case 0x22: vu_i_addai(vu); return; - case 0x23: vu_i_maddai(vu); return; - case 0x24: vu_i_subaq(vu); return; - case 0x25: vu_i_msubaq(vu); return; - case 0x26: vu_i_subai(vu); return; - case 0x27: vu_i_msubai(vu); return; - case 0x28: vu_i_adda(vu); return; - case 0x29: vu_i_madda(vu); return; - case 0x2A: vu_i_mula(vu); return; - case 0x2C: vu_i_suba(vu); return; - case 0x2D: vu_i_msuba(vu); return; - case 0x2E: vu_i_opmula(vu); return; - case 0x2F: vu_i_nop(vu); return; + case 0x00: VU_DEC_UD_S_SRC_T_BROADCAST(VU_FLD_X, vu_i_addax); return; + case 0x01: VU_DEC_UD_S_SRC_T_BROADCAST(VU_FLD_Y, vu_i_adday); return; + case 0x02: VU_DEC_UD_S_SRC_T_BROADCAST(VU_FLD_Z, vu_i_addaz); return; + case 0x03: VU_DEC_UD_S_SRC_T_BROADCAST(VU_FLD_W, vu_i_addaw); return; + case 0x04: VU_DEC_UD_S_SRC_T_BROADCAST(VU_FLD_X, vu_i_subax); return; + case 0x05: VU_DEC_UD_S_SRC_T_BROADCAST(VU_FLD_Y, vu_i_subay); return; + case 0x06: VU_DEC_UD_S_SRC_T_BROADCAST(VU_FLD_Z, vu_i_subaz); return; + case 0x07: VU_DEC_UD_S_SRC_T_BROADCAST(VU_FLD_W, vu_i_subaw); return; + case 0x08: VU_DEC_UD_S_SRC_T_BROADCAST(VU_FLD_X, vu_i_maddax); return; + case 0x09: VU_DEC_UD_S_SRC_T_BROADCAST(VU_FLD_Y, vu_i_madday); return; + case 0x0A: VU_DEC_UD_S_SRC_T_BROADCAST(VU_FLD_Z, vu_i_maddaz); return; + case 0x0B: VU_DEC_UD_S_SRC_T_BROADCAST(VU_FLD_W, vu_i_maddaw); return; + case 0x0C: VU_DEC_UD_S_SRC_T_BROADCAST(VU_FLD_X, vu_i_msubax); return; + case 0x0D: VU_DEC_UD_S_SRC_T_BROADCAST(VU_FLD_Y, vu_i_msubay); return; + case 0x0E: VU_DEC_UD_S_SRC_T_BROADCAST(VU_FLD_Z, vu_i_msubaz); return; + case 0x0F: VU_DEC_UD_S_SRC_T_BROADCAST(VU_FLD_W, vu_i_msubaw); return; + case 0x10: VU_DEC_UD_T_DST_S_SRC(vu_i_itof0); return; + case 0x11: VU_DEC_UD_T_DST_S_SRC(vu_i_itof4); return; + case 0x12: VU_DEC_UD_T_DST_S_SRC(vu_i_itof12); return; + case 0x13: VU_DEC_UD_T_DST_S_SRC(vu_i_itof15); return; + case 0x14: VU_DEC_UD_T_DST_S_SRC(vu_i_ftoi0); return; + case 0x15: VU_DEC_UD_T_DST_S_SRC(vu_i_ftoi4); return; + case 0x16: VU_DEC_UD_T_DST_S_SRC(vu_i_ftoi12); return; + case 0x17: VU_DEC_UD_T_DST_S_SRC(vu_i_ftoi15); return; + case 0x18: VU_DEC_UD_S_SRC_T_BROADCAST(VU_FLD_X, vu_i_mulax); return; + case 0x19: VU_DEC_UD_S_SRC_T_BROADCAST(VU_FLD_Y, vu_i_mulay); return; + case 0x1A: VU_DEC_UD_S_SRC_T_BROADCAST(VU_FLD_Z, vu_i_mulaz); return; + case 0x1B: VU_DEC_UD_S_SRC_T_BROADCAST(VU_FLD_W, vu_i_mulaw); return; + case 0x1C: VU_DEC_UD_S_SRC(vu_i_mulaq); return; + case 0x1D: VU_DEC_UD_T_DST_S_SRC(vu_i_abs); return; + case 0x1E: VU_DEC_UD_S_SRC(vu_i_mulai); return; + case 0x1F: VU_DEC_CLIP(); return; + case 0x20: VU_DEC_UD_S_SRC(vu_i_addaq); return; + case 0x21: VU_DEC_UD_S_SRC(vu_i_maddaq); return; + case 0x22: VU_DEC_UD_S_SRC(vu_i_addai); return; + case 0x23: VU_DEC_UD_S_SRC(vu_i_maddai); return; + case 0x24: VU_DEC_UD_S_SRC(vu_i_subaq); return; + case 0x25: VU_DEC_UD_S_SRC(vu_i_msubaq); return; + case 0x26: VU_DEC_UD_S_SRC(vu_i_subai); return; + case 0x27: VU_DEC_UD_S_SRC(vu_i_msubai); return; + case 0x28: VU_DEC_UD_S_SRC_T_SRC(vu_i_adda); return; + case 0x29: VU_DEC_UD_S_SRC_T_SRC(vu_i_madda); return; + case 0x2A: VU_DEC_UD_S_SRC_T_SRC(vu_i_mula); return; + case 0x2C: VU_DEC_UD_S_SRC_T_SRC(vu_i_suba); return; + case 0x2D: VU_DEC_UD_S_SRC_T_SRC(vu_i_msuba); return; + case 0x2E: VU_DEC_OPMULA(); return; + case 0x2F: VU_DEC_UD_NONE(vu_i_nop); return; } } else { // Decode 0000003F style instruction switch (opcode & 0x3f) { - case 0x00: vu_i_addx(vu); return; - case 0x01: vu_i_addy(vu); return; - case 0x02: vu_i_addz(vu); return; - case 0x03: vu_i_addw(vu); return; - case 0x04: vu_i_subx(vu); return; - case 0x05: vu_i_suby(vu); return; - case 0x06: vu_i_subz(vu); return; - case 0x07: vu_i_subw(vu); return; - case 0x08: vu_i_maddx(vu); return; - case 0x09: vu_i_maddy(vu); return; - case 0x0A: vu_i_maddz(vu); return; - case 0x0B: vu_i_maddw(vu); return; - case 0x0C: vu_i_msubx(vu); return; - case 0x0D: vu_i_msuby(vu); return; - case 0x0E: vu_i_msubz(vu); return; - case 0x0F: vu_i_msubw(vu); return; - case 0x10: vu_i_maxx(vu); return; - case 0x11: vu_i_maxy(vu); return; - case 0x12: vu_i_maxz(vu); return; - case 0x13: vu_i_maxw(vu); return; - case 0x14: vu_i_minix(vu); return; - case 0x15: vu_i_miniy(vu); return; - case 0x16: vu_i_miniz(vu); return; - case 0x17: vu_i_miniw(vu); return; - case 0x18: vu_i_mulx(vu); return; - case 0x19: vu_i_muly(vu); return; - case 0x1A: vu_i_mulz(vu); return; - case 0x1B: vu_i_mulw(vu); return; - case 0x1C: vu_i_mulq(vu); return; - case 0x1D: vu_i_maxi(vu); return; - case 0x1E: vu_i_muli(vu); return; - case 0x1F: vu_i_minii(vu); return; - case 0x20: vu_i_addq(vu); return; - case 0x21: vu_i_maddq(vu); return; - case 0x22: vu_i_addi(vu); return; - case 0x23: vu_i_maddi(vu); return; - case 0x24: vu_i_subq(vu); return; - case 0x25: vu_i_msubq(vu); return; - case 0x26: vu_i_subi(vu); return; - case 0x27: vu_i_msubi(vu); return; - case 0x28: vu_i_add(vu); return; - case 0x29: vu_i_madd(vu); return; - case 0x2A: vu_i_mul(vu); return; - case 0x2B: vu_i_max(vu); return; - case 0x2C: vu_i_sub(vu); return; - case 0x2D: vu_i_msub(vu); return; - case 0x2E: vu_i_opmsub(vu); return; - case 0x2F: vu_i_mini(vu); return; - } - } -} - -static inline void vu_execute_lower(struct vu_state* vu, uint32_t opcode) { + case 0x00: VU_DEC_UD_D_DST_S_SRC_T_BROADCAST(VU_FLD_X, vu_i_addx); return; + case 0x01: VU_DEC_UD_D_DST_S_SRC_T_BROADCAST(VU_FLD_Y, vu_i_addy); return; + case 0x02: VU_DEC_UD_D_DST_S_SRC_T_BROADCAST(VU_FLD_Z, vu_i_addz); return; + case 0x03: VU_DEC_UD_D_DST_S_SRC_T_BROADCAST(VU_FLD_W, vu_i_addw); return; + case 0x04: VU_DEC_UD_D_DST_S_SRC_T_BROADCAST(VU_FLD_X, vu_i_subx); return; + case 0x05: VU_DEC_UD_D_DST_S_SRC_T_BROADCAST(VU_FLD_Y, vu_i_suby); return; + case 0x06: VU_DEC_UD_D_DST_S_SRC_T_BROADCAST(VU_FLD_Z, vu_i_subz); return; + case 0x07: VU_DEC_UD_D_DST_S_SRC_T_BROADCAST(VU_FLD_W, vu_i_subw); return; + case 0x08: VU_DEC_UD_D_DST_S_SRC_T_BROADCAST(VU_FLD_X, vu_i_maddx); return; + case 0x09: VU_DEC_UD_D_DST_S_SRC_T_BROADCAST(VU_FLD_Y, vu_i_maddy); return; + case 0x0A: VU_DEC_UD_D_DST_S_SRC_T_BROADCAST(VU_FLD_Z, vu_i_maddz); return; + case 0x0B: VU_DEC_UD_D_DST_S_SRC_T_BROADCAST(VU_FLD_W, vu_i_maddw); return; + case 0x0C: VU_DEC_UD_D_DST_S_SRC_T_BROADCAST(VU_FLD_X, vu_i_msubx); return; + case 0x0D: VU_DEC_UD_D_DST_S_SRC_T_BROADCAST(VU_FLD_Y, vu_i_msuby); return; + case 0x0E: VU_DEC_UD_D_DST_S_SRC_T_BROADCAST(VU_FLD_Z, vu_i_msubz); return; + case 0x0F: VU_DEC_UD_D_DST_S_SRC_T_BROADCAST(VU_FLD_W, vu_i_msubw); return; + case 0x10: VU_DEC_UD_D_DST_S_SRC_T_BROADCAST(VU_FLD_X, vu_i_maxx); return; + case 0x11: VU_DEC_UD_D_DST_S_SRC_T_BROADCAST(VU_FLD_Y, vu_i_maxy); return; + case 0x12: VU_DEC_UD_D_DST_S_SRC_T_BROADCAST(VU_FLD_Z, vu_i_maxz); return; + case 0x13: VU_DEC_UD_D_DST_S_SRC_T_BROADCAST(VU_FLD_W, vu_i_maxw); return; + case 0x14: VU_DEC_UD_D_DST_S_SRC_T_BROADCAST(VU_FLD_X, vu_i_minix); return; + case 0x15: VU_DEC_UD_D_DST_S_SRC_T_BROADCAST(VU_FLD_Y, vu_i_miniy); return; + case 0x16: VU_DEC_UD_D_DST_S_SRC_T_BROADCAST(VU_FLD_Z, vu_i_miniz); return; + case 0x17: VU_DEC_UD_D_DST_S_SRC_T_BROADCAST(VU_FLD_W, vu_i_miniw); return; + case 0x18: VU_DEC_UD_D_DST_S_SRC_T_BROADCAST(VU_FLD_X, vu_i_mulx); return; + case 0x19: VU_DEC_UD_D_DST_S_SRC_T_BROADCAST(VU_FLD_Y, vu_i_muly); return; + case 0x1A: VU_DEC_UD_D_DST_S_SRC_T_BROADCAST(VU_FLD_Z, vu_i_mulz); return; + case 0x1B: VU_DEC_UD_D_DST_S_SRC_T_BROADCAST(VU_FLD_W, vu_i_mulw); return; + case 0x1C: VU_DEC_UD_D_DST_S_SRC(vu_i_mulq); return; + case 0x1D: VU_DEC_UD_D_DST_S_SRC(vu_i_maxi); return; + case 0x1E: VU_DEC_UD_D_DST_S_SRC(vu_i_muli); return; + case 0x1F: VU_DEC_UD_D_DST_S_SRC(vu_i_minii); return; + case 0x20: VU_DEC_UD_D_DST_S_SRC(vu_i_addq); return; + case 0x21: VU_DEC_UD_D_DST_S_SRC(vu_i_maddq); return; + case 0x22: VU_DEC_UD_D_DST_S_SRC(vu_i_addi); return; + case 0x23: VU_DEC_UD_D_DST_S_SRC(vu_i_maddi); return; + case 0x24: VU_DEC_UD_D_DST_S_SRC(vu_i_subq); return; + case 0x25: VU_DEC_UD_D_DST_S_SRC(vu_i_msubq); return; + case 0x26: VU_DEC_UD_D_DST_S_SRC(vu_i_subi); return; + case 0x27: VU_DEC_UD_D_DST_S_SRC(vu_i_msubi); return; + case 0x28: VU_DEC_UD_D_DST_S_SRC_T_SRC(vu_i_add); return; + case 0x29: VU_DEC_UD_D_DST_S_SRC_T_SRC(vu_i_madd); return; + case 0x2A: VU_DEC_UD_D_DST_S_SRC_T_SRC(vu_i_mul); return; + case 0x2B: VU_DEC_UD_D_DST_S_SRC_T_SRC(vu_i_max); return; + case 0x2C: VU_DEC_UD_D_DST_S_SRC_T_SRC(vu_i_sub); return; + case 0x2D: VU_DEC_UD_D_DST_S_SRC_T_SRC(vu_i_msub); return; + case 0x2E: VU_DEC_OPMSUB(); return; + case 0x2F: VU_DEC_UD_D_DST_S_SRC_T_SRC(vu_i_mini); return; + } + } +} + +void vu_decode_lower(struct vu_state* vu, uint32_t opcode) { + vu->lower.ld_d = (opcode >> 6) & 0x1f; + vu->lower.ld_s = (opcode >> 11) & 0x1f; + vu->lower.ld_t = (opcode >> 16) & 0x1f; + vu->lower.ld_sf = (opcode >> 21) & 3; + vu->lower.ld_tf = (opcode >> 23) & 3; + vu->lower.ld_imm5 = ((int32_t)(((opcode >> 6) & 0x1f) << 27)) >> 27; + vu->lower.ld_imm11 = ((int32_t)((opcode & 0x7ff) << 21)) >> 21; + vu->lower.ld_imm12 = (((opcode >> 21) & 1) << 11) | (opcode & 0x7ff); + vu->lower.ld_imm15 = (opcode & 0x7ff) | ((opcode & 0x1e00000) >> 10); + vu->lower.ld_imm24 = opcode & 0xffffff; + + for (int i = 0; i < 4; i++) + vu->lower.ld_di[i] = opcode & (1 << (24 - i)); + + vu->lower.func = NULL; + vu->lower.dst.reg = 0; + vu->lower.dst.field = 0; + vu->lower.src[0].reg = 0; + vu->lower.src[0].field = 0; + vu->lower.src[1].reg = 0; + vu->lower.src[1].field = 0; + vu->lower.vi_src[0] = 0; + vu->lower.vi_src[1] = 0; + vu->lower.vi_dst = 0; + switch ((opcode & 0xFE000000) >> 25) { - case 0x00: vu_i_lq(vu); return; - case 0x01: vu_i_sq(vu); return; - case 0x04: vu_i_ilw(vu); return; - case 0x05: vu_i_isw(vu); return; - case 0x08: vu_i_iaddiu(vu); return; - case 0x09: vu_i_isubiu(vu); return; - case 0x10: vu_i_fceq(vu); return; - case 0x11: vu_i_fcset(vu); return; - case 0x12: vu_i_fcand(vu); return; - case 0x13: vu_i_fcor(vu); return; - case 0x14: vu_i_fseq(vu); return; - case 0x15: vu_i_fsset(vu); return; - case 0x16: vu_i_fsand(vu); return; - case 0x17: vu_i_fsor(vu); return; - case 0x18: vu_i_fmeq(vu); return; - case 0x1A: vu_i_fmand(vu); return; - case 0x1B: vu_i_fmor(vu); return; - case 0x1C: vu_i_fcget(vu); return; - case 0x20: vu_i_b(vu); return; - case 0x21: vu_i_bal(vu); return; - case 0x24: vu_i_jr(vu); return; - case 0x25: vu_i_jalr(vu); return; - case 0x28: vu_i_ibeq(vu); return; - case 0x29: vu_i_ibne(vu); return; - case 0x2C: vu_i_ibltz(vu); return; - case 0x2D: vu_i_ibgtz(vu); return; - case 0x2E: vu_i_iblez(vu); return; - case 0x2F: vu_i_ibgez(vu); return; + case 0x00: VU_DEC_LD_T_DST_S_VISRC(vu_i_lq); return; + case 0x01: VU_DEC_LD_S_SRC_T_VISRC(vu_i_sq); return; + case 0x04: VU_DEC_LD_T_VIDST_S_VISRC(vu_i_ilw); return; + case 0x05: VU_DEC_LD_S_VISRC_T_VISRC(vu_i_isw); return; + case 0x08: VU_DEC_LD_T_VIDST_S_VISRC(vu_i_iaddiu); return; + case 0x09: VU_DEC_LD_T_VIDST_S_VISRC(vu_i_isubiu); return; + case 0x10: VU_DEC_LD_VIDST(1, vu_i_fceq); return; + case 0x11: VU_DEC_LD_NONE(vu_i_fcset); return; + case 0x12: VU_DEC_LD_VIDST(1, vu_i_fcand); return; + case 0x13: VU_DEC_LD_VIDST(1, vu_i_fcor); return; + case 0x14: VU_DEC_LD_T_VIDST(vu_i_fseq); return; + case 0x15: VU_DEC_LD_NONE(vu_i_fsset); return; + case 0x16: VU_DEC_LD_T_VIDST(vu_i_fsand); return; + case 0x17: VU_DEC_LD_T_VIDST(vu_i_fsor); return; + case 0x18: VU_DEC_LD_T_VIDST_S_VISRC(vu_i_fmeq); return; + case 0x1A: VU_DEC_LD_T_VIDST_S_VISRC(vu_i_fmand); return; + case 0x1B: VU_DEC_LD_T_VIDST_S_VISRC(vu_i_fmor); return; + case 0x1C: VU_DEC_LD_T_VIDST(vu_i_fcget); return; + case 0x20: VU_DEC_LD_NONE(vu_i_b); return; + case 0x21: VU_DEC_LD_T_VIDST(vu_i_bal); return; + case 0x24: VU_DEC_LD_S_VISRC(vu_i_jr); return; + case 0x25: VU_DEC_LD_T_VIDST_S_VISRC(vu_i_jalr); return; + case 0x28: VU_DEC_LD_S_VISRC_T_VISRC(vu_i_ibeq); return; + case 0x29: VU_DEC_LD_S_VISRC_T_VISRC(vu_i_ibne); return; + case 0x2C: VU_DEC_LD_S_VISRC(vu_i_ibltz); return; + case 0x2D: VU_DEC_LD_S_VISRC(vu_i_ibgtz); return; + case 0x2E: VU_DEC_LD_S_VISRC(vu_i_iblez); return; + case 0x2F: VU_DEC_LD_S_VISRC(vu_i_ibgez); return; case 0x40: { if ((opcode & 0x3C) == 0x3C) { switch (((opcode & 0x7C0) >> 4) | (opcode & 3)) { - case 0x30: vu_i_move(vu); return; - case 0x31: vu_i_mr32(vu); return; - case 0x34: vu_i_lqi(vu); return; - case 0x35: vu_i_sqi(vu); return; - case 0x36: vu_i_lqd(vu); return; - case 0x37: vu_i_sqd(vu); return; - case 0x38: vu_i_div(vu); return; - case 0x39: vu_i_sqrt(vu); return; - case 0x3A: vu_i_rsqrt(vu); return; - case 0x3B: vu_i_waitq(vu); return; - case 0x3C: vu_i_mtir(vu); return; - case 0x3D: vu_i_mfir(vu); return; - case 0x3E: vu_i_ilwr(vu); return; - case 0x3F: vu_i_iswr(vu); return; - case 0x40: vu_i_rnext(vu); return; - case 0x41: vu_i_rget(vu); return; - case 0x42: vu_i_rinit(vu); return; - case 0x43: vu_i_rxor(vu); return; - case 0x64: vu_i_mfp(vu); return; - case 0x68: vu_i_xtop(vu); return; - case 0x69: vu_i_xitop(vu); return; - case 0x6C: vu_i_xgkick(vu); return; - case 0x70: vu_i_esadd(vu); return; - case 0x71: vu_i_ersadd(vu); return; - case 0x72: vu_i_eleng(vu); return; - case 0x73: vu_i_erleng(vu); return; - case 0x74: vu_i_eatanxy(vu); return; - case 0x75: vu_i_eatanxz(vu); return; - case 0x76: vu_i_esum(vu); return; - case 0x78: vu_i_esqrt(vu); return; - case 0x79: vu_i_ersqrt(vu); return; - case 0x7A: vu_i_ercpr(vu); return; - case 0x7B: vu_i_waitp(vu); return; - case 0x7C: vu_i_esin(vu); return; - case 0x7D: vu_i_eatan(vu); return; - case 0x7E: vu_i_eexp(vu); return; + case 0x30: VU_DEC_LD_T_DST_S_SRC(vu_i_move); return; + case 0x31: VU_DEC_MR32(); return; + case 0x34: VU_DEC_LD_T_DST_S_VISRC_S_VIDST(vu_i_lqi); return; + case 0x35: VU_DEC_LD_S_SRC_T_VISRC_T_VIDST(vu_i_sqi); return; + case 0x36: VU_DEC_LD_T_DST_S_VISRC_S_VIDST(vu_i_lqd); return; + case 0x37: VU_DEC_LD_S_SRC_T_VISRC_T_VIDST(vu_i_sqd); return; + case 0x38: VU_DEC_LD_S_SF_SRC_T_TF_SRC(vu_i_div); return; + case 0x39: VU_DEC_LD_T_TF_SRC(vu_i_sqrt); return; + case 0x3A: VU_DEC_LD_S_SF_SRC_T_TF_SRC(vu_i_rsqrt); return; + case 0x3B: VU_DEC_LD_NONE(vu_i_waitq); return; + case 0x3C: VU_DEC_LD_T_VIDST_S_SF_SRC(vu_i_mtir); return; + case 0x3D: VU_DEC_LD_T_DST_S_VISRC(vu_i_mfir); return; + case 0x3E: VU_DEC_LD_T_VIDST_S_VISRC(vu_i_ilwr); return; + case 0x3F: VU_DEC_LD_T_VISRC_S_VISRC(vu_i_iswr); return; + case 0x40: VU_DEC_LD_T_DST(vu_i_rnext); return; + case 0x41: VU_DEC_LD_T_DST(vu_i_rget); return; + case 0x42: VU_DEC_LD_S_SF_SRC(vu_i_rinit); return; + case 0x43: VU_DEC_LD_S_SF_SRC(vu_i_rxor); return; + case 0x64: VU_DEC_LD_T_DST(vu_i_mfp); return; + case 0x68: VU_DEC_LD_T_VIDST(vu_i_xtop); return; + case 0x69: VU_DEC_LD_T_VIDST(vu_i_xitop); return; + case 0x6C: VU_DEC_LD_S_VISRC(vu_i_xgkick); return; + case 0x70: VU_DEC_LD_S_FLD_SRC(VU_FLD_X | VU_FLD_Y | VU_FLD_Z, vu_i_esadd); return; + case 0x71: VU_DEC_LD_S_FLD_SRC(VU_FLD_X | VU_FLD_Y | VU_FLD_Z, vu_i_ersadd); return; + case 0x72: VU_DEC_LD_S_FLD_SRC(VU_FLD_X | VU_FLD_Y | VU_FLD_Z, vu_i_eleng); return; + case 0x73: VU_DEC_LD_S_FLD_SRC(VU_FLD_X | VU_FLD_Y | VU_FLD_Z, vu_i_erleng); return; + case 0x74: VU_DEC_LD_S_FLD_SRC(VU_FLD_X | VU_FLD_Y, vu_i_eatanxy); return; + case 0x75: VU_DEC_LD_S_FLD_SRC(VU_FLD_X | VU_FLD_Z, vu_i_eatanxz); return; + case 0x76: VU_DEC_LD_S_FLD_SRC(VU_FLD_X | VU_FLD_Y | VU_FLD_Z | VU_FLD_W, vu_i_esum); return; + case 0x78: VU_DEC_LD_S_SF_SRC(vu_i_esqrt); return; + case 0x79: VU_DEC_LD_S_SF_SRC(vu_i_ersqrt); return; + case 0x7A: VU_DEC_LD_S_SF_SRC(vu_i_ercpr); return; + case 0x7B: VU_DEC_LD_NONE(vu_i_waitp); return; + case 0x7C: VU_DEC_LD_S_SF_SRC(vu_i_esin); return; + case 0x7D: VU_DEC_LD_S_SF_SRC(vu_i_eatan); return; + case 0x7E: VU_DEC_LD_S_SF_SRC(vu_i_eexp); return; } } else { switch (opcode & 0x3F) { - case 0x30: vu_i_iadd(vu); return; - case 0x31: vu_i_isub(vu); return; - case 0x32: vu_i_iaddi(vu); return; - case 0x34: vu_i_iand(vu); return; - case 0x35: vu_i_ior(vu); return; + case 0x30: VU_DEC_LD_D_VIDST_S_VISRC_T_VISRC(vu_i_iadd); return; + case 0x31: VU_DEC_LD_D_VIDST_S_VISRC_T_VISRC(vu_i_isub); return; + case 0x32: VU_DEC_LD_T_VIDST_S_VISRC(vu_i_iaddi); return; + case 0x34: VU_DEC_LD_D_VIDST_S_VISRC_T_VISRC(vu_i_iand); return; + case 0x35: VU_DEC_LD_D_VIDST_S_VISRC_T_VISRC(vu_i_ior); return; } } } break; @@ -2750,8 +2993,6 @@ void vu_execute_program(struct vu_state* vu, uint32_t addr) { vu->tpc = addr; vu->next_tpc = addr + 1; - vu->upper = 0; - vu->lower = 0; vu->i_bit = 0; vu->e_bit = 0; vu->m_bit = 0; @@ -2773,36 +3014,83 @@ void vu_execute_program(struct vu_state* vu, uint32_t addr) { delayed_e_bit = vu->e_bit != 0; - vu->upper = liw >> 32; - vu->lower = liw & 0xffffffff; - vu->i_bit = (vu->upper & 0x80000000) != 0; - vu->e_bit = (vu->upper & 0x40000000) != 0; - vu->m_bit = (vu->upper & 0x20000000) != 0; - vu->d_bit = (vu->upper & 0x10000000) != 0; - vu->t_bit = (vu->upper & 0x08000000) != 0; + uint32_t upper = liw >> 32; + uint32_t lower = liw & 0xffffffff; + + vu->i_bit = (upper & 0x80000000) != 0; + vu->e_bit = (upper & 0x40000000) != 0; + vu->m_bit = (upper & 0x20000000) != 0; + vu->d_bit = (upper & 0x10000000) != 0; + vu->t_bit = (upper & 0x08000000) != 0; vu->q_delay--; vu_update_status(vu); + + vu_decode_upper(vu, upper & 0x7ffffff); - // printf("%04x: %08x %08x %s", tpc, vu->upper, vu->lower, vu->e_bit ? "[e] " : " "); - - // vu->status = vu->mac_pipeline[3]; + // char ubuf[512]; + // printf("%04x: %08x %08x ", tpc, upper, lower); + // printf("%-40s", vu_disassemble_upper(ubuf, upper & 0x7ffffff, &ds)); - vu_execute_upper(vu, vu->upper & 0x7ffffff); - if (vu->i_bit) { - // printf("loi %08x\n", vu->lower); + // printf("loi 0x%08x\n", lower); + + vu->upper.func(vu, &vu->upper); // LOI - vu->i.u32 = vu->lower; - } else { - // char ud[512], ld[512]; + vu->i.u32 = lower; + vu->lower.func = NULL; + vu->lower.dst.reg = 0; + vu->lower.dst.field = 0; + vu->lower.src[0].reg = 0; + vu->lower.src[0].field = 0; + vu->lower.src[1].reg = 0; + vu->lower.src[1].field = 0; + vu->lower.vi_src[0] = 0; + vu->lower.vi_src[1] = 0; + vu->lower.vi_dst = 0; + } else { + vu_decode_lower(vu, lower); + + // char lbuf[512]; + // printf("%-40s\n", vu_disassemble_lower(lbuf, lower & 0xffffffff, &ds)); + + int hazard0 = vu->upper.dst.reg == vu->lower.src[0].reg; + int hazard1 = vu->upper.dst.reg == vu->lower.src[1].reg; + int hazard2 = vu->upper.dst.reg == vu->lower.dst.reg; + + if (!vu->upper.dst.reg) { + vu->upper.func(vu, &vu->upper); + vu->lower.func(vu, &vu->lower); + } else if (hazard0 || hazard1) { + // Upper instruction writes to a register that the lower + // instruction reads from. In this case the lower instruction + // gets the previous value of the register, executing the lower + // instruction first does the trick. + + vu->lower.func(vu, &vu->lower); + vu->upper.func(vu, &vu->upper); + } else if (hazard2) { + // Upper and lower instructions write to the same register. + // In this case the upper instruction takes priority, so we + // restore the value of the register after executing the lower + // instruction. + + vu->upper.func(vu, &vu->upper); + + struct vu_reg tmp = vu->vf[vu->upper.dst.reg]; + + vu->lower.func(vu, &vu->lower); + + vu->vf[vu->upper.dst.reg] = tmp; + } else { + vu->upper.func(vu, &vu->upper); + vu->lower.func(vu, &vu->lower); + } + } - // printf("%-40s%-40s\n", vu_disassemble_upper(ud, vu->upper, &ds), vu_disassemble_lower(ld, vu->lower, &ds)); - vu_execute_lower(vu, vu->lower); - } vu->mac_pipeline[3] = vu->mac_pipeline[2]; vu->mac_pipeline[2] = vu->mac_pipeline[1]; @@ -2937,8 +3225,6 @@ void ps2_vu_reset(struct vu_state* vu) { vu->clip_pipeline[3] = 0; vu->tpc = 0; vu->next_tpc = 1; - vu->upper = 0; - vu->lower = 0; vu->i_bit = 0; vu->e_bit = 0; vu->m_bit = 0; @@ -2948,4 +3234,12 @@ void ps2_vu_reset(struct vu_state* vu) { vu->vf[0].w = 1.0; } +void ps2_vu_decode_upper(struct vu_state* vu, uint32_t opcode) { + vu_decode_upper(vu, opcode); +} + +void ps2_vu_decode_lower(struct vu_state* vu, uint32_t opcode) { + vu_decode_lower(vu, opcode); +} + // #undef printf \ No newline at end of file diff --git a/src/ee/vu.h b/src/ee/vu.h index de6a81a..764a0f5 100644 --- a/src/ee/vu.h +++ b/src/ee/vu.h @@ -29,11 +29,41 @@ struct vu_reg { }; }; +struct vu_instruction { + uint32_t ld_di[4]; + uint32_t ld_d; + uint32_t ld_s; + uint32_t ld_t; + uint32_t ld_sf; + uint32_t ld_tf; + int32_t ld_imm5; + int32_t ld_imm11; + uint32_t ld_imm12; + uint32_t ld_imm15; + uint32_t ld_imm24; + uint32_t ud_di[4]; + uint32_t ud_d; + uint32_t ud_s; + uint32_t ud_t; + + struct { + int reg; + int field; + } dst, src[2]; + + int vi_dst; + int vi_src[2]; + + void (*func)(struct vu_state* vu, const struct vu_instruction* i); +}; + struct vu_state { struct vu_reg vf[32]; uint16_t vi[16]; struct vu_reg acc; + struct vu_instruction upper, lower; + uint64_t micro_mem[0x800]; uint128_t vu_mem[0x400]; @@ -41,9 +71,6 @@ struct vu_state { int vu_mem_size; int id; - uint32_t upper; - uint32_t lower; - int i_bit; int e_bit; int m_bit; @@ -117,172 +144,172 @@ void vu_init(struct vu_state* vu, int id, struct ps2_gif* gif, struct ps2_vif* v void vu_destroy(struct vu_state* vu); // Upper pipeline -void vu_i_abs(struct vu_state* vu); -void vu_i_add(struct vu_state* vu); -void vu_i_addi(struct vu_state* vu); -void vu_i_addq(struct vu_state* vu); -void vu_i_addx(struct vu_state* vu); -void vu_i_addy(struct vu_state* vu); -void vu_i_addz(struct vu_state* vu); -void vu_i_addw(struct vu_state* vu); -void vu_i_adda(struct vu_state* vu); -void vu_i_addai(struct vu_state* vu); -void vu_i_addaq(struct vu_state* vu); -void vu_i_addax(struct vu_state* vu); -void vu_i_adday(struct vu_state* vu); -void vu_i_addaz(struct vu_state* vu); -void vu_i_addaw(struct vu_state* vu); -void vu_i_sub(struct vu_state* vu); -void vu_i_subi(struct vu_state* vu); -void vu_i_subq(struct vu_state* vu); -void vu_i_subx(struct vu_state* vu); -void vu_i_suby(struct vu_state* vu); -void vu_i_subz(struct vu_state* vu); -void vu_i_subw(struct vu_state* vu); -void vu_i_suba(struct vu_state* vu); -void vu_i_subai(struct vu_state* vu); -void vu_i_subaq(struct vu_state* vu); -void vu_i_subax(struct vu_state* vu); -void vu_i_subay(struct vu_state* vu); -void vu_i_subaz(struct vu_state* vu); -void vu_i_subaw(struct vu_state* vu); -void vu_i_mul(struct vu_state* vu); -void vu_i_muli(struct vu_state* vu); -void vu_i_mulq(struct vu_state* vu); -void vu_i_mulx(struct vu_state* vu); -void vu_i_muly(struct vu_state* vu); -void vu_i_mulz(struct vu_state* vu); -void vu_i_mulw(struct vu_state* vu); -void vu_i_mula(struct vu_state* vu); -void vu_i_mulai(struct vu_state* vu); -void vu_i_mulaq(struct vu_state* vu); -void vu_i_mulax(struct vu_state* vu); -void vu_i_mulay(struct vu_state* vu); -void vu_i_mulaz(struct vu_state* vu); -void vu_i_mulaw(struct vu_state* vu); -void vu_i_madd(struct vu_state* vu); -void vu_i_maddi(struct vu_state* vu); -void vu_i_maddq(struct vu_state* vu); -void vu_i_maddx(struct vu_state* vu); -void vu_i_maddy(struct vu_state* vu); -void vu_i_maddz(struct vu_state* vu); -void vu_i_maddw(struct vu_state* vu); -void vu_i_madda(struct vu_state* vu); -void vu_i_maddai(struct vu_state* vu); -void vu_i_maddaq(struct vu_state* vu); -void vu_i_maddax(struct vu_state* vu); -void vu_i_madday(struct vu_state* vu); -void vu_i_maddaz(struct vu_state* vu); -void vu_i_maddaw(struct vu_state* vu); -void vu_i_msub(struct vu_state* vu); -void vu_i_msubi(struct vu_state* vu); -void vu_i_msubq(struct vu_state* vu); -void vu_i_msubx(struct vu_state* vu); -void vu_i_msuby(struct vu_state* vu); -void vu_i_msubz(struct vu_state* vu); -void vu_i_msubw(struct vu_state* vu); -void vu_i_msuba(struct vu_state* vu); -void vu_i_msubai(struct vu_state* vu); -void vu_i_msubaq(struct vu_state* vu); -void vu_i_msubax(struct vu_state* vu); -void vu_i_msubay(struct vu_state* vu); -void vu_i_msubaz(struct vu_state* vu); -void vu_i_msubaw(struct vu_state* vu); -void vu_i_max(struct vu_state* vu); -void vu_i_maxi(struct vu_state* vu); -void vu_i_maxx(struct vu_state* vu); -void vu_i_maxy(struct vu_state* vu); -void vu_i_maxz(struct vu_state* vu); -void vu_i_maxw(struct vu_state* vu); -void vu_i_mini(struct vu_state* vu); -void vu_i_minii(struct vu_state* vu); -void vu_i_minix(struct vu_state* vu); -void vu_i_miniy(struct vu_state* vu); -void vu_i_miniz(struct vu_state* vu); -void vu_i_miniw(struct vu_state* vu); -void vu_i_opmula(struct vu_state* vu); -void vu_i_opmsub(struct vu_state* vu); -void vu_i_nop(struct vu_state* vu); -void vu_i_ftoi0(struct vu_state* vu); -void vu_i_ftoi4(struct vu_state* vu); -void vu_i_ftoi12(struct vu_state* vu); -void vu_i_ftoi15(struct vu_state* vu); -void vu_i_itof0(struct vu_state* vu); -void vu_i_itof4(struct vu_state* vu); -void vu_i_itof12(struct vu_state* vu); -void vu_i_itof15(struct vu_state* vu); -void vu_i_clip(struct vu_state* vu); +void vu_i_abs(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_add(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_addi(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_addq(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_addx(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_addy(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_addz(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_addw(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_adda(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_addai(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_addaq(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_addax(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_adday(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_addaz(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_addaw(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_sub(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_subi(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_subq(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_subx(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_suby(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_subz(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_subw(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_suba(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_subai(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_subaq(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_subax(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_subay(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_subaz(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_subaw(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_mul(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_muli(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_mulq(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_mulx(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_muly(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_mulz(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_mulw(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_mula(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_mulai(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_mulaq(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_mulax(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_mulay(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_mulaz(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_mulaw(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_madd(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_maddi(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_maddq(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_maddx(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_maddy(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_maddz(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_maddw(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_madda(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_maddai(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_maddaq(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_maddax(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_madday(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_maddaz(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_maddaw(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_msub(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_msubi(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_msubq(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_msubx(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_msuby(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_msubz(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_msubw(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_msuba(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_msubai(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_msubaq(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_msubax(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_msubay(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_msubaz(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_msubaw(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_max(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_maxi(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_maxx(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_maxy(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_maxz(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_maxw(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_mini(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_minii(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_minix(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_miniy(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_miniz(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_miniw(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_opmula(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_opmsub(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_nop(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_ftoi0(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_ftoi4(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_ftoi12(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_ftoi15(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_itof0(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_itof4(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_itof12(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_itof15(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_clip(struct vu_state* vu, const struct vu_instruction* ins); // Lower pipeline -void vu_i_b(struct vu_state* vu); -void vu_i_bal(struct vu_state* vu); -void vu_i_div(struct vu_state* vu); -void vu_i_eatan(struct vu_state* vu); -void vu_i_eatanxy(struct vu_state* vu); -void vu_i_eatanxz(struct vu_state* vu); -void vu_i_eexp(struct vu_state* vu); -void vu_i_eleng(struct vu_state* vu); -void vu_i_ercpr(struct vu_state* vu); -void vu_i_erleng(struct vu_state* vu); -void vu_i_ersadd(struct vu_state* vu); -void vu_i_ersqrt(struct vu_state* vu); -void vu_i_esadd(struct vu_state* vu); -void vu_i_esin(struct vu_state* vu); -void vu_i_esqrt(struct vu_state* vu); -void vu_i_esum(struct vu_state* vu); -void vu_i_fcand(struct vu_state* vu); -void vu_i_fceq(struct vu_state* vu); -void vu_i_fcget(struct vu_state* vu); -void vu_i_fcor(struct vu_state* vu); -void vu_i_fcset(struct vu_state* vu); -void vu_i_fmand(struct vu_state* vu); -void vu_i_fmeq(struct vu_state* vu); -void vu_i_fmor(struct vu_state* vu); -void vu_i_fsand(struct vu_state* vu); -void vu_i_fseq(struct vu_state* vu); -void vu_i_fsor(struct vu_state* vu); -void vu_i_fsset(struct vu_state* vu); -void vu_i_iadd(struct vu_state* vu); -void vu_i_iaddi(struct vu_state* vu); -void vu_i_iaddiu(struct vu_state* vu); -void vu_i_iand(struct vu_state* vu); -void vu_i_ibeq(struct vu_state* vu); -void vu_i_ibgez(struct vu_state* vu); -void vu_i_ibgtz(struct vu_state* vu); -void vu_i_iblez(struct vu_state* vu); -void vu_i_ibltz(struct vu_state* vu); -void vu_i_ibne(struct vu_state* vu); -void vu_i_ilw(struct vu_state* vu); -void vu_i_ilwr(struct vu_state* vu); -void vu_i_ior(struct vu_state* vu); -void vu_i_isub(struct vu_state* vu); -void vu_i_isubiu(struct vu_state* vu); -void vu_i_isw(struct vu_state* vu); -void vu_i_iswr(struct vu_state* vu); -void vu_i_jalr(struct vu_state* vu); -void vu_i_jr(struct vu_state* vu); -void vu_i_lq(struct vu_state* vu); -void vu_i_lqd(struct vu_state* vu); -void vu_i_lqi(struct vu_state* vu); -void vu_i_mfir(struct vu_state* vu); -void vu_i_mfp(struct vu_state* vu); -void vu_i_move(struct vu_state* vu); -void vu_i_mr32(struct vu_state* vu); -void vu_i_mtir(struct vu_state* vu); -void vu_i_rget(struct vu_state* vu); -void vu_i_rinit(struct vu_state* vu); -void vu_i_rnext(struct vu_state* vu); -void vu_i_rsqrt(struct vu_state* vu); -void vu_i_rxor(struct vu_state* vu); -void vu_i_sq(struct vu_state* vu); -void vu_i_sqd(struct vu_state* vu); -void vu_i_sqi(struct vu_state* vu); -void vu_i_sqrt(struct vu_state* vu); -void vu_i_waitp(struct vu_state* vu); -void vu_i_waitq(struct vu_state* vu); -void vu_i_xgkick(struct vu_state* vu); -void vu_i_xitop(struct vu_state* vu); -void vu_i_xtop(struct vu_state* vu); +void vu_i_b(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_bal(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_div(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_eatan(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_eatanxy(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_eatanxz(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_eexp(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_eleng(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_ercpr(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_erleng(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_ersadd(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_ersqrt(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_esadd(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_esin(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_esqrt(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_esum(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_fcand(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_fceq(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_fcget(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_fcor(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_fcset(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_fmand(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_fmeq(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_fmor(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_fsand(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_fseq(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_fsor(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_fsset(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_iadd(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_iaddi(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_iaddiu(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_iand(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_ibeq(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_ibgez(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_ibgtz(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_iblez(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_ibltz(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_ibne(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_ilw(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_ilwr(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_ior(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_isub(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_isubiu(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_isw(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_iswr(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_jalr(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_jr(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_lq(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_lqd(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_lqi(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_mfir(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_mfp(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_move(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_mr32(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_mtir(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_rget(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_rinit(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_rnext(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_rsqrt(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_rxor(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_sq(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_sqd(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_sqi(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_sqrt(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_waitp(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_waitq(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_xgkick(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_xitop(struct vu_state* vu, const struct vu_instruction* ins); +void vu_i_xtop(struct vu_state* vu, const struct vu_instruction* ins); // VU mem bus interface uint64_t ps2_vu_read8(struct vu_state* vu, uint32_t addr); @@ -298,6 +325,8 @@ void ps2_vu_write128(struct vu_state* vu, uint32_t addr, uint128_t data); void ps2_vu_write_vi(struct vu_state* vu, int index, uint32_t value); uint32_t ps2_vu_read_vi(struct vu_state* vu, int index); void ps2_vu_reset(struct vu_state* vu); +void ps2_vu_decode_upper(struct vu_state* vu, uint32_t opcode); +void ps2_vu_decode_lower(struct vu_state* vu, uint32_t opcode); void vu_cycle(struct vu_state* vu); void vu_execute_program(struct vu_state* vu, uint32_t addr); diff --git a/src/gs/gs.c b/src/gs/gs.c index cd7116b..8bab620 100644 --- a/src/gs/gs.c +++ b/src/gs/gs.c @@ -16,6 +16,8 @@ static inline void gs_test_gs_irq(struct ps2_gs* gs) { uint32_t stat = gs->csr & 0x1f; if (stat & (~mask)) { + // printf("gs: IRQ triggered! stat=%02x mask=%02x\n", stat, mask); + ps2_intc_irq(gs->ee_intc, EE_INTC_GS); } } @@ -70,14 +72,14 @@ void gs_handle_vblank_in(void* udata, int overshoot) { struct sched_event vblank_out_event; vblank_out_event.callback = gs_handle_vblank_out; - vblank_out_event.cycles = GS_VBLANK_NTSC; + vblank_out_event.cycles = GS_VBLANK_NTSC; vblank_out_event.name = "Vblank out event"; vblank_out_event.udata = gs; struct sched_event field_flip_event; field_flip_event.callback = gs_flip_field; - field_flip_event.cycles = 30000 * 4; + field_flip_event.cycles = 65622; field_flip_event.name = "Field flip event"; field_flip_event.udata = gs; @@ -319,6 +321,8 @@ uint64_t ps2_gs_read64(struct ps2_gs* gs, uint32_t addr) { // Hack toggle between FIFO empty and FIFO "Neither Empty nor Almost Full" gs->csr ^= 0x4000; + addr = (addr & 0xfffff000) | (addr & 0x3ff); + switch (addr) { case 0x12000000: return gs->csr | 0x551b0000; case 0x12000010: return gs->csr | 0x551b0000; @@ -339,6 +343,8 @@ uint64_t ps2_gs_read64(struct ps2_gs* gs, uint32_t addr) { case 0x12001010: return gs->csr | 0x551b0000; case 0x12001040: return gs->csr | 0x551b0000; case 0x12001080: return gs->siglblid; + + case 0x12001001: return (gs->csr >> 8) & 0xff; } printf("gs: Unhandled read from %08x\n", addr); @@ -376,17 +382,28 @@ void ps2_gs_write64(struct ps2_gs* gs, uint32_t addr, uint64_t data) { case 0x120000D0: gs->extwrite = data; return; case 0x120000E0: gs->bgcolor = data; return; case 0x12001000: { + if (data & 8) { + // Game is requesting vsync + // gs->vblank |= 1; + } + gs->csr = (gs->csr & 0xfffffe00) | (gs->csr & ~(data & 0xf)); - if (gs->signal_pending && ((gs->csr & 1) == 0)) { - gs->csr |= 1; + if (data & 1) { + if (gs->signal_pending) { + gs->siglblid &= ~0xffffffffull; + gs->siglblid |= gs->stall_sigid; + } } } return; case 0x12001010: { + int prev_signal = (gs->imr >> 8) & 1; + int new_signal = (data >> 8) & 1; + gs->imr = data; - if (gs->signal_pending && (((gs->imr >> 8) & 1) == 0)) { - gs->signal_pending = 0; + if (gs->signal_pending && (prev_signal && !new_signal)) { + gs->signal_pending--; ps2_intc_irq(gs->ee_intc, EE_INTC_GS); } @@ -676,30 +693,35 @@ void ps2_gs_write_internal(struct ps2_gs* gs, int reg, uint64_t data) { case 0x53: /* printf("gs: TRXDIR <- %016lx\n", data); */ gs->trxdir = data; gs->backend.transfer_start(gs, gs->backend.udata); return; case 0x54: gs->hwreg = data; gs->backend.transfer_write(gs, gs->backend.udata); return; case 0x60: /* printf("gs: SIGNAL <- %016lx\n", data); */ { + uint64_t mask = data >> 32; + uint64_t value = data & mask; + if (gs->csr & 1) { - gs->signal_pending = 1; + gs->signal_pending++; + + gs->stall_sigid = gs->siglblid & 0xffffffff; + gs->stall_sigid &= ~mask; + gs->stall_sigid |= value; return; } - gs->signal_pending = 0; + gs->signal_pending++; gs->signal = data; - uint64_t mask = data >> 32; - gs->csr |= 1; gs->siglblid &= ~mask; - gs->siglblid |= data & mask; + gs->siglblid |= value; gs_test_gs_irq(gs); } return; - case 0x61: { + case 0x61: /* printf("gs: FINISH <- %016lx\n", data); */ { // Trigger FINISH event gs->csr |= 2; gs_test_gs_irq(gs); } return; - case 0x62: { + case 0x62: /* printf("gs: LABEL <- %016lx\n", data); */ { gs->label = data; uint64_t mask = data >> 32; @@ -711,8 +733,6 @@ void ps2_gs_write_internal(struct ps2_gs* gs, int reg, uint64_t data) { // printf("gs: Invalid privileged register %02x write %016lx\n", reg, data); return; - - exit(1); } } } diff --git a/src/gs/gs.h b/src/gs/gs.h index e8c6da6..6a5ac58 100644 --- a/src/gs/gs.h +++ b/src/gs/gs.h @@ -118,8 +118,10 @@ extern "C" { // EE clock: 294.912 MHz, 294912000 clocks/s // 294912000/60=4915200 clocks/frame -#define GS_FRAME_NTSC 4497600 // (240 * 9370) -#define GS_VBLANK_NTSC 417600 // (22 * 9370) +// #define GS_FRAME_NTSC (4497600) // (240 * 9370) +// #define GS_VBLANK_NTSC (417600) // (22 * 9370) +#define GS_FRAME_NTSC 4489019 // (240 * 9370) +#define GS_VBLANK_NTSC 431096 // (22 * 9370) #define GS_FRAME_PAL (286 * 9476) #define GS_VBLANK_PAL (26 * 9476) @@ -262,7 +264,11 @@ struct ps2_gs { uint32_t* vram; int vblank; + + // SIGNAL stuff int signal_pending; + int signal_stall; + uint32_t stall_sigid; // 1KB CLUT cache uint32_t clut_cache[0x100]; diff --git a/src/gs/renderer/null.cpp b/src/gs/renderer/null.cpp index 01da8bd..ec9acdb 100644 --- a/src/gs/renderer/null.cpp +++ b/src/gs/renderer/null.cpp @@ -1,3 +1,5 @@ +#include "renderer.hpp" + #include "null.hpp" void null_init(void* ctx, struct ps2_gs* gs, SDL_Window* window, SDL_GPUDevice* device) {} @@ -35,4 +37,10 @@ extern "C" void null_transfer_read(struct ps2_gs* gs, void* udata) {} void null_begin_render(void* udata, SDL_GPUCommandBuffer* command_buffer) {} void null_render(void* udata, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass) {} -void null_end_render(void* udata, SDL_GPUCommandBuffer* command_buffer) {} \ No newline at end of file +void null_end_render(void* udata, SDL_GPUCommandBuffer* command_buffer) {} + +renderer_stats* null_get_debug_stats(void* ctx) { + static renderer_stats stats = {}; + + return &stats; +} \ No newline at end of file diff --git a/src/gs/renderer/null.hpp b/src/gs/renderer/null.hpp index bad6fa9..0fe173e 100644 --- a/src/gs/renderer/null.hpp +++ b/src/gs/renderer/null.hpp @@ -18,6 +18,7 @@ void null_get_display_format(void* ctx, int* fmt); void null_get_interlace_mode(void* ctx, int* mode); void null_set_window_rect(void* ctx, int x, int y, int w, int h); void* null_get_buffer_data(void* ctx, int* w, int* h, int* bpp); +renderer_stats* null_get_debug_stats(void* ctx); const char* null_get_name(void* ctx); void null_begin_render(void* udata, SDL_GPUCommandBuffer* command_buffer); void null_render(void* udata, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass); diff --git a/src/gs/renderer/renderer.cpp b/src/gs/renderer/renderer.cpp index 8dcd7a3..fa19743 100644 --- a/src/gs/renderer/renderer.cpp +++ b/src/gs/renderer/renderer.cpp @@ -24,6 +24,7 @@ void renderer_init_null(renderer_state* renderer, struct ps2_gs* gs, SDL_Window* renderer->set_window_rect = null_set_window_rect; renderer->get_buffer_data = null_get_buffer_data; renderer->get_name = null_get_name; + renderer->get_debug_stats = null_get_debug_stats; renderer->begin_render = null_begin_render; renderer->render = null_render; renderer->end_render = null_end_render; @@ -54,6 +55,7 @@ void renderer_init_software(renderer_state* renderer, struct ps2_gs* gs, SDL_Win renderer->set_window_rect = software_set_window_rect; renderer->get_buffer_data = software_get_buffer_data; renderer->get_name = software_get_name; + renderer->get_debug_stats = software_get_debug_stats; renderer->begin_render = software_begin_render; renderer->render = software_render; renderer->end_render = software_end_render; @@ -83,6 +85,7 @@ void renderer_init_software_thread(renderer_state* renderer, struct ps2_gs* gs, renderer->get_interlace_mode = software_thread_get_interlace_mode; renderer->set_window_rect = software_thread_set_window_rect; renderer->get_buffer_data = software_thread_get_buffer_data; + renderer->get_debug_stats = software_thread_get_debug_stats; renderer->get_name = software_thread_get_name; renderer->begin_render = software_thread_begin_render; renderer->render = software_thread_render; @@ -158,6 +161,9 @@ void* renderer_get_buffer_data(renderer_state* renderer, int* w, int* h, int* bp const char* renderer_get_name(renderer_state* renderer) { return renderer->get_name(renderer->udata); } +renderer_stats* renderer_get_debug_stats(renderer_state* renderer) { + return renderer->get_debug_stats(renderer->udata); +} void renderer_destroy(renderer_state* renderer) { if (renderer->udata) diff --git a/src/gs/renderer/renderer.hpp b/src/gs/renderer/renderer.hpp index 78824d7..c478152 100644 --- a/src/gs/renderer/renderer.hpp +++ b/src/gs/renderer/renderer.hpp @@ -27,6 +27,18 @@ enum : int { RENDERER_SOFTWARE_THREAD }; +struct renderer_stats { + unsigned int primitives = 0; + unsigned int triangles = 0; + unsigned int lines = 0; + unsigned int points = 0; + unsigned int sprites = 0; + unsigned int texture_uploads = 0; + unsigned int texture_blits = 0; + unsigned int frames_rendered = 0; + float frame_latency = 0.0f; +}; + struct renderer_state { struct ps2_gs* gs = nullptr; void* udata = nullptr; @@ -46,6 +58,7 @@ struct renderer_state { void (*set_render_context)(void*, SDL_GPUCommandBuffer*, SDL_GPURenderPass*); void* (*get_buffer_data)(void*, int*, int*, int*) = nullptr; const char* (*get_name)(void*) = nullptr; + renderer_stats* (*get_debug_stats)(void*) = nullptr; // Rendering interface void (*begin_render)(void*, SDL_GPUCommandBuffer*); @@ -69,6 +82,7 @@ void renderer_get_display_format(renderer_state* renderer, int* fmt); void renderer_get_interlace_mode(renderer_state* renderer, int* mode); void renderer_set_window_rect(renderer_state* renderer, int x, int y, int w, int h); void* renderer_get_buffer_data(renderer_state* renderer, int* w, int* h, int* bpp); +renderer_stats* renderer_get_debug_stats(renderer_state* renderer); const char* renderer_get_name(renderer_state* renderer); void renderer_destroy(renderer_state* renderer); diff --git a/src/gs/renderer/software.cpp b/src/gs/renderer/software.cpp index b4feed0..25b175d 100644 --- a/src/gs/renderer/software.cpp +++ b/src/gs/renderer/software.cpp @@ -8,6 +8,8 @@ #include +renderer_stats dummy = {}; + int software_psmct32_block[] = { 0 , 1 , 4 , 5 , 16, 17, 20, 21, 2 , 3 , 6 , 7 , 18, 19, 22, 23, @@ -1793,4 +1795,8 @@ extern "C" void software_transfer_read(struct ps2_gs* gs, void* udata) { void software_begin_render(void* udata, SDL_GPUCommandBuffer* command_buffer) {} void software_render(void* udata, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass) {} -void software_end_render(void* udata, SDL_GPUCommandBuffer* command_buffer) {} \ No newline at end of file +void software_end_render(void* udata, SDL_GPUCommandBuffer* command_buffer) {} + +renderer_stats* software_get_debug_stats(void* udata) { + return &dummy; +} \ No newline at end of file diff --git a/src/gs/renderer/software.hpp b/src/gs/renderer/software.hpp index bf6a715..9bfd660 100644 --- a/src/gs/renderer/software.hpp +++ b/src/gs/renderer/software.hpp @@ -50,6 +50,7 @@ void software_get_display_format(void* ctx, int* fmt); void software_get_interlace_mode(void* ctx, int* mode); void software_set_window_rect(void* udata, int x, int y, int w, int h); void* software_get_buffer_data(void* udata, int* w, int* h, int* bpp); +renderer_stats* software_get_debug_stats(void* ctx); const char* software_get_name(void* ctx); void software_begin_render(void* udata, SDL_GPUCommandBuffer* command_buffer); void software_render(void* udata, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass); diff --git a/src/gs/renderer/software_thread.cpp b/src/gs/renderer/software_thread.cpp index 9154df0..67d5641 100644 --- a/src/gs/renderer/software_thread.cpp +++ b/src/gs/renderer/software_thread.cpp @@ -559,7 +559,10 @@ void software_thread_set_size(void* udata, int width, int height) { uint64_t display = 0, dispfb = 0; - if (en1) { + if (en1 && en2) { + display = ctx->gs->display1 > ctx->gs->display2 ? ctx->gs->display1 : ctx->gs->display2; + dispfb = ctx->gs->dispfb1 > ctx->gs->dispfb2 ? ctx->gs->dispfb1 : ctx->gs->dispfb2; + } else if (en1) { display = ctx->gs->display1; dispfb = ctx->gs->dispfb1; } else if (en2) { @@ -594,7 +597,16 @@ void software_thread_set_size(void* udata, int width, int height) { // tex_h /= 2; // } - // printf("gsr: Setting framebuffer size to %dx%d fmt=%02x\n", tex_w, tex_h, ctx->disp_fmt); + // Weird dobiestation hack, should fix Silent Hill 2, Choro Q HG, etc. + if (tex_h >= (tex_w * 1.3)) + tex_h = tex_h / 2; + + // printf("gsr: Setting framebuffer size to %dx%d fmt=%02x magh=%d magv=%d en=(%d,%d) dwh=(%d,%d) dxy=(%d,%d)\n", tex_w, tex_h, tex_fmt, magh, magv, en1, en2, + // (int)((display >> 32) & 0xfff) + 1, + // (int)((display >> 44) & 0x7ff) + 1, + // (int)(display & 0xfff), + // (int)((display >> 12) & 0xfff) + // ); // Do nothing if the size hasn't changed if (tex_w == ctx->tex_w && tex_h == ctx->tex_h && tex_fmt == ctx->disp_fmt) { @@ -1851,6 +1863,28 @@ static inline uint32_t gs_generic_read(struct ps2_gs* gs, uint32_t bp, uint32_t return data >> 28; } break; + case GS_PSMZ32: { + return gs->vram[psmz32_addr(bp, bw, u, v) & 0xfffff]; + } break; + case GS_PSMZ24: { + return gs->vram[psmz32_addr(bp, bw, u, v) & 0xfffff] & 0xffffff; + } break; + case GS_PSMZ16: { + uint32_t addr = psmz16_addr(bp, bw, u, v); + uint16_t* vram = (uint16_t*)(&gs->vram[addr & 0xfffff]); + + int idx = (u & 15) + ((v & 1) * 16); + + return vram[psmct16_shift[idx] & 0xfffff]; + } break; + case GS_PSMZ16S: { + uint32_t addr = psmz16s_addr(bp, bw, u, v); + uint16_t* vram = (uint16_t*)(&gs->vram[addr & 0xfffff]); + + int idx = (u & 15) + ((v & 1) * 16); + + return vram[psmct16_shift[idx] & 0xfffff]; + } break; default: { // printf("Unsupported PSMT %02x for generic read\n", gs->ctx->tbpsm); // exit(1); @@ -1863,8 +1897,11 @@ static inline void gs_generic_write(struct ps2_gs* gs, uint32_t bp, uint32_t bw, case GS_PSMCT32: gs->vram[psmct32_addr(bp, bw, u, v) & 0xfffff] = data; break; - case GS_PSMCT24: - gs->vram[psmct32_addr(bp, bw, u, v) & 0xfffff] = data; + case GS_PSMCT24: { + uint32_t addr = psmct32_addr(bp, bw, u, v) & 0xfffff; + + gs->vram[addr] = (gs->vram[addr] & 0xff000000) | (data & 0xffffff); + } break; break; case GS_PSMCT16: { uint32_t addr = psmct16_addr(bp, bw, u, v); @@ -1915,6 +1952,31 @@ static inline void gs_generic_write(struct ps2_gs* gs, uint32_t bp, uint32_t bw, gs->vram[addr] = (gs->vram[addr] & 0x0fffffff) | ((data & 0xf) << 28); } break; + case GS_PSMZ32: + gs->vram[psmz32_addr(bp, bw, u, v) & 0xfffff] = data; + break; + case GS_PSMZ24: { + uint32_t addr = psmz32_addr(bp, bw, u, v) & 0xfffff; + + gs->vram[addr] = (gs->vram[addr] & 0xff000000) | (data & 0xffffff); + } break; + break; + case GS_PSMZ16: { + uint32_t addr = psmz16_addr(bp, bw, u, v); + uint16_t* vram = (uint16_t*)(&gs->vram[addr & 0xfffff]); + + int idx = (u & 15) + ((v & 1) * 16); + + vram[psmct16_shift[idx] & 0xfffff] = data; + } break; + case GS_PSMZ16S: { + uint32_t addr = psmz16s_addr(bp, bw, u, v); + uint16_t* vram = (uint16_t*)(&gs->vram[addr & 0xfffff]); + + int idx = (u & 15) + ((v & 1) * 16); + + vram[psmct16_shift[idx] & 0xfffff] = data; + } break; default: { // printf("Unsupported PSMT %02x for write\n", gs->ctx->tbpsm); // exit(1); @@ -2060,11 +2122,10 @@ void render_triangle(struct ps2_gs* gs, void* udata) { area = EDGE(v0, v1, v2); } - // printf("triangle: v0=(%04x,%04x) v1=(%04x,%04x) v2=(%04x,%04x) v3=(%04x,%04x)\n", + // printf("triangle: v0=(%04x,%04x) v1=(%04x,%04x) v2=(%04x,%04x)\n", // v0.x, v0.y, // v1.x, v1.y, - // v2.x, v2.y, - // gs->vq[3].x, gs->vq[3].y + // v2.x, v2.y // ); v0.x -= gs->ctx->ofx; @@ -2106,7 +2167,12 @@ void render_triangle(struct ps2_gs* gs, void* udata) { int w1_row = EDGE(v2, v0, p); int w2_row = EDGE(v0, v1, p); - // if (gs->fge) + // printf("triangle: v0=(%d.%d,%d.%d) v1=(%d.%d,%d.%d) v2=(%d.%d,%d.%d) v3=(%d.%d,%d.%d)\n", + // v0.x >> 4, (v0.x & 0xf) * 625, v0.y >> 4, (v0.y & 0xf) * 625, + // v1.x >> 4, (v1.x & 0xf) * 625, v1.y >> 4, (v1.y & 0xf) * 625, + // v2.x >> 4, (v2.x & 0xf) * 625, v2.y >> 4, (v2.y & 0xf) * 625, + // gs->vq[3].x >> 4, (gs->vq[3].x & 0xf) * 625, gs->vq[3].y >> 4, (gs->vq[3].y & 0xf) * 625 + // ); for (p.y = ymin; p.y < ymax; p.y += 16) { // Barycentric coordinates at start of row @@ -2727,6 +2793,8 @@ void transfer_start(struct ps2_gs* gs, void* udata) { if (ctx->xdir == 2) { ctx->render_mtx.lock(); + ctx->stats.texture_blits++; + software_thread_vram_blit(gs, ctx); ctx->render_mtx.unlock(); @@ -2734,6 +2802,8 @@ void transfer_start(struct ps2_gs* gs, void* udata) { printf("gs: Read transfer requested\n"); // exit(1); + } else { + ctx->stats.texture_uploads++; } } @@ -2755,6 +2825,9 @@ void transfer_read(struct ps2_gs* gs, void* udata) { extern "C" void software_thread_render_point(struct ps2_gs* gs, void* udata) { software_thread_state* ctx = (software_thread_state*)udata; + ctx->stats.points++; + ctx->stats.primitives++; + ctx->queue_mtx.lock(); ctx->render_queue.push(render_data()); @@ -2768,6 +2841,9 @@ extern "C" void software_thread_render_point(struct ps2_gs* gs, void* udata) { extern "C" void software_thread_render_line(struct ps2_gs* gs, void* udata) { software_thread_state* ctx = (software_thread_state*)udata; + ctx->stats.lines++; + ctx->stats.primitives++; + ctx->queue_mtx.lock(); ctx->render_queue.push(render_data()); @@ -2781,6 +2857,9 @@ extern "C" void software_thread_render_line(struct ps2_gs* gs, void* udata) { extern "C" void software_thread_render_triangle(struct ps2_gs* gs, void* udata) { software_thread_state* ctx = (software_thread_state*)udata; + ctx->stats.triangles++; + ctx->stats.primitives++; + ctx->queue_mtx.lock(); ctx->render_queue.push(render_data()); @@ -2794,6 +2873,9 @@ extern "C" void software_thread_render_triangle(struct ps2_gs* gs, void* udata) extern "C" void software_thread_render_sprite(struct ps2_gs* gs, void* udata) { software_thread_state* ctx = (software_thread_state*)udata; + ctx->stats.sprites++; + ctx->stats.primitives++; + ctx->queue_mtx.lock(); ctx->render_queue.push(render_data()); @@ -2978,7 +3060,7 @@ void software_thread_begin_render(void* udata, SDL_GPUCommandBuffer* command_buf if (ctx->gs->smode2 & 2) { gs_blit_dispfb_deinterlace_frame(ctx, dfb); } else { - gs_blit_dispfb_deinterlace_field(ctx, dfb); + gs_blit_dispfb_no_deinterlace(ctx, dfb); } } else { gs_blit_dispfb_no_deinterlace(ctx, dfb); @@ -3159,6 +3241,16 @@ void software_thread_render(void* udata, SDL_GPUCommandBuffer* command_buffer, S if (!ctx->texture) return; + ctx->stats.frames_rendered++; + ctx->last_frame_stats = ctx->stats; + ctx->stats.lines = 0; + ctx->stats.points = 0; + ctx->stats.triangles = 0; + ctx->stats.sprites = 0; + ctx->stats.primitives = 0; + ctx->stats.texture_uploads = 0; + ctx->stats.texture_blits = 0; + SDL_BindGPUGraphicsPipeline(render_pass, ctx->pipeline); // bind the vertex buffer @@ -3186,4 +3278,10 @@ void software_thread_render(void* udata, SDL_GPUCommandBuffer* command_buffer, S void software_thread_end_render(void* udata, SDL_GPUCommandBuffer* command_buffer) { // Nothing for now +} + +renderer_stats* software_thread_get_debug_stats(void* udata) { + software_thread_state* ctx = (software_thread_state*)udata; + + return &ctx->last_frame_stats; } \ No newline at end of file diff --git a/src/gs/renderer/software_thread.hpp b/src/gs/renderer/software_thread.hpp index 05c283e..616a0f9 100644 --- a/src/gs/renderer/software_thread.hpp +++ b/src/gs/renderer/software_thread.hpp @@ -78,6 +78,9 @@ struct software_thread_state { unsigned int frame = 0; uint32_t* buf = nullptr; + + renderer_stats stats = { 0 }; + renderer_stats last_frame_stats = { 0 }; }; void software_thread_init(void* udata, struct ps2_gs* gs, SDL_Window* window, SDL_GPUDevice* device); @@ -93,6 +96,7 @@ void software_thread_get_display_format(void* udata, int* fmt); void software_thread_get_interlace_mode(void* udata, int* mode); void software_thread_set_window_rect(void* udata, int x, int y, int w, int h); void* software_thread_get_buffer_data(void* udata, int* w, int* h, int* bpp); +renderer_stats* software_thread_get_debug_stats(void* udata); const char* software_thread_get_name(void* udata); void software_thread_begin_render(void* udata, SDL_GPUCommandBuffer* command_buffer); void software_thread_render(void* udata, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass); diff --git a/src/iop/bus.c b/src/iop/bus.c index 7d84996..a5515ab 100644 --- a/src/iop/bus.c +++ b/src/iop/bus.c @@ -123,18 +123,7 @@ uint32_t iop_bus_read8(void* udata, uint32_t addr) { MAP_MEM_READ(8, 0x1E000000, 0x1E3FFFFF, bios, rom1); MAP_MEM_READ(8, 0x1E400000, 0x1E7FFFFF, bios, rom2); - // Namco System 246 DIP switches - if (addr == 0x1f803204) { - return 0x81; - } - - if (addr == 0x1f803100) { - return 0x82; - } - - if (addr == 0x1f803200) { - return 0x83; - } + if (addr == 0x1f80146e) { return 0x30; } printf("iop_bus: Unhandled 8-bit read from physical address 0x%08x\n", addr); @@ -162,10 +151,21 @@ uint32_t iop_bus_read16(void* udata, uint32_t addr) { MAP_MEM_READ(16, 0x1E000000, 0x1E3FFFFF, bios, rom1); MAP_MEM_READ(16, 0x1E400000, 0x1E7FFFFF, bios, rom2); - // PCMCIA (CXD9566) + // 0x20 - PCMCIA (CXD9566) + // 0x30 - Expansion bay if (addr == 0x1f80146e) { return 0x30; } - // printf("iop_bus: Unhandled 16-bit read from physical address 0x%08x\n", addr); + // SPEED rev3 (Capabilities) + // bit 0 - SMAP + // bit 1 - ATA + // bit 3 - UART + // bit 4 - DVR + // bit 5 - FLASH + // if (addr == 0x10000004) { return 0x03; } + // if (addr == 0x1000205c) { return 0xffff; } + // if (addr == 0x1000205e) { return 0xffff; } + + printf("iop_bus: Unhandled 16-bit read from physical address 0x%08x\n", addr); return 0; } diff --git a/src/iop/cdvd.c b/src/iop/cdvd.c index 6d2608c..000cb87 100644 --- a/src/iop/cdvd.c +++ b/src/iop/cdvd.c @@ -8,6 +8,32 @@ #include "cdvd.h" +#define printf(fmt,...)(0) + +struct nvram_layout g_spc970_layout = { + .bios_version = 0x00000000, + .config0_offset = 0x00000280, + .config1_offset = 0x00000300, + .config2_offset = 0x00000200, + .console_id_offset = 0x000001C8, + .ilink_id_offset = 0x000001C0, + .modelnum_offset = 0x000001A0, + .regparams_offset = 0x00000180, + .mac_offset = 0x00000198 +}; + +struct nvram_layout g_dragon_layout = { + .bios_version = 0x00000146, + .config0_offset = 0x00000270, + .config1_offset = 0x000002B0, + .config2_offset = 0x00000200, + .console_id_offset = 0x000001F0, + .ilink_id_offset = 0x000001E0, + .modelnum_offset = 0x000001B0, + .regparams_offset = 0x00000180, + .mac_offset = 0x00000198 +}; + static const uint8_t nvram_init_data[1024] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -176,7 +202,7 @@ static inline void cdvd_init_s_fifo(struct ps2_cdvd* cdvd, int size) { cdvd->s_stat &= ~0x40; } -static inline void cdvd_s_mechacon_version(struct ps2_cdvd* cdvd) { +static inline void cdvd_s_mechacon_cmd(struct ps2_cdvd* cdvd) { switch (cdvd->s_params[0]) { case 0x00: { cdvd_init_s_fifo(cdvd, 4); @@ -252,26 +278,31 @@ static inline void cdvd_s_write_nvram(struct ps2_cdvd* cdvd) { static inline void cdvd_s_read_ilink_id(struct ps2_cdvd* cdvd) { cdvd_init_s_fifo(cdvd, 9); - uint8_t id[9] = { - 0x00, 0xac, 0xff, 0xff, - 0xff, 0xff, 0xb9, 0x86, - 0x00 - }; + // uint8_t id[9] = { + // 0x00, 0xac, 0xff, 0xff, + // 0xff, 0xff, 0xb9, 0x86, + // 0x00 + // }; - for (int i = 0; i < 9; i++) { - cdvd->s_fifo[i] = id[i]; - } + // for (int i = 0; i < 9; i++) { + // cdvd->s_fifo[i] = id[i]; + // } + + int offset = g_dragon_layout.ilink_id_offset; + + memcpy(&cdvd->s_fifo[1], &cdvd->nvram[offset], 8); } static inline void cdvd_s_forbid_dvd(struct ps2_cdvd* cdvd) { cdvd_init_s_fifo(cdvd, 1); cdvd->s_fifo[0] = 5; } -static inline void cdvd_s_read_ilink_model(struct ps2_cdvd* cdvd) { +static inline void cdvd_s_read_model(struct ps2_cdvd* cdvd) { cdvd_init_s_fifo(cdvd, 9); - for (int i = 0; i < 9; i++) - cdvd->s_fifo[i] = 0; + int offset = g_dragon_layout.modelnum_offset + cdvd->s_params[0]; + + memcpy(&cdvd->s_fifo[1], &cdvd->nvram[offset], 8); } static inline void cdvd_s_certify_boot(struct ps2_cdvd* cdvd) { cdvd_init_s_fifo(cdvd, 1); @@ -302,13 +333,29 @@ static inline void cdvd_s_rc_bypass_ctrl(struct ps2_cdvd* cdvd) { static inline void cdvd_s_open_config(struct ps2_cdvd* cdvd) { cdvd_init_s_fifo(cdvd, 1); + cdvd->config_rw = cdvd->s_params[0]; + cdvd->config_offset = cdvd->s_params[1]; + cdvd->config_numblocks = cdvd->s_params[2]; + cdvd->config_block_index = 0; + cdvd->s_fifo[0] = 0; } static inline void cdvd_s_read_config(struct ps2_cdvd* cdvd) { cdvd_init_s_fifo(cdvd, 16); - for (int i = 0; i < 16; i++) - cdvd->s_fifo[i] = 0; + int offset = 0; + + switch (cdvd->config_offset) { + case 0: offset = g_dragon_layout.config0_offset; break; + case 1: offset = g_dragon_layout.config1_offset; break; + case 2: offset = g_dragon_layout.config2_offset; break; + + default: offset = g_dragon_layout.config1_offset; break; + } + + offset += (cdvd->config_block_index++) * 16; + + memcpy(cdvd->s_fifo, &cdvd->nvram[offset], 16); } static inline void cdvd_s_write_config(struct ps2_cdvd* cdvd) { cdvd_init_s_fifo(cdvd, 1); @@ -393,6 +440,13 @@ static inline void cdvd_s_mg_write_data(struct ps2_cdvd* cdvd) { cdvd_init_s_fifo(cdvd, 1); cdvd->s_fifo[0] = 0; + + printf("mg: Write KELF data params="); + + for (int i = 0; i < cdvd->s_param_index; i++) + printf("%02x ", cdvd->s_params[i]); + + printf("\n"); } static inline void cdvd_s_mechacon_auth_8f(struct ps2_cdvd* cdvd) { cdvd_init_s_fifo(cdvd, 1); @@ -402,20 +456,35 @@ static inline void cdvd_s_mechacon_auth_8f(struct ps2_cdvd* cdvd) { static inline void cdvd_s_mg_write_hdr_start(struct ps2_cdvd* cdvd) { cdvd_init_s_fifo(cdvd, 1); + printf("mg: Write KELF header params="); + + for (int i = 0; i < cdvd->s_param_index; i++) + printf("%02x ", cdvd->s_params[i]); + + printf("\n"); + cdvd->s_fifo[0] = 0; } static inline void cdvd_s_get_region_params(struct ps2_cdvd* cdvd) { cdvd_init_s_fifo(cdvd, 15); - //This is basically what PCSX2 returns on a blank NVM/MEC file + for (int i = 5; i < 15; i++) + cdvd->s_fifo[i] = 0; + + int offset = g_dragon_layout.regparams_offset; + cdvd->s_fifo[0] = 0; - cdvd->s_fifo[1] = 1 << 0x3; //MEC encryption zone + cdvd->s_fifo[1] = 1 << 3; // MechaCon encryption zone cdvd->s_fifo[2] = 0; - cdvd->s_fifo[3] = 0x80; //Region Params - cdvd->s_fifo[4] = 0x1; - for (int i = 5; i < 15; i++) - cdvd->s_fifo[i] = 0; + memcpy(&cdvd->s_fifo[3], &cdvd->nvram[offset], 8); + + //This is basically what PCSX2 returns on a blank NVM/MEC file + // cdvd->s_fifo[0] = 0; + // cdvd->s_fifo[1] = 1 << 0x3; //MEC encryption zone + // cdvd->s_fifo[2] = 0; + // cdvd->s_fifo[3] = 0x80; //Region Params + // cdvd->s_fifo[4] = 0x1; } static inline void cdvd_s_remote2_read(struct ps2_cdvd* cdvd) { cdvd_init_s_fifo(cdvd, 5); @@ -431,17 +500,17 @@ void cdvd_handle_s_command(struct ps2_cdvd* cdvd, uint8_t cmd) { cdvd->s_cmd = cmd; switch (cmd) { - case 0x03: printf("cdvd: mechacon_version\n"); cdvd_s_mechacon_version(cdvd); break; + case 0x03: printf("cdvd: mechacon_cmd(%02x)\n", cdvd->s_params[0]); cdvd_s_mechacon_cmd(cdvd); break; case 0x05: printf("cdvd: update_sticky_flags\n"); cdvd_s_update_sticky_flags(cdvd); break; // case 0x06: printf("cdvd: tray_ctrl\n"); cdvd_s_tray_ctrl(cdvd); break; - case 0x08: /* printf("cdvd: read_rtc\n"); */ cdvd_s_read_rtc(cdvd); break; + case 0x08: printf("cdvd: read_rtc\n"); cdvd_s_read_rtc(cdvd); break; case 0x09: printf("cdvd: write_rtc\n"); cdvd_s_write_rtc(cdvd); break; case 0x0a: printf("cdvd: read_nvram\n"); cdvd_s_read_nvram(cdvd); break; case 0x0b: printf("cdvd: write_nvram\n"); cdvd_s_write_nvram(cdvd); break; // case 0x0f: printf("cdvd: power_off\n"); cdvd_s_power_off(cdvd); break; case 0x12: printf("cdvd: read_ilink_id\n"); cdvd_s_read_ilink_id(cdvd); break; case 0x15: printf("cdvd: forbid_dvd\n"); cdvd_s_forbid_dvd(cdvd); break; - case 0x17: printf("cdvd: read_ilink_model\n"); cdvd_s_read_ilink_model(cdvd); break; + case 0x17: printf("cdvd: read_model\n"); cdvd_s_read_model(cdvd); break; case 0x1a: printf("cdvd: certify_boot\n"); cdvd_s_certify_boot(cdvd); break; case 0x1b: printf("cdvd: cancel_pwoff_ready\n"); cdvd_s_cancel_pwoff_ready(cdvd); break; @@ -479,13 +548,11 @@ void cdvd_handle_s_command(struct ps2_cdvd* cdvd, uint8_t cmd) { } static inline void cdvd_handle_s_param(struct ps2_cdvd* cdvd, uint8_t param) { - cdvd->s_params[cdvd->s_param_index++] = param; - - if (cdvd->s_param_index > 15) { + if (cdvd->s_param_index == 16) { printf("cdvd: S parameter FIFO overflow\n"); - - // exit(1); } + + cdvd->s_params[cdvd->s_param_index++] = param; } static inline uint8_t cdvd_read_s_response(struct ps2_cdvd* cdvd) { @@ -777,14 +844,14 @@ static inline void cdvd_n_read_cd(struct ps2_cdvd* cdvd) { CDVD_STATUS_SEEKING ); - printf("cdvd: ReadCd lba=%08x count=%08x size=%d cycles=%ld speed=%02x (%p)\n", - cdvd->read_lba, - cdvd->read_count, - cdvd->read_size, - event.cycles, - cdvd->n_params[9], - cdvd->disc->read_sector - ); + // printf("cdvd: ReadCd lba=%08x count=%08x size=%d cycles=%ld speed=%02x (%p)\n", + // cdvd->read_lba, + // cdvd->read_count, + // cdvd->read_size, + // event.cycles, + // cdvd->n_params[9], + // cdvd->disc->read_sector + // ); } static inline void cdvd_n_read_cdda(struct ps2_cdvd* cdvd) { /* Params: @@ -1041,6 +1108,14 @@ void ps2_cdvd_init(struct ps2_cdvd* cdvd, struct ps2_iop_dma* dma, struct ps2_io cdvd->intc = intc; memcpy(cdvd->nvram, nvram_init_data, 1024); + + FILE* file = fopen("nvram.bin", "rb"); + + if (!file) + return; + + fread(cdvd->nvram, 1, 1024, file); + fclose(file); } void ps2_cdvd_destroy(struct ps2_cdvd* cdvd) { @@ -1078,6 +1153,8 @@ int ps2_cdvd_open(struct ps2_cdvd* cdvd, const char* path, int delay) { cdvd->detected_disc_type = CDVD_DISC_PS2_CD; } + printf("cdvd: Opened \'%s\' (%s)\n", path, cdvd_get_type_name(cdvd->detected_disc_type)); + if (!delay) { cdvd->status &= ~CDVD_STATUS_TRAY_OPEN; @@ -1086,8 +1163,6 @@ int ps2_cdvd_open(struct ps2_cdvd* cdvd, const char* path, int delay) { return 0; } - printf("cdvd: Opened \'%s\' (%s)\n", path, cdvd_get_type_name(cdvd->detected_disc_type)); - switch (cdvd->detected_disc_type) { case CDVD_DISC_PS2_CD: case CDVD_DISC_PS2_CDDA: @@ -1161,43 +1236,44 @@ uint64_t ps2_cdvd_read8(struct ps2_cdvd* cdvd, uint32_t addr) { // printf("cdvd: read %08x\n", addr); switch (addr) { - case 0x1F402004: /* printf("cdvd: read n_cmd %x\n", cdvd->n_cmd); */ return cdvd->n_cmd; - case 0x1F402005: /* printf("cdvd: read n_stat %x\n", cdvd->n_stat); */ return cdvd->n_stat; + case 0x1F402004: printf("cdvd: read n_cmd %x\n", cdvd->n_cmd); return cdvd->n_cmd; + case 0x1F402005: printf("cdvd: read n_stat %x\n", cdvd->n_stat); return cdvd->n_stat; // case 0x1F402005: (W) - case 0x1F402006: /* printf("cdvd: read error %x\n", 0); */ return 0; //cdvd->error; + case 0x1F402006: printf("cdvd: read error %x\n", 0); return 0; //cdvd->error; // case 0x1F402007: (W) - case 0x1F402008: /* printf("cdvd: read i_stat %x\n", cdvd->i_stat); */ return cdvd->i_stat; - case 0x1F40200A: /* printf("cdvd: read status %x\n", cdvd->status); */ return cdvd->status; - case 0x1F40200B: /* printf("cdvd: read sticky_status %x\n", cdvd->sticky_status); */ return cdvd->sticky_status; - case 0x1F40200F: /* printf("cdvd: read disc_type %x\n", cdvd->disc_type); */ return cdvd->disc_type; - case 0x1F402013: /* printf("cdvd: read speed %x\n", cdvd_read_speed(cdvd)); return */ cdvd_read_speed(cdvd); - case 0x1F402016: /* printf("cdvd: read s_cmd %x\n", cdvd->s_cmd); */ return cdvd->s_cmd; - case 0x1F402017: /* printf("cdvd: read s_stat %x\n", cdvd->s_stat); */ return cdvd->s_stat; + case 0x1F402008: printf("cdvd: read i_stat %x\n", cdvd->i_stat); return cdvd->i_stat; + case 0x1F40200A: printf("cdvd: read status %x\n", cdvd->status); return cdvd->status; + case 0x1F40200B: printf("cdvd: read sticky_status %x\n", cdvd->sticky_status); return cdvd->sticky_status; + case 0x1F40200F: printf("cdvd: read disc_type %x\n", cdvd->disc_type); return cdvd->disc_type; + case 0x1F402013: printf("cdvd: read speed %x\n", cdvd_read_speed(cdvd)); return cdvd_read_speed(cdvd); + case 0x1F402016: printf("cdvd: read s_cmd %x\n", cdvd->s_cmd); return cdvd->s_cmd; + case 0x1F402017: printf("cdvd: read s_stat %x\n", cdvd->s_stat); return cdvd->s_stat; // case 0x1F402017: (W); - case 0x1F402018: return cdvd_read_s_response(cdvd); // { int r = cdvd_read_s_response(cdvd); printf("cdvd: read s_response %x\n", r); return r; } + case 0x1F402018: { int r = cdvd_read_s_response(cdvd); printf("cdvd: read s_response %x\n", r); return r; } case 0x1F402020: case 0x1F402021: case 0x1F402022: case 0x1F402023: case 0x1F402024: - // printf("cdvd: ReadKey %08x (%d) -> %02x\n", addr, addr - 0x1f402020, cdvd->cdkey[addr - 0x1F402020]); + printf("cdvd: ReadKey %08x (%d) -> %02x\n", addr, addr - 0x1f402020, cdvd->cdkey[addr - 0x1F402020]); return cdvd->cdkey[addr - 0x1F402020]; case 0x1F402028: case 0x1F402029: case 0x1F40202A: case 0x1F40202B: case 0x1F40202C: - // printf("cdvd: ReadKey %08x (%d) -> %02x\n", addr, addr - 0x1f402023, cdvd->cdkey[addr - 0x1F402023]); + printf("cdvd: ReadKey %08x (%d) -> %02x\n", addr, addr - 0x1f402023, cdvd->cdkey[addr - 0x1F402023]); return cdvd->cdkey[addr - 0x1F402023]; case 0x1F402030: case 0x1F402031: case 0x1F402032: case 0x1F402033: case 0x1F402034: - // printf("cdvd: ReadKey %08x (%d) -> %02x\n", addr, addr - 0x1f402026, cdvd->cdkey[addr - 0x1F402026]); + printf("cdvd: ReadKey %08x (%d) -> %02x\n", addr, addr - 0x1f402026, cdvd->cdkey[addr - 0x1F402026]); return cdvd->cdkey[addr - 0x1F402026]; case 0x1F402038: + printf("cdvd: ReadKey %08x (%d) -> %02x\n", addr, addr - 0x1f402038, cdvd->cdkey[15]); return cdvd->cdkey[15]; } @@ -1226,4 +1302,30 @@ void ps2_cdvd_write8(struct ps2_cdvd* cdvd, uint32_t addr, uint64_t data) { } return; +} + +void ps2_cdvd_reset(struct ps2_cdvd* cdvd) { + cdvd->n_stat = 0x4c; + // cdvd->s_stat = CDVD_S_STATUS_NO_DATA; + // cdvd->sticky_status = 0x1e; + // cdvd->s_cmd = 0; + // cdvd->s_stat = 0; + // cdvd->n_cmd = 0; + // cdvd->i_stat = 0; + + // cdvd->n_param_index = 0; + // cdvd->s_param_index = 0; + // cdvd->s_fifo_index = 0; + // cdvd->s_fifo_size = 0; + // cdvd->buf_size = 0; + + cdvd->read_lba = 0x150; + cdvd->read_count = 0; + cdvd->read_size = 0; + cdvd->read_speed = 0; + + cdvd->config_rw = 0; + cdvd->config_offset = 0; + cdvd->config_numblocks = 0; + cdvd->config_block_index = 0; } \ No newline at end of file diff --git a/src/iop/cdvd.h b/src/iop/cdvd.h index c50b014..fca758b 100644 --- a/src/iop/cdvd.h +++ b/src/iop/cdvd.h @@ -71,6 +71,18 @@ extern "C" { #define CDVD_CD_SS_2048 2048 #define CDVD_DVD_SS 2064 +struct nvram_layout { + uint32_t bios_version; // bios version that this eeprom layout is for + int32_t config0_offset; // offset of 1st config block + int32_t config1_offset; // offset of 2nd config block + int32_t config2_offset; // offset of 3rd config block + int32_t console_id_offset; // offset of console id (?) + int32_t ilink_id_offset; // offset of ilink id (ilink mac address) + int32_t modelnum_offset; // offset of ps2 model number (eg "SCPH-70002") + int32_t regparams_offset; // offset of RegionParams for PStwo + int32_t mac_offset; // offset of MAC address on PStwo +}; + struct ps2_cdvd { uint8_t n_cmd; uint8_t n_stat; @@ -118,6 +130,11 @@ struct ps2_cdvd { struct sched_state* sched; uint64_t layer2_lba; + uint32_t config_rw; + uint32_t config_offset; + uint32_t config_numblocks; + uint32_t config_block_index; + // To-do: // void (*poweroff_handler)(void* udata) // void (*trayctrl_handler)(void* udata, uint8_t ctrl) @@ -131,6 +148,7 @@ void ps2_cdvd_close(struct ps2_cdvd* cdvd); void ps2_cdvd_power_off(struct ps2_cdvd* cdvd); uint64_t ps2_cdvd_read8(struct ps2_cdvd* cdvd, uint32_t addr); void ps2_cdvd_write8(struct ps2_cdvd* cdvd, uint32_t addr, uint64_t data); +void ps2_cdvd_reset(struct ps2_cdvd* cdvd); #undef ALIGNED_U32 diff --git a/src/iop/spu2.c b/src/iop/spu2.c index fd785e2..e5dd8d8 100644 --- a/src/iop/spu2.c +++ b/src/iop/spu2.c @@ -5,6 +5,9 @@ #include "spu2.h" +FILE* output = NULL; +uint32_t chunk_size = 0; + static const int16_t g_spu_gauss_table[] = { -0x001, -0x001, -0x001, -0x001, -0x001, -0x001, -0x001, -0x001, -0x001, -0x001, -0x001, -0x001, -0x001, -0x001, -0x001, -0x001, @@ -76,6 +79,34 @@ struct ps2_spu2* ps2_spu2_create(void) { return (struct ps2_spu2*)malloc(sizeof(struct ps2_spu2)); } +struct wav_hdr { + char riff[4]; + uint32_t size; + char wave[4]; + char fmt[4]; + uint32_t block_size; + uint16_t audio_format; + uint16_t num_channels; + uint32_t samplerate; + uint32_t bytes_per_sec; + uint16_t bytes_per_block; + uint16_t bits_per_sample; +}; + +struct wav_chunk { + char id[4]; // "data" + uint32_t size; +}; + +// FormatBlocID (4 bytes) : Identifier « fmt␣ » (0x66, 0x6D, 0x74, 0x20) +// BlocSize (4 bytes) : Chunk size minus 8 bytes, which is 16 bytes here (0x10) +// AudioFormat (2 bytes) : Audio format (1: PCM integer, 3: IEEE 754 float) +// NbrChannels (2 bytes) : Number of channels +// Frequency (4 bytes) : Sample rate (in hertz) +// BytePerSec (4 bytes) : Number of bytes to read per second (Frequency * BytePerBloc). +// BytePerBloc (2 bytes) : Number of bytes per block (NbrChannels * BitsPerSample / 8). +// BitsPerSample (2 bytes) : Number of bits per sample + void ps2_spu2_init(struct ps2_spu2* spu2, struct ps2_iop_dma* dma, struct ps2_iop_intc* intc, struct sched_state* sched) { memset(spu2, 0, sizeof(struct ps2_spu2)); @@ -88,13 +119,17 @@ void ps2_spu2_init(struct ps2_spu2* spu2, struct ps2_iop_dma* dma, struct ps2_io spu2->c[1].stat = 0x80; spu2->c[0].endx = 0x00ffffff; spu2->c[1].endx = 0x00ffffff; + + output = fopen("adma.wav", "wb"); + + fseek(output, sizeof(struct wav_hdr) + sizeof(struct wav_chunk), SEEK_SET); } void spu2_irq(struct ps2_spu2* spu2, int c) { - if (spu2->spdif_irq & (8 << c)) + if (spu2->spdif_irq & (4 << c)) return; - spu2->spdif_irq |= 8 << c; + spu2->spdif_irq |= 4 << c; // printf("spu2: IRQ fired\n"); @@ -103,7 +138,7 @@ void spu2_irq(struct ps2_spu2* spu2, int c) { void spu2_check_irq(struct ps2_spu2* spu2, uint32_t addr) { for (int i = 0; i < 2; i++) { - if (addr == spu2->c[i].irqa && (spu2->c[i].attr & (1 << 6))) { + if ((addr == spu2->c[i].irqa) && (spu2->c[i].attr & (1 << 6))) { spu2_irq(spu2, i); } } @@ -125,8 +160,11 @@ void spu2_write_kon(struct ps2_spu2* spu2, int c, int h, uint64_t data) { if (idx >= 24) break; - struct spu2_voice* v = &spu2->c[c].v[idx]; struct spu2_core* cr = &spu2->c[c]; + struct spu2_voice* v = &cr->v[idx]; + + // if (v->playing) + // continue; // Make sure to clear the internal state of a voice // before playing @@ -157,7 +195,6 @@ void spu2_write_kon(struct ps2_spu2* spu2, int c, int h, uint64_t data) { v->adsr_pending_step = 0; v->adsr_sustain_level = 0; - v->playing = 1; v->nax = v->ssa; v->adsr_sustain_level = ((v->adsr1 & 0xf) + 1) * 0x800; @@ -184,8 +221,10 @@ void spu2_write_koff(struct ps2_spu2* spu2, int c, int h, uint64_t data) { // spu2->c[c].v[i+h*16].playing = 0; - // To-do: Enter ADSR release // printf("spu2: voice %d koff\n", v); + if (!spu2->c[c].v[v].playing) + continue; + adsr_load_release(spu2, &spu2->c[c], &spu2->c[c].v[v], v); } } @@ -235,11 +274,11 @@ void spu2_core1_reset_handler(void* udata, int overshoot) { } void spu2_write_attr(struct ps2_spu2* spu2, int c, uint64_t data) { - // if (spu2->c[c].attr & (1 << 6)) { - // if (!(data & (1 << 6))) { - // spu2->spdif_irq &= ~(4 << c); - // } - // } + if (spu2->c[c].attr & (1 << 6)) { + if (!(data & (1 << 6))) { + spu2->spdif_irq &= ~(4 << c); + } + } spu2->c[c].attr = data & 0x7fff; @@ -314,9 +353,13 @@ uint64_t ps2_spu2_read16(struct ps2_spu2* spu2, uint32_t addr) { if ((addr >= 0x1c0 && addr <= 0x2df) || (addr >= 0x5c0 && addr <= 0x6df)) { int core = (addr >> 10) & 1; - int voice = (addr - (0x1c0 + 0x400 * core)) / 12; - switch (addr % 0xc) { + addr -= 0x1c0 + 0x400 * core; + + int voice = addr / 12; + int reg = addr % 12; + + switch (reg) { case 0x0: return spu2->c[core].v[voice].ssa >> 16; case 0x2: return spu2->c[core].v[voice].ssa & 0xffff; case 0x4: return spu2->c[core].v[voice].lsax >> 16; @@ -614,7 +657,7 @@ void ps2_spu2_write16(struct ps2_spu2* spu2, uint32_t addr, uint64_t data) { case 0x7ac: spu2->c[1].in_coef_l = data; return; case 0x7ae: spu2->c[1].in_coef_r = data; return; case 0x7C0: spu2->spdif_out = data; return; - case 0x7C2: printf("spdif irq write %04x", data); spu2->spdif_irq = data; return; + case 0x7C2: spu2->spdif_irq = data; return; case 0x7C6: spu2->spdif_mode = data; return; case 0x7C8: spu2->spdif_media = data; return; case 0x7CA: spu2->spdif_copy = data; return; @@ -624,6 +667,46 @@ void ps2_spu2_write16(struct ps2_spu2* spu2, uint32_t addr, uint64_t data) { } void ps2_spu2_destroy(struct ps2_spu2* spu2) { + uint32_t size = ftell(output) - 8; + + struct wav_hdr hdr; + + hdr.riff[0] = 'R'; + hdr.riff[1] = 'I'; + hdr.riff[2] = 'F'; + hdr.riff[3] = 'F'; + hdr.size = size; + hdr.wave[0] = 'W'; + hdr.wave[1] = 'A'; + hdr.wave[2] = 'V'; + hdr.wave[3] = 'E'; + hdr.fmt[0] = 'f'; + hdr.fmt[1] = 'm'; + hdr.fmt[2] = 't'; + hdr.fmt[3] = ' '; + hdr.block_size = 16; + hdr.audio_format = 1; + hdr.num_channels = 2; + hdr.samplerate = 48000; + hdr.bits_per_sample = 16; + hdr.bytes_per_block = 4; + hdr.bytes_per_sec = 48000 * 4; + + struct wav_chunk chunk; + + chunk.id[0] = 'd'; + chunk.id[1] = 'a'; + chunk.id[2] = 't'; + chunk.id[3] = 'a'; + chunk.size = chunk_size; + + fseek(output, 0, SEEK_SET); + fwrite(&hdr, sizeof(struct wav_hdr), 1, output); + fwrite(&chunk, sizeof(struct wav_chunk), 1, output); + + fflush(output); + fclose(output); + free(spu2); } @@ -652,7 +735,13 @@ void spu2_decode_adpcm_block(struct ps2_spu2* spu2, struct spu2_voice* v) { // printf("spu2: start=%d loop=%d end=%d\n", v->loop_start, v->loop, v->loop_end); int shift_factor = (hdr & 0xf); - int coef_index = ((hdr >> 4) & 0xF); + int coef_index = ((hdr >> 4) & 0x7); + + if (coef_index > 4) { + // printf("spu2: Invalid ADPCM coefficient index %d\n", coef_index); + + coef_index = 4; + } int32_t f0 = ps_adpcm_coefs_i[coef_index][0]; int32_t f1 = ps_adpcm_coefs_i[coef_index][1]; @@ -723,12 +812,14 @@ void adsr_load_attack(struct ps2_spu2* spu2, struct spu2_core* c, struct spu2_vo adsr_calculate_values(spu2, v); - // printf("adsr: attack mode=%d shift=%d step=%d dir=%d envx=%d\n", + // printf("adsr: attack mode=%d shift=%d step=%d dir=%d envx=%d cycles=%d level_step=%d\n", // v->adsr_mode, // v->adsr_shift, // v->adsr_step, // v->adsr_dir, - // v->envx + // v->envx, + // CYCLES, + // LEVEL_STEP // ); } @@ -774,8 +865,6 @@ void spu2_handle_adsr(struct ps2_spu2* spu2, struct spu2_core* c, struct spu2_vo return; } - adsr_calculate_values(spu2, v); - int level = v->envx; level += LEVEL_STEP; @@ -808,12 +897,17 @@ void spu2_handle_adsr(struct ps2_spu2* spu2, struct spu2_core* c, struct spu2_vo PHASE = ADSR_END; CYCLES = 0; + // v->nax = 0; + // v->ssa = 0; + // v->lsax = 0; + v->envx = 0; v->playing = 0; } } break; case ADSR_END: { + level = 0; v->envx = 0; v->playing = 0; } break; @@ -821,6 +915,8 @@ void spu2_handle_adsr(struct ps2_spu2* spu2, struct spu2_core* c, struct spu2_vo v->envx = level; + adsr_calculate_values(spu2, v); + CYCLES = v->adsr_cycles_reload; } @@ -835,8 +931,8 @@ void spu2_handle_adsr(struct ps2_spu2* spu2, struct spu2_core* c, struct spu2_vo #undef MAX struct spu2_sample spu2_get_voice_sample(struct ps2_spu2* spu2, int cr, int vc) { - if (!spu2->c[cr].v[vc].playing) - return silence; + // if (!spu2->c[cr].v[vc].playing) + // return silence; struct spu2_core* c = &spu2->c[cr]; struct spu2_voice* v = &c->v[vc]; @@ -870,22 +966,25 @@ struct spu2_sample spu2_get_voice_sample(struct ps2_spu2* spu2, int cr, int vc) v->lsax = v->nax; v->nax += 8; + v->nax &= 0xfffff; } else if (v->loop_end) { - // printf("spu2: Voice %d loop end at 0x%08x (lsax=%08x ssa=%08x) loop=%d\n", vc, v->nax, v->lsax, v->ssa, v->loop); - v->nax = v->lsax; - - spu2_check_irq(spu2, v->nax); + // if (vc == 18 && cr == 1) + // printf("spu2: Voice %d loop end at 0x%08x (lsax=%08x ssa=%08x) loop=%d end=%d start=%d\n", vc, v->nax, v->lsax, v->ssa, v->loop, v->loop_end, v->loop_start); if (!v->loop) { adsr_load_release(spu2, c, v, vc); v->envx = 0; - v->playing = 0; + } else { + v->nax = v->lsax; } + + spu2_check_irq(spu2, v->nax); } else { spu2_check_irq(spu2, v->nax); v->nax += 8; + v->nax &= 0xfffff; } spu2_decode_adpcm_block(spu2, v); @@ -912,6 +1011,27 @@ struct spu2_sample spu2_get_voice_sample(struct ps2_spu2* spu2, int cr, int vc) out += (g2 * v->s[1]) >> 15; out += (g3 * v->s[0]) >> 15; + // Output voice 1 and 3 to the capture buffers + if (vc == 1) { + uint16_t addr = c->cb_out1_addr + (cr ? 0xc00 : 0x400); + + c->cb_out1_addr = (c->cb_out1_addr + 1) & 0x1ff; + + spu2->ram[addr] = out; + + spu2_check_irq(spu2, addr); + } + + if (vc == 3) { + uint16_t addr = c->cb_out3_addr + (cr ? 0xe00 : 0x600); + + c->cb_out3_addr = (c->cb_out3_addr + 1) & 0x1ff; + + spu2->ram[addr] = out; + + spu2_check_irq(spu2, addr); + } + s.s16[0] = (out * v->voll) >> 15; s.s16[1] = (out * v->volr) >> 15; s.s16[0] = ((int32_t)s.s16[0] * v->envx) >> 15; @@ -967,10 +1087,22 @@ struct spu2_sample ps2_spu2_get_sample(struct ps2_spu2* spu2) { struct spu2_sample c0_adma = spu2_get_adma_sample(spu2, 0); struct spu2_sample c1_adma = spu2_get_adma_sample(spu2, 1); - s.s16[0] += c0_adma.s16[0]; - s.s16[1] += c0_adma.s16[1]; - s.s16[0] += c1_adma.s16[0]; - s.s16[1] += c1_adma.s16[1]; + if (output) { + if (spu2->c[0].adma_playing) { + chunk_size += sizeof(int16_t) * 2; + fwrite(&c0_adma.s16, sizeof(int16_t), 2, output); + } + + if (spu2->c[1].adma_playing) { + chunk_size += sizeof(int16_t) * 2; + fwrite(&c1_adma.s16, sizeof(int16_t), 2, output); + } + } + + // s.s16[0] += c0_adma.s16[0]; + // s.s16[1] += c0_adma.s16[1]; + // s.s16[0] += c1_adma.s16[0]; + // s.s16[1] += c1_adma.s16[1]; for (int i = 0; i < 24; i++) { struct spu2_sample c0 = spu2_get_voice_sample(spu2, 0, i); diff --git a/src/iop/spu2.h b/src/iop/spu2.h index a73c488..1f2dc1d 100644 --- a/src/iop/spu2.h +++ b/src/iop/spu2.h @@ -176,6 +176,10 @@ struct spu2_core { uint32_t adma_ringbuf_write_idx; uint32_t adma_ringbuf_read_idx; int adma_ringbuf_full; + + // Capture buffers + uint16_t cb_out1_addr; + uint16_t cb_out3_addr; }; struct ps2_spu2 { diff --git a/src/iop/timers.c b/src/iop/timers.c index 7a1462f..1d7bcc6 100644 --- a/src/iop/timers.c +++ b/src/iop/timers.c @@ -49,10 +49,24 @@ void iop_timer_tick(struct ps2_iop_timers* timers, int i) { t->internal = 0; } } else { - ++t->counter; + t->counter += 2; } } else { - t->counter += 9; + if (i == 4) { + switch (t->t4_prescaler) { + case 0: t->counter += 2; break; + case 1: { + if (t->internal != 128) { + ++t->internal; + } else { + t->counter += 1; + t->internal = 0; + } + } break; + } + } else { + t->counter += 2; + } } if (t->counter >= t->target && prev < t->target) { @@ -178,20 +192,20 @@ void iop_timer_handle_mode_write(struct ps2_iop_timers* timers, int t, uint64_t // ps2_iop_intc_irq(timers->intc, timer_get_irq_mask(t)); } - printf("iop: Timer %d mode write %08x -> %08x gate_en=%d gate_mode=%d irq_reset=%d cmp_irq=%d ovf_irq=%d rep_irq=%d levl=%d use_ext=%d irq_en=%d t4_prescaler=%d\n", - t, timers->timer[t].mode, - data, - timers->timer[t].gate_en, - timers->timer[t].gate_mode, - timers->timer[t].irq_reset, - timers->timer[t].cmp_irq, - timers->timer[t].ovf_irq, - timers->timer[t].rep_irq, - timers->timer[t].levl, - timers->timer[t].use_ext, - timers->timer[t].irq_en, - timers->timer[t].t4_prescaler - ); + // printf("iop: Timer %d mode write %08x -> %08x gate_en=%d gate_mode=%d irq_reset=%d cmp_irq=%d ovf_irq=%d rep_irq=%d levl=%d use_ext=%d irq_en=%d t4_prescaler=%d\n", + // t, timers->timer[t].mode, + // data, + // timers->timer[t].gate_en, + // timers->timer[t].gate_mode, + // timers->timer[t].irq_reset, + // timers->timer[t].cmp_irq, + // timers->timer[t].ovf_irq, + // timers->timer[t].rep_irq, + // timers->timer[t].levl, + // timers->timer[t].use_ext, + // timers->timer[t].irq_en, + // timers->timer[t].t4_prescaler + // ); /* To-do: Schedule timer interrupts for better performance */ } diff --git a/src/iop/usb.c b/src/iop/usb.c index 7bd1910..9d59cc1 100644 --- a/src/iop/usb.c +++ b/src/iop/usb.c @@ -50,8 +50,6 @@ uint64_t ps2_usb_read32(struct ps2_usb* usb, uint32_t addr) { printf("usb: Unhandled read at %08x\n", addr); - exit(1); - return 0; } @@ -90,7 +88,5 @@ void ps2_usb_write32(struct ps2_usb* usb, uint32_t addr, uint64_t data) { printf("usb: Unhandled write at %08x (%08x)\n", addr, data); - exit(1); - return; } \ No newline at end of file diff --git a/src/ps2.c b/src/ps2.c index dda13dd..64b7541 100644 --- a/src/ps2.c +++ b/src/ps2.c @@ -5,10 +5,6 @@ #include "ps2.h" -#ifndef _PS2_TIMESCALE -#define _PS2_TIMESCALE 4 -#endif - struct ps2_state* ps2_create(void) { return malloc(sizeof(struct ps2_state)); } @@ -149,6 +145,7 @@ void ps2_init(struct ps2_state* ps2) { ps2_ipu_reset(ps2->ipu); ps2->ee_cycles = 7; + ps2->timescale = 1; } void ps2_init_kputchar(struct ps2_state* ps2, void (*ee_kputchar)(void*, char), void* ee_udata, void (*iop_kputchar)(void*, char), void* iop_udata) { @@ -210,6 +207,7 @@ void ps2_reset(struct ps2_state* ps2) { ps2_usb_init(ps2->usb); ps2_fw_init(ps2->fw, ps2->iop_intc); ps2_sbus_init(ps2->sbus, ps2->ee_intc, ps2->iop_intc, ps2->sched); + ps2_cdvd_reset(ps2->cdvd); ps2_gs_reset(ps2->gs); ps2_ram_reset(ps2->ee_ram); @@ -242,29 +240,6 @@ void ps2_reset(struct ps2_state* ps2) { // } void ps2_cycle(struct ps2_state* ps2) { - // if (ps2->ee->pc == 0xe0040) - // printf("ee: Entry @ cyc=%ld\n", ps2->ee->total_cycles); - - // ps2_trace(ps2); - - // Waitloop detection - // if (ps2->ee->pc == 0x81fc0) { - // while (!sched_tick(ps2->sched, 4)) { - // --ps2->ee_cycles; - - // if (!ps2->ee_cycles) { - // iop_cycle(ps2->iop); - // ps2_iop_timers_tick(ps2->iop_timers); - - // ps2->ee_cycles = 7; - // } - // } - - // ee_cycle(ps2->ee); - - // return; - // } - int cycles = ee_run_block(ps2->ee, 128); while (!cycles) { @@ -273,7 +248,7 @@ void ps2_cycle(struct ps2_state* ps2) { ps2->ee_cycles += cycles; - sched_tick(ps2->sched, (2 * _PS2_TIMESCALE) * cycles); + sched_tick(ps2->sched, ps2->timescale * cycles); ps2_ipu_run(ps2->ipu); @@ -304,6 +279,10 @@ void ps2_iop_cycle(struct ps2_state* ps2) { // ps2->ee_cycles = 7; } +void ps2_set_timescale(struct ps2_state* ps2, int timescale) { + ps2->timescale = timescale; +} + void ps2_destroy(struct ps2_state* ps2) { free(ps2->strtab); free(ps2->func); diff --git a/src/ps2.h b/src/ps2.h index 6b750f5..9bc4f88 100644 --- a/src/ps2.h +++ b/src/ps2.h @@ -86,6 +86,7 @@ struct ps2_state { struct sched_state* sched; int ee_cycles; + int timescale; // Debug struct ps2_elf_function* func; @@ -102,6 +103,7 @@ void ps2_load_bios(struct ps2_state* ps2, const char* path); void ps2_load_rom1(struct ps2_state* ps2, const char* path); void ps2_load_rom2(struct ps2_state* ps2, const char* path); void ps2_cycle(struct ps2_state* ps2); +void ps2_set_timescale(struct ps2_state* ps2, int timescale); void ps2_iop_cycle(struct ps2_state* ps2); void ps2_destroy(struct ps2_state* ps2); diff --git a/src/shared/ram.h b/src/shared/ram.h index ec28f33..2b4d3cf 100644 --- a/src/shared/ram.h +++ b/src/shared/ram.h @@ -16,6 +16,7 @@ struct ps2_ram { #define RAM_SIZE_1KB 0x400 #define RAM_SIZE_2MB 0x200000 +#define RAM_SIZE_4MB 0x400000 #define RAM_SIZE_32MB 0x2000000 #define RAM_SIZE_64MB 0x4000000 #define RAM_SIZE_128MB 0x8000000 diff --git a/src/u128.h b/src/u128.h index 3b467df..02445d0 100644 --- a/src/u128.h +++ b/src/u128.h @@ -14,6 +14,10 @@ typedef union { uint32_t u32[4]; uint16_t u16[8]; uint8_t u8[16]; + int64_t s64[2]; + int32_t s32[4]; + int16_t s16[8]; + int8_t s8[16]; uint64_t ul64; uint32_t ul32; uint16_t ul16;