ref: 0f41e84591f3ecba3e53789a891b6f43746abf27
parent: a4fb5d06d406d9a21fcc767d81e870603d3b397a
author: Jean-André Santoni <jean.andre.santoni@gmail.com>
date: Sat Mar 7 20:03:33 EST 2026
LF
--- a/Makefile
+++ b/Makefile
@@ -1,35 +1,35 @@
-.ONESHELL:
-
-CFLAGS := -g -DLOG_USE_COLOR `sdl2-config --cflags --libs`
-CFLAGS += -Ofast -Wno-overflow -Wall -pedantic -Wno-address-of-packed-member -flto
-
-PLATFORM := $(shell uname -s)
-
-ifeq ($(PLATFORM),Darwin)
- CFLAGS += -mmacosx-version-min=10.9 -Wno-newline-eof
-endif
-
-VERSION_TAG := $(shell git describe --always --tags --abbrev=0)
-COMMIT_HASH := $(shell git rev-parse --short HEAD)
-OS_INFO := $(shell uname -rmo)
-
-SOURCES := $(wildcard psx/*.c)
-SOURCES += $(wildcard psx/dev/*.c)
-SOURCES += $(wildcard psx/dev/cdrom/*.c)
-SOURCES += $(wildcard psx/input/*.c)
-SOURCES += $(wildcard psx/disc/*.c)
-SOURCES += $(wildcard frontend/*.c)
-
-bin/psxe frontend/main.c:
- mkdir -p bin
-
- gcc $(SOURCES) -o bin/psxe \
- -I"." \
- -I"psx" \
- -DOS_INFO="$(OS_INFO)" \
- -DREP_VERSION="$(VERSION_TAG)" \
- -DREP_COMMIT_HASH="$(COMMIT_HASH)" \
- $(CFLAGS)
-
-clean:
- rm -rf "bin"
+.ONESHELL:
+
+CFLAGS := -g -DLOG_USE_COLOR `sdl2-config --cflags --libs`
+CFLAGS += -Ofast -Wno-overflow -Wall -pedantic -Wno-address-of-packed-member -flto
+
+PLATFORM := $(shell uname -s)
+
+ifeq ($(PLATFORM),Darwin)
+ CFLAGS += -mmacosx-version-min=10.9 -Wno-newline-eof
+endif
+
+VERSION_TAG := $(shell git describe --always --tags --abbrev=0)
+COMMIT_HASH := $(shell git rev-parse --short HEAD)
+OS_INFO := $(shell uname -rmo)
+
+SOURCES := $(wildcard psx/*.c)
+SOURCES += $(wildcard psx/dev/*.c)
+SOURCES += $(wildcard psx/dev/cdrom/*.c)
+SOURCES += $(wildcard psx/input/*.c)
+SOURCES += $(wildcard psx/disc/*.c)
+SOURCES += $(wildcard frontend/*.c)
+
+bin/psxe frontend/main.c:
+ mkdir -p bin
+
+ gcc $(SOURCES) -o bin/psxe \
+ -I"." \
+ -I"psx" \
+ -DOS_INFO="$(OS_INFO)" \
+ -DREP_VERSION="$(VERSION_TAG)" \
+ -DREP_COMMIT_HASH="$(COMMIT_HASH)" \
+ $(CFLAGS)
+
+clean:
+ rm -rf "bin"
--- a/README.md
+++ b/README.md
@@ -1,90 +1,90 @@
-# psxe
-A simple and portable Sony PlayStation emulator and emulation library written in C
-
-## Screenshots
-| Windows | Ubuntu | macOS |
-| ------------- | ------------- | -------------
-|  |  |  |
-|  |  |  |
-
-### CI status
-
-
-
-
-## Running
-You can download the latest automated build for your platform on Releases. If your system isn't supported, you can easily build the emulator from source, instructions on "Building" below.
-
-In order to run the emulator, you will need a BIOS file. You can either get one from the internet or [dump it from your own console](https://www.youtube.com/watch?v=u8eHp0COcBo).
-
-Most BIOS versions are confirmed to work.
-
-Use the `-b` or `--bios` setting to configure the BIOS file.
-
-## Progress
-All components have been implemented, Memory card support is temporarily disabled.
-
-<img src="https://github.com/allkern/psxe/assets/15825466/199c20e4-4e7e-4d0a-a033-eda347034ed5" width="12" height="12"/> CPU </br>
-<img src="https://github.com/allkern/psxe/assets/15825466/199c20e4-4e7e-4d0a-a033-eda347034ed5" width="12" height="12"/> DMA </br>
-<img src="https://github.com/allkern/psxe/assets/15825466/199c20e4-4e7e-4d0a-a033-eda347034ed5" width="12" height="12"/> GPU </br>
-<img src="https://github.com/allkern/psxe/assets/15825466/199c20e4-4e7e-4d0a-a033-eda347034ed5" width="12" height="12"/> SPU </br>
-<img src="https://github.com/allkern/psxe/assets/15825466/199c20e4-4e7e-4d0a-a033-eda347034ed5" width="12" height="12"/> MDEC </br>
-<img src="https://github.com/allkern/psxe/assets/15825466/199c20e4-4e7e-4d0a-a033-eda347034ed5" width="12" height="12"/> GTE </br>
-<img src="https://github.com/allkern/psxe/assets/15825466/199c20e4-4e7e-4d0a-a033-eda347034ed5" width="12" height="12"/> Timers </br>
-<img src="https://github.com/allkern/psxe/assets/15825466/199c20e4-4e7e-4d0a-a033-eda347034ed5" width="12" height="12"/> CDROM </br>
-<img src="https://github.com/allkern/psxe/assets/15825466/0ed1fe97-de2f-47de-bb30-82286e6c5fa0" width="12" height="12"/> Memory cards </br>
-
-## Building
-Building the emulator should be easy, just use the scripts provided in this repo.
-
-On Windows, the `build-deps.ps1` script downloads SDL2 and unzips it. If you want to run the emulator standalone, you will have to move the SDL2 DLL to the same folder where the executable is located.
-
-**If you already have SDL2 on your system**, you can skip running `build-deps.ps1`. Though you will have to edit `build-win.ps1` to point the `SDL2_DIR` variable to your installation path.
-
-On Ubuntu, you will also need to install `libsdl2-dev`, you can get it from `apt` like so:
-```
-sudo apt update
-sudo apt upgrade
-sudo apt install libsdl2-dev
-```
-
-Building on macOS requires installing SDL2 and dylibbundler, this can be done using `brew`:
-```
-brew install sdl2
-brew install dylibbundler
-```
-
-Assuming you did everything described above, you should be able to build the emulator by using the following commands.
-
-### Windows
-```
-git clone https://github.com/allkern/psxe
-cd psxe
-./build-deps
-./build-win64.ps1
-```
-On rare cases these scripts might not work (PowerShell/Windows bugs). If so, please open an issue on the issues tab with information about your system so we can make sure we cover the maximum amount of systems.
-
-### Ubuntu
-```
-git clone https://github.com/allkern/psxe
-cd psxe
-make clean && make
-```
-
-### macOS
-```
-git clone https://github.com/allkern/psxe
-cd psxe
-./build.sh
-```
-
-## Acknowledgements
-This project uses external open source code that can be found on the following GitHub repos:
-- argparse.c: https://github.com/cofyc/argparse
-- log.c (slightly modified): https://github.com/rxi/log.c
-- tomlc99: https://github.com/cktan/tomlc99
-
-Their original licenses are respected and apply to the code in this project.
-
-As always, thanks to all original developers for their amazing work.
+# psxe
+A simple and portable Sony PlayStation emulator and emulation library written in C
+
+## Screenshots
+| Windows | Ubuntu | macOS |
+| ------------- | ------------- | -------------
+|  |  |  |
+|  |  |  |
+
+### CI status
+
+
+
+
+## Running
+You can download the latest automated build for your platform on Releases. If your system isn't supported, you can easily build the emulator from source, instructions on "Building" below.
+
+In order to run the emulator, you will need a BIOS file. You can either get one from the internet or [dump it from your own console](https://www.youtube.com/watch?v=u8eHp0COcBo).
+
+Most BIOS versions are confirmed to work.
+
+Use the `-b` or `--bios` setting to configure the BIOS file.
+
+## Progress
+All components have been implemented, Memory card support is temporarily disabled.
+
+<img src="https://github.com/allkern/psxe/assets/15825466/199c20e4-4e7e-4d0a-a033-eda347034ed5" width="12" height="12"/> CPU </br>
+<img src="https://github.com/allkern/psxe/assets/15825466/199c20e4-4e7e-4d0a-a033-eda347034ed5" width="12" height="12"/> DMA </br>
+<img src="https://github.com/allkern/psxe/assets/15825466/199c20e4-4e7e-4d0a-a033-eda347034ed5" width="12" height="12"/> GPU </br>
+<img src="https://github.com/allkern/psxe/assets/15825466/199c20e4-4e7e-4d0a-a033-eda347034ed5" width="12" height="12"/> SPU </br>
+<img src="https://github.com/allkern/psxe/assets/15825466/199c20e4-4e7e-4d0a-a033-eda347034ed5" width="12" height="12"/> MDEC </br>
+<img src="https://github.com/allkern/psxe/assets/15825466/199c20e4-4e7e-4d0a-a033-eda347034ed5" width="12" height="12"/> GTE </br>
+<img src="https://github.com/allkern/psxe/assets/15825466/199c20e4-4e7e-4d0a-a033-eda347034ed5" width="12" height="12"/> Timers </br>
+<img src="https://github.com/allkern/psxe/assets/15825466/199c20e4-4e7e-4d0a-a033-eda347034ed5" width="12" height="12"/> CDROM </br>
+<img src="https://github.com/allkern/psxe/assets/15825466/0ed1fe97-de2f-47de-bb30-82286e6c5fa0" width="12" height="12"/> Memory cards </br>
+
+## Building
+Building the emulator should be easy, just use the scripts provided in this repo.
+
+On Windows, the `build-deps.ps1` script downloads SDL2 and unzips it. If you want to run the emulator standalone, you will have to move the SDL2 DLL to the same folder where the executable is located.
+
+**If you already have SDL2 on your system**, you can skip running `build-deps.ps1`. Though you will have to edit `build-win.ps1` to point the `SDL2_DIR` variable to your installation path.
+
+On Ubuntu, you will also need to install `libsdl2-dev`, you can get it from `apt` like so:
+```
+sudo apt update
+sudo apt upgrade
+sudo apt install libsdl2-dev
+```
+
+Building on macOS requires installing SDL2 and dylibbundler, this can be done using `brew`:
+```
+brew install sdl2
+brew install dylibbundler
+```
+
+Assuming you did everything described above, you should be able to build the emulator by using the following commands.
+
+### Windows
+```
+git clone https://github.com/allkern/psxe
+cd psxe
+./build-deps
+./build-win64.ps1
+```
+On rare cases these scripts might not work (PowerShell/Windows bugs). If so, please open an issue on the issues tab with information about your system so we can make sure we cover the maximum amount of systems.
+
+### Ubuntu
+```
+git clone https://github.com/allkern/psxe
+cd psxe
+make clean && make
+```
+
+### macOS
+```
+git clone https://github.com/allkern/psxe
+cd psxe
+./build.sh
+```
+
+## Acknowledgements
+This project uses external open source code that can be found on the following GitHub repos:
+- argparse.c: https://github.com/cofyc/argparse
+- log.c (slightly modified): https://github.com/rxi/log.c
+- tomlc99: https://github.com/cktan/tomlc99
+
+Their original licenses are respected and apply to the code in this project.
+
+As always, thanks to all original developers for their amazing work.
--- a/build-deps.ps1
+++ b/build-deps.ps1
@@ -1,10 +1,10 @@
-if (Test-Path "SDL2-2.30.3") {
- Remove-Item -Recurse "SDL2-2.30.3"
-}
-
-$SDL2_URL = "https://github.com/libsdl-org/SDL/releases/download/release-2.30.3/SDL2-devel-2.30.3-mingw.zip"
-
-Invoke-WebRequest -URI $SDL2_URL -OutFile "sdl2.zip"
-Expand-Archive "sdl2.zip" -DestinationPath "." -Force
-
+if (Test-Path "SDL2-2.30.3") {+ Remove-Item -Recurse "SDL2-2.30.3"
+}
+
+$SDL2_URL = "https://github.com/libsdl-org/SDL/releases/download/release-2.30.3/SDL2-devel-2.30.3-mingw.zip"
+
+Invoke-WebRequest -URI $SDL2_URL -OutFile "sdl2.zip"
+Expand-Archive "sdl2.zip" -DestinationPath "." -Force
+
Remove-Item "sdl2.zip"
\ No newline at end of file
--- a/build-win32.ps1
+++ b/build-win32.ps1
@@ -1,32 +1,32 @@
-git fetch --all --tags
-
-$VERSION_TAG = git describe --always --tags --abbrev=0
-$COMMIT_HASH = git rev-parse --short HEAD
-$OS_INFO = (Get-WMIObject win32_operatingsystem).caption + " " + `
- (Get-WMIObject win32_operatingsystem).version + " " + `
- (Get-WMIObject win32_operatingsystem).OSArchitecture
-
-$SDL2_DIR = "SDL2-2.30.3\i686-w64-mingw32"
-$PSX_DIR = "."
-
-mkdir -Force -Path bin > $null
-
-gcc -I"$($PSX_DIR)" `
- -I"$($PSX_DIR)\psx" `
- -I"$($SDL2_DIR)\include\SDL2" `
- "psx\*.c" `
- "psx\dev\*.c" `
- "psx\input\*.c" `
- "psx\disc\*.c" `
- "frontend\*.c" `
- -o "bin\psxe.exe" `
- -DREP_VERSION="`"$($VERSION_TAG)`"" `
- -DREP_COMMIT_HASH="`"$($COMMIT_HASH)`"" `
- -DOS_INFO="`"$($OS_INFO)`"" `
- -L"$($SDL2_DIR)\lib" `
- -lSDL2main -lSDL2 -Wno-overflow `
- -Wall -pedantic -DLOG_USE_COLOR `
- -Wno-address-of-packed-member `
- -ffast-math -Ofast -g -flto
-
+git fetch --all --tags
+
+$VERSION_TAG = git describe --always --tags --abbrev=0
+$COMMIT_HASH = git rev-parse --short HEAD
+$OS_INFO = (Get-WMIObject win32_operatingsystem).caption + " " + `
+ (Get-WMIObject win32_operatingsystem).version + " " + `
+ (Get-WMIObject win32_operatingsystem).OSArchitecture
+
+$SDL2_DIR = "SDL2-2.30.3\i686-w64-mingw32"
+$PSX_DIR = "."
+
+mkdir -Force -Path bin > $null
+
+gcc -I"$($PSX_DIR)" `
+ -I"$($PSX_DIR)\psx" `
+ -I"$($SDL2_DIR)\include\SDL2" `
+ "psx\*.c" `
+ "psx\dev\*.c" `
+ "psx\input\*.c" `
+ "psx\disc\*.c" `
+ "frontend\*.c" `
+ -o "bin\psxe.exe" `
+ -DREP_VERSION="`"$($VERSION_TAG)`"" `
+ -DREP_COMMIT_HASH="`"$($COMMIT_HASH)`"" `
+ -DOS_INFO="`"$($OS_INFO)`"" `
+ -L"$($SDL2_DIR)\lib" `
+ -lSDL2main -lSDL2 -Wno-overflow `
+ -Wall -pedantic -DLOG_USE_COLOR `
+ -Wno-address-of-packed-member `
+ -ffast-math -Ofast -g -flto
+
Copy-Item -Path "$($SDL2_DIR)\bin\SDL2.dll" -Destination "bin"
\ No newline at end of file
--- a/build-win64.ps1
+++ b/build-win64.ps1
@@ -1,32 +1,32 @@
-git fetch --all --tags
-
-$VERSION_TAG = git describe --always --tags --abbrev=0
-$COMMIT_HASH = git rev-parse --short HEAD
-$OS_INFO = (Get-WMIObject win32_operatingsystem).caption + " " + `
- (Get-WMIObject win32_operatingsystem).version + " " + `
- (Get-WMIObject win32_operatingsystem).OSArchitecture
-
-$SDL2_DIR = "SDL2-2.30.3\x86_64-w64-mingw32"
-$PSX_DIR = "."
-
-mkdir -Force -Path bin > $null
-
-gcc -I"$($PSX_DIR)" `
- -I"$($PSX_DIR)\psx" `
- -I"$($SDL2_DIR)\include\SDL2" `
- "psx\*.c" `
- "psx\dev\*.c" `
- "psx\dev\cdrom\*.c" `
- "psx\input\*.c" `
- "frontend\*.c" `
- -o "bin\psxe.exe" `
- -DREP_VERSION="`"$($VERSION_TAG)`"" `
- -DREP_COMMIT_HASH="`"$($COMMIT_HASH)`"" `
- -DOS_INFO="`"$($OS_INFO)`"" `
- -L"$($SDL2_DIR)\lib" `
- -m64 -lSDL2main -lSDL2 -Wno-overflow `
- -Wall -pedantic -DLOG_USE_COLOR `
- -Wno-address-of-packed-member `
- -ffast-math -Ofast -g -flto -Werror
-
+git fetch --all --tags
+
+$VERSION_TAG = git describe --always --tags --abbrev=0
+$COMMIT_HASH = git rev-parse --short HEAD
+$OS_INFO = (Get-WMIObject win32_operatingsystem).caption + " " + `
+ (Get-WMIObject win32_operatingsystem).version + " " + `
+ (Get-WMIObject win32_operatingsystem).OSArchitecture
+
+$SDL2_DIR = "SDL2-2.30.3\x86_64-w64-mingw32"
+$PSX_DIR = "."
+
+mkdir -Force -Path bin > $null
+
+gcc -I"$($PSX_DIR)" `
+ -I"$($PSX_DIR)\psx" `
+ -I"$($SDL2_DIR)\include\SDL2" `
+ "psx\*.c" `
+ "psx\dev\*.c" `
+ "psx\dev\cdrom\*.c" `
+ "psx\input\*.c" `
+ "frontend\*.c" `
+ -o "bin\psxe.exe" `
+ -DREP_VERSION="`"$($VERSION_TAG)`"" `
+ -DREP_COMMIT_HASH="`"$($COMMIT_HASH)`"" `
+ -DOS_INFO="`"$($OS_INFO)`"" `
+ -L"$($SDL2_DIR)\lib" `
+ -m64 -lSDL2main -lSDL2 -Wno-overflow `
+ -Wall -pedantic -DLOG_USE_COLOR `
+ -Wno-address-of-packed-member `
+ -ffast-math -Ofast -g -flto -Werror
+
Copy-Item -Path "$($SDL2_DIR)\bin\SDL2.dll" -Destination "bin"
\ No newline at end of file
--- a/frontend/common.h
+++ b/frontend/common.h
@@ -1,17 +1,17 @@
-#ifndef COMMON_H
-#define COMMON_H
-
-#ifndef OS_INFO
-#define OS_INFO unknown
-#endif
-#ifndef REP_VERSION
-#define REP_VERSION latest
-#endif
-#ifndef REP_COMMIT_HASH
-#define REP_COMMIT_HASH latest
-#endif
-
-#define STR1(m) #m
-#define STR(m) STR1(m)
-
+#ifndef COMMON_H
+#define COMMON_H
+
+#ifndef OS_INFO
+#define OS_INFO unknown
+#endif
+#ifndef REP_VERSION
+#define REP_VERSION latest
+#endif
+#ifndef REP_COMMIT_HASH
+#define REP_COMMIT_HASH latest
+#endif
+
+#define STR1(m) #m
+#define STR(m) STR1(m)
+
#endif
\ No newline at end of file
--- a/frontend/config.c
+++ b/frontend/config.c
@@ -1,299 +1,299 @@
-#include <string.h>
-#include <stdlib.h>
-
-#include "config.h"
-#include "common.h"
-
-#include "../psx/log.h"
-
-static const char* g_version_text =
-#ifdef _WIN32
- "psxe.exe (" STR(OS_INFO) ") " STR(REP_VERSION) "-" STR(REP_COMMIT_HASH) "\n"
-#elif __linux__
- "psxe (" STR(OS_INFO) ") " STR(REP_VERSION) "-" STR(REP_COMMIT_HASH) "\n"
-#else
- "psxe (" STR(OS_INFO) ") " STR(REP_VERSION) "-" STR(REP_COMMIT_HASH) "\n"
-#endif
- "\nPSXE - A simple, fast and portable Sony PlayStation emulator.\n\n"
- "Copyright (C) 2023 Allkern (Lisandro Alarcon)\n"
- "This is free software; see the source for copying conditions. There is NO\n"
- "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n";
-
-static const char g_default_settings[] =
- "# Settings file generated by PSXE\n"
- "\n"
- "# Don't change please, reserved for future use\n"
- "psxe_version = \"" STR(REP_VERSION) "\"\n"
- "\n"
- "# BIOS-related settings:\n"
- "[bios]\n"
- " search_path = \"bios\"\n"
- " preferred_model = \"SCPH-1001\"\n"
- " override_file = \"\"\n"
- "\n"
- "# Console settings\n"
- "[console]\n"
- " region = \"auto\"\n";
-
-static const char* g_models_text =
- "Available console models:\n"
- "\"scph1000\" (SCPH-1000) [NTSC-J]\n"
- "\"scph1001\" (SCPH-1001) [NTSC-U/C]\n"
- "\"scph1002\" (SCPH-1002) [PAL]\n"
- "\"scph3000\" (SCPH-3000) [NTSC-J]\n"
- "\"scph3500\" (SCPH-3500) [NTSC-J]\n"
- "\"scph5000\" (SCPH-5000) [NTSC-U/C]\n"
- "\"scph5501\" (SCPH-5501) [NTSC-U/C]\n"
- "\"scph5500\" (SCPH-5500) [NTSC-J]\n"
- "\"scph5502\" (SCPH-5502) [PAL]\n"
- "\"scph5552\" (SCPH-5552) [PAL]\n"
- "\"scph7000\" (SCPH-7000) [NTSC-J]\n"
- "\"scph7001\" (SCPH-7001) [NTSC-U/C]\n"
- "\"scph7002\" (SCPH-7002) [PAL]\n"
- "\"scph7003\" (SCPH-7003) [NTSC-J]\n"
- "\"scph7501\" (SCPH-7501) [NTSC]\n"
- "\"scph7502\" (SCPH-7502) [PAL]\n"
- "\"scph9002\" (SCPH-9002) [PAL]\n"
- "\"scph100\" (SCPH-100) [NTSC-J]\n"
- "\"scph101\" (SCPH-101) [NTSC-U/C]\n"
- "\"scph102a\" (SCPH-102A) [PAL]\n"
- "\"scph102b\" (SCPH-102B) [PAL]\n"
- "\"scph102c\" (SCPH-102C) [?]\n";
-
-static const char* g_regions_text =
- "Available region options: \"ntsc\", \"pal\", \"auto\"\n";
-
-static const char* g_desc_text =
- "\nPlease report any bugs to <https://github.com/allkern/psxe/issues>\n";
-
-psxe_config_t* psxe_cfg_create(void) {
- return (psxe_config_t*)malloc(sizeof(psxe_config_t));
-}
-
-void psxe_cfg_init(psxe_config_t* cfg) {
- memset(cfg, 0, sizeof(psxe_config_t));
-}
-
-void psxe_cfg_destroy(psxe_config_t* cfg) {
- free(cfg);
-}
-
-void psxe_cfg_load_defaults(psxe_config_t* cfg) {
- cfg->bios = "bios.bin";
- cfg->bios_search = "bios";
- cfg->exe = NULL;
- cfg->help_model = 0;
- cfg->help_region = 0;
- cfg->model = "scph1001";
- cfg->scale = 3;
- cfg->psxe_version = STR(REP_VERSION);
- cfg->region = "ntsc";
- cfg->settings_path = NULL;
- cfg->use_args = 0;
- cfg->version = 0;
- cfg->log_level = LOG_FATAL;
- cfg->quiet = 0;
- cfg->cd_path = NULL;
- cfg->exp_path = NULL;
-}
-
-void psxe_cfg_load(psxe_config_t* cfg, int argc, const char* argv[]) {
- log_set_level(LOG_INFO);
-
- int use_args = 0;
- int version = 0;
- int help_model = 0;
- int help_region = 0;
- int log_level = 0;
- int quiet = 0;
- int console_source = 0;
- int scale = 0;
- const char* settings_path = NULL;
- const char* bios = NULL;
- const char* bios_search = NULL;
- const char* model = NULL;
- const char* exe = NULL;
- const char* region = NULL;
- const char* psxe_version = NULL;
- const char* cd_path = NULL;
- const char* exp_path = NULL;
-
- static const char *const usages[] = {
- "psxe [options] path-to-cdrom",
- NULL,
- };
-
- struct argparse_option options[] = {
- OPT_BOOLEAN ('h', "help" , NULL , "Display this information", argparse_help_cb, 0, 0),
- OPT_BOOLEAN (0 , "help-model" , &help_model , "Display available console models", NULL, 0, 0),
- OPT_BOOLEAN (0 , "help-region" , &help_region , "Display available region options", NULL, 0, 0),
- OPT_BOOLEAN ('v', "version" , &version , "Display version and build information", NULL, 0, 0),
- OPT_GROUP("Basic options"),
- OPT_BOOLEAN ('a', "use-args" , &use_args , "Ignore settings file, use CLI args instead", NULL, 0, 0),
- OPT_STRING ('b', "bios" , &bios , "Specify a BIOS file (ignores -B, -M)", NULL, 0, 0),
- OPT_BOOLEAN ('B', "bios-folder" , &bios_search , "Specify a BIOS search folder", NULL, 0, 0),
- OPT_STRING ('c', "console-source", &console_source, "Select console source (auto, null, kernel, atcons)"),
- OPT_STRING ('e', "exp-rom" , &exp_path , "Specify an expansion ROM file"),
- OPT_INTEGER ('L', "log-level" , &log_level , "Set log level"),
- OPT_STRING ('M', "model" , &model , "Specify console model (SPCH-XXXX)", NULL, 0, 0),
- OPT_STRING ('r', "region" , ®ion , "Specify console region"),
- OPT_INTEGER ('s', "scale" , &scale , "Display scaling factor", NULL, 0, 0),
- OPT_STRING ('S', "settings-file" , &settings_path , "Specify settings file path", NULL, 0, 0),
- OPT_BOOLEAN ('q', "quiet" , &quiet , "Silence all logs (ignores -L)"),
- OPT_STRING ('x', "exe" , &exe , "Launch a PS-X EXE file"),
- OPT_STRING (0 , "cdrom" , &cd_path , "Specify a CDROM image"),
- OPT_END()
- };
-
- struct argparse argparse;
-
- argparse_init(&argparse, options, usages, 0);
- argparse_describe(&argparse, NULL, g_desc_text);
-
- argc = argparse_parse(&argparse, argc, argv);
-
- if (help_model) {
- printf("%s\n", g_models_text);
-
- exit(0);
- }
-
- if (help_region) {
- printf("%s\n", g_regions_text);
-
- exit(0);
- }
-
- if (version) {
- printf("%s\n", g_version_text);
-
- exit(0);
- }
-
- log_set_quiet(quiet);
-
- if (!use_args) {
- if (!settings_path)
- settings_path = "settings.toml";
-
- FILE* settings = fopen(settings_path, "rb");
-
- char error[0x100];
-
- if (!settings) {
- settings = fopen("settings.toml", "w+b");
-
- if (!settings) {
- log_error("Couldn't create settings file, loading default settings");
-
- psxe_cfg_load_defaults(cfg);
-
- return;
- }
-
- fwrite(g_default_settings, 1, sizeof(g_default_settings) - 1, settings);
-
- fseek(settings, 0, 0);
- }
-
- log_info("Parsing settings file...");
-
- toml_table_t* conf = toml_parse_file(settings, error, sizeof(error));
-
- if (!conf) {
- log_error("Couldn't parse settings file");
-
- exit(1);
- }
-
- toml_datum_t s_version = toml_string_in(conf, "psxe_version");
-
- if (!s_version.ok) {
- log_error("Settings file lacking version number");
-
- exit(1);
- }
-
- toml_table_t* s_bios_table = toml_table_in(conf, "bios");
-
- if (s_bios_table) {
- toml_datum_t s_bios_search_path = toml_string_in(s_bios_table, "search_path");
-
- if (s_bios_search_path.ok)
- bios_search = s_bios_search_path.u.s;
-
- toml_datum_t s_bios_preferred_model = toml_string_in(s_bios_table, "preferred_model");
-
- if (s_bios_preferred_model.ok)
- model = s_bios_preferred_model.u.s;
-
- toml_datum_t s_bios_override_file = toml_string_in(s_bios_table, "override_file");
-
- if (s_bios_override_file.ok)
- bios = s_bios_override_file.u.s;
- }
-
- toml_table_t* s_console_table = toml_table_in(conf, "console");
-
- if (s_console_table) {
- toml_datum_t s_console_region = toml_string_in(s_console_table, "region");
-
- if (s_console_region.ok)
- region = s_console_region.u.s;
- }
-
- psxe_version = s_version.u.s;
-
- log_info("Settings file parsed. PSXE version: %s", psxe_version);
-
- fclose(settings);
- }
-
- if (argc) {
- if (argc > 1) {
- log_error("Unrecognized parameter \'%s\'", argv[1]);
-
- exit(1);
- }
-
- cd_path = argv[0];
- }
-
- if (cd_path)
- cfg->cd_path = cd_path;
-
- if (log_level)
- cfg->log_level = log_level - 1;
-
- if (bios)
- cfg->bios = bios;
-
- if (bios_search)
- cfg->bios_search = bios_search;
-
- if (model)
- cfg->model = model;
-
- if (exe)
- cfg->exe = exe;
-
- if (region)
- cfg->region = region;
-
- if (psxe_version)
- cfg->psxe_version = psxe_version;
-
- if (exp_path)
- cfg->exp_path = exp_path;
-
- if (scale)
- cfg->scale = scale;
-}
-
-// To-do: Implement BIOS searching
-char* psxe_cfg_get_bios_path(psxe_config_t* cfg) {
- return NULL;
-}
-
-#undef STR1
+#include <string.h>
+#include <stdlib.h>
+
+#include "config.h"
+#include "common.h"
+
+#include "../psx/log.h"
+
+static const char* g_version_text =
+#ifdef _WIN32
+ "psxe.exe (" STR(OS_INFO) ") " STR(REP_VERSION) "-" STR(REP_COMMIT_HASH) "\n"+#elif __linux__
+ "psxe (" STR(OS_INFO) ") " STR(REP_VERSION) "-" STR(REP_COMMIT_HASH) "\n"+#else
+ "psxe (" STR(OS_INFO) ") " STR(REP_VERSION) "-" STR(REP_COMMIT_HASH) "\n"+#endif
+ "\nPSXE - A simple, fast and portable Sony PlayStation emulator.\n\n"
+ "Copyright (C) 2023 Allkern (Lisandro Alarcon)\n"
+ "This is free software; see the source for copying conditions. There is NO\n"
+ "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n";
+
+static const char g_default_settings[] =
+ "# Settings file generated by PSXE\n"
+ "\n"
+ "# Don't change please, reserved for future use\n"
+ "psxe_version = \"" STR(REP_VERSION) "\"\n"
+ "\n"
+ "# BIOS-related settings:\n"
+ "[bios]\n"
+ " search_path = \"bios\"\n"
+ " preferred_model = \"SCPH-1001\"\n"
+ " override_file = \"\"\n"
+ "\n"
+ "# Console settings\n"
+ "[console]\n"
+ " region = \"auto\"\n";
+
+static const char* g_models_text =
+ "Available console models:\n"
+ "\"scph1000\" (SCPH-1000) [NTSC-J]\n"
+ "\"scph1001\" (SCPH-1001) [NTSC-U/C]\n"
+ "\"scph1002\" (SCPH-1002) [PAL]\n"
+ "\"scph3000\" (SCPH-3000) [NTSC-J]\n"
+ "\"scph3500\" (SCPH-3500) [NTSC-J]\n"
+ "\"scph5000\" (SCPH-5000) [NTSC-U/C]\n"
+ "\"scph5501\" (SCPH-5501) [NTSC-U/C]\n"
+ "\"scph5500\" (SCPH-5500) [NTSC-J]\n"
+ "\"scph5502\" (SCPH-5502) [PAL]\n"
+ "\"scph5552\" (SCPH-5552) [PAL]\n"
+ "\"scph7000\" (SCPH-7000) [NTSC-J]\n"
+ "\"scph7001\" (SCPH-7001) [NTSC-U/C]\n"
+ "\"scph7002\" (SCPH-7002) [PAL]\n"
+ "\"scph7003\" (SCPH-7003) [NTSC-J]\n"
+ "\"scph7501\" (SCPH-7501) [NTSC]\n"
+ "\"scph7502\" (SCPH-7502) [PAL]\n"
+ "\"scph9002\" (SCPH-9002) [PAL]\n"
+ "\"scph100\" (SCPH-100) [NTSC-J]\n"
+ "\"scph101\" (SCPH-101) [NTSC-U/C]\n"
+ "\"scph102a\" (SCPH-102A) [PAL]\n"
+ "\"scph102b\" (SCPH-102B) [PAL]\n"
+ "\"scph102c\" (SCPH-102C) [?]\n";
+
+static const char* g_regions_text =
+ "Available region options: \"ntsc\", \"pal\", \"auto\"\n";
+
+static const char* g_desc_text =
+ "\nPlease report any bugs to <https://github.com/allkern/psxe/issues>\n";
+
+psxe_config_t* psxe_cfg_create(void) {+ return (psxe_config_t*)malloc(sizeof(psxe_config_t));
+}
+
+void psxe_cfg_init(psxe_config_t* cfg) {+ memset(cfg, 0, sizeof(psxe_config_t));
+}
+
+void psxe_cfg_destroy(psxe_config_t* cfg) {+ free(cfg);
+}
+
+void psxe_cfg_load_defaults(psxe_config_t* cfg) {+ cfg->bios = "bios.bin";
+ cfg->bios_search = "bios";
+ cfg->exe = NULL;
+ cfg->help_model = 0;
+ cfg->help_region = 0;
+ cfg->model = "scph1001";
+ cfg->scale = 3;
+ cfg->psxe_version = STR(REP_VERSION);
+ cfg->region = "ntsc";
+ cfg->settings_path = NULL;
+ cfg->use_args = 0;
+ cfg->version = 0;
+ cfg->log_level = LOG_FATAL;
+ cfg->quiet = 0;
+ cfg->cd_path = NULL;
+ cfg->exp_path = NULL;
+}
+
+void psxe_cfg_load(psxe_config_t* cfg, int argc, const char* argv[]) {+ log_set_level(LOG_INFO);
+
+ int use_args = 0;
+ int version = 0;
+ int help_model = 0;
+ int help_region = 0;
+ int log_level = 0;
+ int quiet = 0;
+ int console_source = 0;
+ int scale = 0;
+ const char* settings_path = NULL;
+ const char* bios = NULL;
+ const char* bios_search = NULL;
+ const char* model = NULL;
+ const char* exe = NULL;
+ const char* region = NULL;
+ const char* psxe_version = NULL;
+ const char* cd_path = NULL;
+ const char* exp_path = NULL;
+
+ static const char *const usages[] = {+ "psxe [options] path-to-cdrom",
+ NULL,
+ };
+
+ struct argparse_option options[] = {+ OPT_BOOLEAN ('h', "help" , NULL , "Display this information", argparse_help_cb, 0, 0),+ OPT_BOOLEAN (0 , "help-model" , &help_model , "Display available console models", NULL, 0, 0),
+ OPT_BOOLEAN (0 , "help-region" , &help_region , "Display available region options", NULL, 0, 0),
+ OPT_BOOLEAN ('v', "version" , &version , "Display version and build information", NULL, 0, 0),+ OPT_GROUP("Basic options"),+ OPT_BOOLEAN ('a', "use-args" , &use_args , "Ignore settings file, use CLI args instead", NULL, 0, 0),+ OPT_STRING ('b', "bios" , &bios , "Specify a BIOS file (ignores -B, -M)", NULL, 0, 0),+ OPT_BOOLEAN ('B', "bios-folder" , &bios_search , "Specify a BIOS search folder", NULL, 0, 0),+ OPT_STRING ('c', "console-source", &console_source, "Select console source (auto, null, kernel, atcons)"),+ OPT_STRING ('e', "exp-rom" , &exp_path , "Specify an expansion ROM file"),+ OPT_INTEGER ('L', "log-level" , &log_level , "Set log level"),+ OPT_STRING ('M', "model" , &model , "Specify console model (SPCH-XXXX)", NULL, 0, 0),+ OPT_STRING ('r', "region" , ®ion , "Specify console region"),+ OPT_INTEGER ('s', "scale" , &scale , "Display scaling factor", NULL, 0, 0),+ OPT_STRING ('S', "settings-file" , &settings_path , "Specify settings file path", NULL, 0, 0),+ OPT_BOOLEAN ('q', "quiet" , &quiet , "Silence all logs (ignores -L)"),+ OPT_STRING ('x', "exe" , &exe , "Launch a PS-X EXE file"),+ OPT_STRING (0 , "cdrom" , &cd_path , "Specify a CDROM image"),
+ OPT_END()
+ };
+
+ struct argparse argparse;
+
+ argparse_init(&argparse, options, usages, 0);
+ argparse_describe(&argparse, NULL, g_desc_text);
+
+ argc = argparse_parse(&argparse, argc, argv);
+
+ if (help_model) {+ printf("%s\n", g_models_text);+
+ exit(0);
+ }
+
+ if (help_region) {+ printf("%s\n", g_regions_text);+
+ exit(0);
+ }
+
+ if (version) {+ printf("%s\n", g_version_text);+
+ exit(0);
+ }
+
+ log_set_quiet(quiet);
+
+ if (!use_args) {+ if (!settings_path)
+ settings_path = "settings.toml";
+
+ FILE* settings = fopen(settings_path, "rb");
+
+ char error[0x100];
+
+ if (!settings) {+ settings = fopen("settings.toml", "w+b");+
+ if (!settings) {+ log_error("Couldn't create settings file, loading default settings");+
+ psxe_cfg_load_defaults(cfg);
+
+ return;
+ }
+
+ fwrite(g_default_settings, 1, sizeof(g_default_settings) - 1, settings);
+
+ fseek(settings, 0, 0);
+ }
+
+ log_info("Parsing settings file...");+
+ toml_table_t* conf = toml_parse_file(settings, error, sizeof(error));
+
+ if (!conf) {+ log_error("Couldn't parse settings file");+
+ exit(1);
+ }
+
+ toml_datum_t s_version = toml_string_in(conf, "psxe_version");
+
+ if (!s_version.ok) {+ log_error("Settings file lacking version number");+
+ exit(1);
+ }
+
+ toml_table_t* s_bios_table = toml_table_in(conf, "bios");
+
+ if (s_bios_table) {+ toml_datum_t s_bios_search_path = toml_string_in(s_bios_table, "search_path");
+
+ if (s_bios_search_path.ok)
+ bios_search = s_bios_search_path.u.s;
+
+ toml_datum_t s_bios_preferred_model = toml_string_in(s_bios_table, "preferred_model");
+
+ if (s_bios_preferred_model.ok)
+ model = s_bios_preferred_model.u.s;
+
+ toml_datum_t s_bios_override_file = toml_string_in(s_bios_table, "override_file");
+
+ if (s_bios_override_file.ok)
+ bios = s_bios_override_file.u.s;
+ }
+
+ toml_table_t* s_console_table = toml_table_in(conf, "console");
+
+ if (s_console_table) {+ toml_datum_t s_console_region = toml_string_in(s_console_table, "region");
+
+ if (s_console_region.ok)
+ region = s_console_region.u.s;
+ }
+
+ psxe_version = s_version.u.s;
+
+ log_info("Settings file parsed. PSXE version: %s", psxe_version);+
+ fclose(settings);
+ }
+
+ if (argc) {+ if (argc > 1) {+ log_error("Unrecognized parameter \'%s\'", argv[1]);+
+ exit(1);
+ }
+
+ cd_path = argv[0];
+ }
+
+ if (cd_path)
+ cfg->cd_path = cd_path;
+
+ if (log_level)
+ cfg->log_level = log_level - 1;
+
+ if (bios)
+ cfg->bios = bios;
+
+ if (bios_search)
+ cfg->bios_search = bios_search;
+
+ if (model)
+ cfg->model = model;
+
+ if (exe)
+ cfg->exe = exe;
+
+ if (region)
+ cfg->region = region;
+
+ if (psxe_version)
+ cfg->psxe_version = psxe_version;
+
+ if (exp_path)
+ cfg->exp_path = exp_path;
+
+ if (scale)
+ cfg->scale = scale;
+}
+
+// To-do: Implement BIOS searching
+char* psxe_cfg_get_bios_path(psxe_config_t* cfg) {+ return NULL;
+}
+
+#undef STR1
#undef STR
\ No newline at end of file
--- a/frontend/config.h
+++ b/frontend/config.h
@@ -1,37 +1,37 @@
-#ifndef CONFIG_H
-#define CONFIG_H
-
-#include <stdlib.h>
-
-#include "argparse.h"
-#include "toml.h"
-
-typedef struct {
- int use_args;
- int version;
- int help_model;
- int help_region;
- int log_level;
- int quiet;
- int console_source;
- int scale;
- const char* snap_path;
- const char* settings_path;
- const char* bios;
- const char* bios_search;
- const char* model;
- const char* exe;
- const char* region;
- const char* psxe_version;
- const char* cd_path;
- const char* exp_path;
-} psxe_config_t;
-
-psxe_config_t* psxe_cfg_create(void);
-void psxe_cfg_init(psxe_config_t*);
-void psxe_cfg_load_defaults(psxe_config_t*);
-void psxe_cfg_load(psxe_config_t*, int, const char**);
-char* psxe_cfg_get_bios_path(psxe_config_t*);
-void psxe_cfg_destroy(psxe_config_t*);
-
+#ifndef CONFIG_H
+#define CONFIG_H
+
+#include <stdlib.h>
+
+#include "argparse.h"
+#include "toml.h"
+
+typedef struct {+ int use_args;
+ int version;
+ int help_model;
+ int help_region;
+ int log_level;
+ int quiet;
+ int console_source;
+ int scale;
+ const char* snap_path;
+ const char* settings_path;
+ const char* bios;
+ const char* bios_search;
+ const char* model;
+ const char* exe;
+ const char* region;
+ const char* psxe_version;
+ const char* cd_path;
+ const char* exp_path;
+} psxe_config_t;
+
+psxe_config_t* psxe_cfg_create(void);
+void psxe_cfg_init(psxe_config_t*);
+void psxe_cfg_load_defaults(psxe_config_t*);
+void psxe_cfg_load(psxe_config_t*, int, const char**);
+char* psxe_cfg_get_bios_path(psxe_config_t*);
+void psxe_cfg_destroy(psxe_config_t*);
+
#endif
\ No newline at end of file
--- a/frontend/main.c
+++ b/frontend/main.c
@@ -1,129 +1,129 @@
-#include "../psx/psx.h"
-#include "../psx/input/sda.h"
-#include "../psx/input/guncon.h"
-#include "../psx/dev/cdrom/cdrom.h"
-
-#include "screen.h"
-#include "config.h"
-
-#undef main
-
-void audio_update(void* ud, uint8_t* buf, int size) {
- psx_cdrom_t* cdrom = ((psx_t*)ud)->cdrom;
- psx_spu_t* spu = ((psx_t*)ud)->spu;
-
- memset(buf, 0, size);
-
- psx_cdrom_get_audio_samples(cdrom, buf, size);
- psx_spu_update_cdda_buffer(spu, cdrom->cdda_buf);
-
- for (int i = 0; i < (size >> 2); i++) {
- uint32_t sample = psx_spu_get_sample(spu);
-
- int16_t left = (int16_t)(sample & 0xffff);
- int16_t right = (int16_t)(sample >> 16);
-
- *(int16_t*)(&buf[(i << 2) + 0]) += left;
- *(int16_t*)(&buf[(i << 2) + 2]) += right;
- }
-}
-
-int main(int argc, const char* argv[]) {
- psxe_config_t* cfg = psxe_cfg_create();
-
- psxe_cfg_init(cfg);
- psxe_cfg_load_defaults(cfg);
- psxe_cfg_load(cfg, argc, argv);
-
- log_set_level(cfg->log_level);
-
- psx_t* psx = psx_create();
- psx_init(psx, cfg->bios, cfg->exp_path);
-
- psx_cdrom_t* cdrom = psx_get_cdrom(psx);
-
- // To-do: Set CDROM firmware version and region based
- // on CLI options
-
- if (cfg->cd_path)
- psx_cdrom_open(cdrom, cfg->cd_path);
-
- psxe_screen_t* screen = psxe_screen_create();
- psxe_screen_init(screen, psx);
- psxe_screen_set_scale(screen, cfg->scale);
- psxe_screen_reload(screen);
-
- SDL_Init(SDL_INIT_AUDIO);
-
- SDL_AudioDeviceID dev;
- SDL_AudioSpec obtained, desired;
-
- desired.freq = 44100;
- desired.format = AUDIO_S16SYS;
- desired.channels = 2;
- desired.samples = CD_SECTOR_SIZE >> 2;
- desired.callback = &audio_update;
- desired.userdata = psx;
-
- dev = SDL_OpenAudioDevice(NULL, 0, &desired, &obtained, 0);
-
- if (dev)
- SDL_PauseAudioDevice(dev, 0);
-
- psx_gpu_t* gpu = psx_get_gpu(psx);
- psx_gpu_set_event_callback(gpu, GPU_EVENT_DMODE, psxe_gpu_dmode_event_cb);
- psx_gpu_set_event_callback(gpu, GPU_EVENT_VBLANK, psxe_gpu_vblank_event_cb);
- psx_gpu_set_event_callback(gpu, GPU_EVENT_HBLANK, psxe_gpu_hblank_event_cb);
- psx_gpu_set_event_callback(gpu, GPU_EVENT_VBLANK_END, psxe_gpu_vblank_end_event_cb);
- psx_gpu_set_event_callback(gpu, GPU_EVENT_HBLANK_END, psxe_gpu_hblank_end_event_cb);
- psx_gpu_set_udata(gpu, 0, screen);
- psx_gpu_set_udata(gpu, 1, psx->timer);
-
- psx_input_t* input = psx_input_create();
- psx_input_init(input);
-
- // psxi_guncon_t* controller = psxi_guncon_create();
- // psxi_guncon_init(controller);
- // psxi_guncon_init_input(controller, input);
- psxi_sda_t* controller = psxi_sda_create();
- psxi_sda_init(controller, SDA_MODEL_DIGITAL);
- psxi_sda_init_input(controller, input);
-
- psx_pad_attach_joy(psx->pad, 0, input);
- psx_pad_attach_mcd(psx->pad, 0, "slot1.mcd");
- psx_pad_attach_mcd(psx->pad, 1, "slot2.mcd");
-
- if (cfg->exe) {
- while (psx->cpu->pc != 0x80030000)
- psx_update(psx);
-
- psx_load_exe(psx, cfg->exe);
- }
-
- psxe_cfg_destroy(cfg);
-
- while (psxe_screen_is_open(screen))
- psx_update(psx);
-
- SDL_PauseAudioDevice(dev, 1);
-
- psx_cpu_t* cpu = psx_get_cpu(psx);
-
- log_set_quiet(0);
-
- log_fatal("r0=%08x at=%08x v0=%08x v1=%08x", cpu->r[0] , cpu->r[1] , cpu->r[2] , cpu->r[3] );
- log_fatal("a0=%08x a1=%08x a2=%08x a3=%08x", cpu->r[4] , cpu->r[5] , cpu->r[6] , cpu->r[7] );
- log_fatal("t0=%08x t1=%08x t2=%08x t3=%08x", cpu->r[8] , cpu->r[9] , cpu->r[10], cpu->r[11]);
- log_fatal("t4=%08x t5=%08x t6=%08x t7=%08x", cpu->r[12], cpu->r[13], cpu->r[14], cpu->r[15]);
- log_fatal("s0=%08x s1=%08x s2=%08x s3=%08x", cpu->r[16], cpu->r[17], cpu->r[18], cpu->r[19]);
- log_fatal("s4=%08x s5=%08x s6=%08x s7=%08x", cpu->r[20], cpu->r[21], cpu->r[22], cpu->r[23]);
- log_fatal("t8=%08x t9=%08x k0=%08x k1=%08x", cpu->r[24], cpu->r[25], cpu->r[26], cpu->r[27]);
- log_fatal("gp=%08x sp=%08x fp=%08x ra=%08x", cpu->r[28], cpu->r[29], cpu->r[30], cpu->r[31]);
- log_fatal("pc=%08x hi=%08x lo=%08x ep=%08x", cpu->pc, cpu->hi, cpu->lo, cpu->cop0_r[COP0_EPC]);
-
- psx_pad_detach_joy(psx->pad, 0);
- psx_destroy(psx);
- psxe_screen_destroy(screen);
-
- return 0;
+#include "../psx/psx.h"
+#include "../psx/input/sda.h"
+#include "../psx/input/guncon.h"
+#include "../psx/dev/cdrom/cdrom.h"
+
+#include "screen.h"
+#include "config.h"
+
+#undef main
+
+void audio_update(void* ud, uint8_t* buf, int size) {+ psx_cdrom_t* cdrom = ((psx_t*)ud)->cdrom;
+ psx_spu_t* spu = ((psx_t*)ud)->spu;
+
+ memset(buf, 0, size);
+
+ psx_cdrom_get_audio_samples(cdrom, buf, size);
+ psx_spu_update_cdda_buffer(spu, cdrom->cdda_buf);
+
+ for (int i = 0; i < (size >> 2); i++) {+ uint32_t sample = psx_spu_get_sample(spu);
+
+ int16_t left = (int16_t)(sample & 0xffff);
+ int16_t right = (int16_t)(sample >> 16);
+
+ *(int16_t*)(&buf[(i << 2) + 0]) += left;
+ *(int16_t*)(&buf[(i << 2) + 2]) += right;
+ }
+}
+
+int main(int argc, const char* argv[]) {+ psxe_config_t* cfg = psxe_cfg_create();
+
+ psxe_cfg_init(cfg);
+ psxe_cfg_load_defaults(cfg);
+ psxe_cfg_load(cfg, argc, argv);
+
+ log_set_level(cfg->log_level);
+
+ psx_t* psx = psx_create();
+ psx_init(psx, cfg->bios, cfg->exp_path);
+
+ psx_cdrom_t* cdrom = psx_get_cdrom(psx);
+
+ // To-do: Set CDROM firmware version and region based
+ // on CLI options
+
+ if (cfg->cd_path)
+ psx_cdrom_open(cdrom, cfg->cd_path);
+
+ psxe_screen_t* screen = psxe_screen_create();
+ psxe_screen_init(screen, psx);
+ psxe_screen_set_scale(screen, cfg->scale);
+ psxe_screen_reload(screen);
+
+ SDL_Init(SDL_INIT_AUDIO);
+
+ SDL_AudioDeviceID dev;
+ SDL_AudioSpec obtained, desired;
+
+ desired.freq = 44100;
+ desired.format = AUDIO_S16SYS;
+ desired.channels = 2;
+ desired.samples = CD_SECTOR_SIZE >> 2;
+ desired.callback = &audio_update;
+ desired.userdata = psx;
+
+ dev = SDL_OpenAudioDevice(NULL, 0, &desired, &obtained, 0);
+
+ if (dev)
+ SDL_PauseAudioDevice(dev, 0);
+
+ psx_gpu_t* gpu = psx_get_gpu(psx);
+ psx_gpu_set_event_callback(gpu, GPU_EVENT_DMODE, psxe_gpu_dmode_event_cb);
+ psx_gpu_set_event_callback(gpu, GPU_EVENT_VBLANK, psxe_gpu_vblank_event_cb);
+ psx_gpu_set_event_callback(gpu, GPU_EVENT_HBLANK, psxe_gpu_hblank_event_cb);
+ psx_gpu_set_event_callback(gpu, GPU_EVENT_VBLANK_END, psxe_gpu_vblank_end_event_cb);
+ psx_gpu_set_event_callback(gpu, GPU_EVENT_HBLANK_END, psxe_gpu_hblank_end_event_cb);
+ psx_gpu_set_udata(gpu, 0, screen);
+ psx_gpu_set_udata(gpu, 1, psx->timer);
+
+ psx_input_t* input = psx_input_create();
+ psx_input_init(input);
+
+ // psxi_guncon_t* controller = psxi_guncon_create();
+ // psxi_guncon_init(controller);
+ // psxi_guncon_init_input(controller, input);
+ psxi_sda_t* controller = psxi_sda_create();
+ psxi_sda_init(controller, SDA_MODEL_DIGITAL);
+ psxi_sda_init_input(controller, input);
+
+ psx_pad_attach_joy(psx->pad, 0, input);
+ psx_pad_attach_mcd(psx->pad, 0, "slot1.mcd");
+ psx_pad_attach_mcd(psx->pad, 1, "slot2.mcd");
+
+ if (cfg->exe) {+ while (psx->cpu->pc != 0x80030000)
+ psx_update(psx);
+
+ psx_load_exe(psx, cfg->exe);
+ }
+
+ psxe_cfg_destroy(cfg);
+
+ while (psxe_screen_is_open(screen))
+ psx_update(psx);
+
+ SDL_PauseAudioDevice(dev, 1);
+
+ psx_cpu_t* cpu = psx_get_cpu(psx);
+
+ log_set_quiet(0);
+
+ log_fatal("r0=%08x at=%08x v0=%08x v1=%08x", cpu->r[0] , cpu->r[1] , cpu->r[2] , cpu->r[3] );+ log_fatal("a0=%08x a1=%08x a2=%08x a3=%08x", cpu->r[4] , cpu->r[5] , cpu->r[6] , cpu->r[7] );+ log_fatal("t0=%08x t1=%08x t2=%08x t3=%08x", cpu->r[8] , cpu->r[9] , cpu->r[10], cpu->r[11]);+ log_fatal("t4=%08x t5=%08x t6=%08x t7=%08x", cpu->r[12], cpu->r[13], cpu->r[14], cpu->r[15]);+ log_fatal("s0=%08x s1=%08x s2=%08x s3=%08x", cpu->r[16], cpu->r[17], cpu->r[18], cpu->r[19]);+ log_fatal("s4=%08x s5=%08x s6=%08x s7=%08x", cpu->r[20], cpu->r[21], cpu->r[22], cpu->r[23]);+ log_fatal("t8=%08x t9=%08x k0=%08x k1=%08x", cpu->r[24], cpu->r[25], cpu->r[26], cpu->r[27]);+ log_fatal("gp=%08x sp=%08x fp=%08x ra=%08x", cpu->r[28], cpu->r[29], cpu->r[30], cpu->r[31]);+ log_fatal("pc=%08x hi=%08x lo=%08x ep=%08x", cpu->pc, cpu->hi, cpu->lo, cpu->cop0_r[COP0_EPC]);+
+ psx_pad_detach_joy(psx->pad, 0);
+ psx_destroy(psx);
+ psxe_screen_destroy(screen);
+
+ return 0;
}
\ No newline at end of file
--- a/frontend/screen.c
+++ b/frontend/screen.c
@@ -1,534 +1,534 @@
-#include "screen.h"
-
-#include "input/sda.h"
-#include "input/guncon.h"
-
-uint32_t screen_get_button(SDL_Keycode k) {
- if (k == SDLK_x ) return PSXI_SW_SDA_CROSS;
- if (k == SDLK_a ) return PSXI_SW_SDA_SQUARE;
- if (k == SDLK_w ) return PSXI_SW_SDA_TRIANGLE;
- if (k == SDLK_d ) return PSXI_SW_SDA_CIRCLE;
- if (k == SDLK_RETURN) return PSXI_SW_SDA_START;
- if (k == SDLK_s ) return PSXI_SW_SDA_SELECT;
- if (k == SDLK_UP ) return PSXI_SW_SDA_PAD_UP;
- if (k == SDLK_DOWN ) return PSXI_SW_SDA_PAD_DOWN;
- if (k == SDLK_LEFT ) return PSXI_SW_SDA_PAD_LEFT;
- if (k == SDLK_RIGHT ) return PSXI_SW_SDA_PAD_RIGHT;
- if (k == SDLK_q ) return PSXI_SW_SDA_L1;
- if (k == SDLK_e ) return PSXI_SW_SDA_R1;
- if (k == SDLK_1 ) return PSXI_SW_SDA_L2;
- if (k == SDLK_3 ) return PSXI_SW_SDA_R2;
- if (k == SDLK_z ) return PSXI_SW_SDA_L3;
- if (k == SDLK_c ) return PSXI_SW_SDA_R3;
- if (k == SDLK_2 ) return PSXI_SW_SDA_ANALOG;
-
- return 0;
-}
-
-uint32_t screen_get_button_joystick(uint8_t b) {
- if (b == SDL_CONTROLLER_BUTTON_A ) return PSXI_SW_SDA_CROSS;
- if (b == SDL_CONTROLLER_BUTTON_X ) return PSXI_SW_SDA_SQUARE;
- if (b == SDL_CONTROLLER_BUTTON_Y ) return PSXI_SW_SDA_TRIANGLE;
- if (b == SDL_CONTROLLER_BUTTON_B ) return PSXI_SW_SDA_CIRCLE;
- if (b == SDL_CONTROLLER_BUTTON_START ) return PSXI_SW_SDA_START;
- if (b == SDL_CONTROLLER_BUTTON_GUIDE ) return PSXI_SW_SDA_SELECT;
- if (b == SDL_CONTROLLER_BUTTON_DPAD_UP ) return PSXI_SW_SDA_PAD_UP;
- if (b == SDL_CONTROLLER_BUTTON_DPAD_DOWN ) return PSXI_SW_SDA_PAD_DOWN;
- if (b == SDL_CONTROLLER_BUTTON_DPAD_LEFT ) return PSXI_SW_SDA_PAD_LEFT;
- if (b == SDL_CONTROLLER_BUTTON_DPAD_RIGHT ) return PSXI_SW_SDA_PAD_RIGHT;
- if (b == SDL_CONTROLLER_BUTTON_LEFTSHOULDER ) return PSXI_SW_SDA_L1;
- if (b == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) return PSXI_SW_SDA_R1;
- if (b == SDL_CONTROLLER_AXIS_TRIGGERLEFT ) return PSXI_SW_SDA_L2; // Can't map these yet
- if (b == SDL_CONTROLLER_AXIS_TRIGGERRIGHT ) return PSXI_SW_SDA_R2; // Can't map these yet
- if (b == SDL_CONTROLLER_BUTTON_LEFTSTICK ) return PSXI_SW_SDA_L3;
- if (b == SDL_CONTROLLER_BUTTON_RIGHTSTICK ) return PSXI_SW_SDA_R3;
-
- return 0;
-}
-
-SDL_GameController* screen_find_controller(void) {
- for (int i = 0; i < SDL_NumJoysticks(); i++)
- if (SDL_IsGameController(i))
- return SDL_GameControllerOpen(i);
-
- return NULL;
-}
-
-int screen_get_base_width(psxe_screen_t* screen) {
- int width = psx_get_dmode_width(screen->psx);
-
- switch (width) {
- case 256: return 256;
- case 320: return 320;
- case 368: return 384;
- }
-
- return 320;
-}
-
-psxe_screen_t* psxe_screen_create(void) {
- return (psxe_screen_t*)malloc(sizeof(psxe_screen_t));
-}
-
-void psxe_screen_init(psxe_screen_t* screen, psx_t* psx) {
- memset(screen, 0, sizeof(psxe_screen_t));
-
- if (screen->debug_mode) {
- screen->width = PSX_GPU_FB_WIDTH;
- screen->height = PSX_GPU_FB_HEIGHT;
- } else {
- screen->width = 320;
- screen->height = 240;
- }
-
- screen->scale = 1;
- screen->open = 1;
- screen->format = SDL_PIXELFORMAT_BGR555;
- screen->psx = psx;
- screen->pad = psx_get_pad(psx);
-
- screen->texture_width = PSX_GPU_FB_WIDTH;
- screen->texture_height = PSX_GPU_FB_HEIGHT;
-
- SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_GAMECONTROLLER);
- SDL_SetRenderDrawColor(screen->renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
-
- screen->controller = screen_find_controller();
-}
-
-void psxe_screen_reload(psxe_screen_t* screen) {
- if (screen->texture) SDL_DestroyTexture(screen->texture);
- if (screen->renderer) SDL_DestroyRenderer(screen->renderer);
- if (screen->window) SDL_DestroyWindow(screen->window);
-
- if (screen->debug_mode) {
- screen->width = PSX_GPU_FB_WIDTH;
- screen->height = PSX_GPU_FB_HEIGHT;
- } else {
- if (screen->vertical_mode) {
- screen->width = 240;
- screen->height = screen_get_base_width(screen);
- } else {
- screen->width = screen_get_base_width(screen);
- screen->height = 240;
- }
- }
-
- screen->window = SDL_CreateWindow(
- "psxe " STR(REP_VERSION) "-" STR(REP_COMMIT_HASH),
- SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
- screen->width * screen->scale,
- screen->height * screen->scale,
- 0
- );
-
- screen->renderer = SDL_CreateRenderer(
- screen->window,
- -1,
- SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC
- );
-
- screen->texture = SDL_CreateTexture(
- screen->renderer,
- screen->format,
- SDL_TEXTUREACCESS_STREAMING,
- screen->texture_width, screen->texture_height
- );
-
-#if SDL_VERSION_ATLEAST(2, 0, 12)
- SDL_SetTextureScaleMode(screen->texture, screen->bilinear);
-#endif
-
- // Check for retina displays
- int width = 0, height = 0;
-
- SDL_GetRendererOutputSize(screen->renderer, &width, &height);
-
- if (width != (screen->width * screen->scale)) {
- float width_scale = (float)width / (float)(screen->width * screen->scale);
- float height_scale = (float)height / (float)(screen->height * screen->scale);
-
- SDL_RenderSetScale(screen->renderer, width_scale, height_scale);
- }
-
- screen->open = 1;
-}
-
-int psxe_screen_is_open(psxe_screen_t* screen) {
- return screen->open;
-}
-
-void psxe_screen_toggle_debug_mode(psxe_screen_t* screen) {
- screen->debug_mode = !screen->debug_mode;
-
- psxe_screen_set_scale(screen, screen->saved_scale);
-
- screen->texture_width = PSX_GPU_FB_WIDTH;
- screen->texture_height = PSX_GPU_FB_HEIGHT;
-
- psxe_gpu_dmode_event_cb(screen->psx->gpu);
-}
-
-// int frame = 0;
-
-void psxe_screen_update(psxe_screen_t* screen) {
- void* display_buf = screen->debug_mode ?
- psx_get_vram(screen->psx) : psx_get_display_buffer(screen->psx);
-
- // printf("res=(%u,%u) off=(%u,%u) disp=(%u,%u-%u,%u) draw=(%u,%u-%u,%u) vres=%u\n",
- // screen->texture_width,
- // screen->texture_height,
- // screen->psx->gpu->disp_x,
- // screen->psx->gpu->disp_y,
- // screen->psx->gpu->disp_x1,
- // screen->psx->gpu->disp_y1,
- // screen->psx->gpu->disp_x2,
- // screen->psx->gpu->disp_y2,
- // screen->psx->gpu->draw_x1,
- // screen->psx->gpu->draw_y1,
- // screen->psx->gpu->draw_x2,
- // screen->psx->gpu->draw_y2,
- // screen->psx->gpu->disp_y2 - screen->psx->gpu->disp_y1
- // );
-
- if ((screen->psx->gpu->disp_y + screen->texture_height) > 512)
- display_buf = psx_get_vram(screen->psx);
-
- SDL_UpdateTexture(screen->texture, NULL, display_buf, PSX_GPU_FB_STRIDE);
- SDL_RenderClear(screen->renderer);
-
- if (!screen->debug_mode) {
- SDL_Rect dstrect;
-
- dstrect.x = screen->image_xoff;
- dstrect.y = screen->image_yoff;
- dstrect.w = screen->image_width;
- dstrect.h = screen->image_height;
-
- SDL_RenderCopyEx(
- screen->renderer,
- screen->texture,
- NULL, &dstrect,
- screen->vertical_mode ? 270 : 0,
- NULL, SDL_FLIP_NONE
- );
- } else {
- SDL_RenderCopy(screen->renderer, screen->texture, NULL, NULL);
- }
-
- SDL_RenderPresent(screen->renderer);
-
- SDL_Event event;
-
- while (SDL_PollEvent(&event)) {
- switch (event.type) {
- case SDL_QUIT: {
- screen->open = 0;
- } break;
-
- case SDL_KEYDOWN: {
- switch (event.key.keysym.sym) {
- case SDLK_F1: {
- psxe_screen_toggle_debug_mode(screen);
-
- return;
- } break;
-
- case SDLK_F2: {
- SDL_Surface* surface = SDL_CreateRGBSurfaceWithFormat(
- 0,
- screen->width,
- screen->height,
- 16,
- SDL_PIXELFORMAT_BGR555
- );
-
- SDL_RenderReadPixels(
- screen->renderer,
- NULL,
- SDL_PIXELFORMAT_BGR555,
- surface->pixels, surface->pitch
- );
-
- SDL_SaveBMP(surface, "snap/screenshot.bmp");
-
- SDL_FreeSurface(surface);
- } break;
-
- case SDLK_F3: {
- screen->vertical_mode = !screen->vertical_mode;
-
- psxe_gpu_dmode_event_cb(screen->psx->gpu);
- } break;
-
- case SDLK_F4: {
- screen->bilinear = !screen->bilinear;
-
- psxe_gpu_dmode_event_cb(screen->psx->gpu);
- } break;
-
- case SDLK_F11: {
- screen->fullscreen = !screen->fullscreen;
-
- SDL_SetWindowFullscreen(
- screen->window,
- screen->fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0
- );
-
- psxe_gpu_dmode_event_cb(screen->psx->gpu);
-
- SDL_SetRenderDrawColor(screen->renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
- SDL_RenderClear(screen->renderer);
- } break;
-
- case SDLK_F5: {
- psx_soft_reset(screen->psx);
- } break;
-
- case SDLK_F6: {
- psx_swap_disc(screen->psx, ".\\roms\\Street Fighter II Movie (Japan) (Disc 2)\\Street Fighter II Movie (Japan) (Disc 2).cue");
- } break;
- }
-
- uint32_t mask = screen_get_button(event.key.keysym.sym);
-
- psx_pad_button_press(screen->pad, 0, mask);
-
- if (event.key.keysym.sym == SDLK_RETURN)
- psx_exp2_atcons_put(screen->psx->exp2, 13);
- } break;
-
- case SDL_CONTROLLERDEVICEADDED: {
- if (!screen->controller)
- screen->controller = SDL_GameControllerOpen(event.cdevice.which);
- } break;
-
- case SDL_CONTROLLERDEVICEREMOVED: {
- SDL_Joystick* joy = SDL_GameControllerGetJoystick(screen->controller);
- SDL_JoystickID id = SDL_JoystickInstanceID(joy);
-
- if (screen->controller && (event.cdevice.which == id)) {
- SDL_GameControllerClose(screen->controller);
-
- screen->controller = screen_find_controller();
- }
- } break;
-
- case SDL_CONTROLLERBUTTONDOWN: {
- SDL_Joystick* joy = SDL_GameControllerGetJoystick(screen->controller);
- SDL_JoystickID id = SDL_JoystickInstanceID(joy);
-
- if (screen->controller && (event.cdevice.which == id)) {
- uint32_t mask = screen_get_button_joystick(event.cbutton.button);
-
- psx_pad_button_press(screen->pad, 0, mask);
- }
- } break;
-
- case SDL_CONTROLLERBUTTONUP: {
- SDL_Joystick* joy = SDL_GameControllerGetJoystick(screen->controller);
- SDL_JoystickID id = SDL_JoystickInstanceID(joy);
-
- if (screen->controller && (event.cdevice.which == id)) {
- uint32_t mask = screen_get_button_joystick(event.cbutton.button);
-
- psx_pad_button_release(screen->pad, 0, mask);
- }
- } break;
-
- case SDL_CONTROLLERAXISMOTION: {
- SDL_Joystick* joy = SDL_GameControllerGetJoystick(screen->controller);
- SDL_JoystickID id = SDL_JoystickInstanceID(joy);
-
- if (screen->controller && (event.cdevice.which == id)) {
- int mapped_axis = ((int)event.caxis.value + INT16_MAX + 1) / 0x100;
-
- switch (event.caxis.axis) {
- case SDL_CONTROLLER_AXIS_RIGHTX:
- psx_pad_analog_change(screen->pad, 0, PSXI_AX_SDA_RIGHT_HORZ, mapped_axis);
- break;
-
- case SDL_CONTROLLER_AXIS_RIGHTY:
- psx_pad_analog_change(screen->pad, 0, PSXI_AX_SDA_RIGHT_VERT, mapped_axis);
- break;
-
- case SDL_CONTROLLER_AXIS_LEFTX:
- psx_pad_analog_change(screen->pad, 0, PSXI_AX_SDA_LEFT_HORZ, mapped_axis);
- break;
-
- case SDL_CONTROLLER_AXIS_LEFTY:
- psx_pad_analog_change(screen->pad, 0, PSXI_AX_SDA_LEFT_VERT, mapped_axis);
- break;
- }
- }
- } break;
-
- // To-do: GunCon
- // case SDL_MOUSEMOTION: {
- // psx_pad_analog_change(screen->pad, 0, PSXI_AX_GUNCON_SX, psx_get_dmode_width(screen->psx));
- // psx_pad_analog_change(screen->pad, 0, PSXI_AX_GUNCON_SY, psx_get_dmode_height(screen->psx));
- // psx_pad_analog_change(screen->pad, 0, PSXI_AX_GUNCON_X, event.motion.x * (1.0f / (float)screen->scale));
- // psx_pad_analog_change(screen->pad, 0, PSXI_AX_GUNCON_Y, event.motion.y * (1.0f / (float)screen->scale));
- // } break;
-
- // case SDL_MOUSEBUTTONDOWN: {
- // switch (event.button.button) {
- // case SDL_BUTTON_LEFT: {
- // psx_pad_button_press(screen->pad, 0, PSXI_SW_GUNCON_A);
- // } break;
-
- // case SDL_BUTTON_RIGHT: {
- // psx_pad_button_press(screen->pad, 0, PSXI_SW_GUNCON_B);
- // } break;
-
- // case SDL_BUTTON_MIDDLE: {
- // psx_pad_button_press(screen->pad, 0, PSXI_SW_GUNCON_TRIGGER);
- // } break;
- // }
- // } break;
-
- // case SDL_MOUSEBUTTONUP: {
- // switch (event.button.button) {
- // case SDL_BUTTON_LEFT: {
- // psx_pad_button_release(screen->pad, 0, PSXI_SW_GUNCON_A);
- // } break;
-
- // case SDL_BUTTON_RIGHT: {
- // psx_pad_button_release(screen->pad, 0, PSXI_SW_GUNCON_B);
- // } break;
-
- // case SDL_BUTTON_MIDDLE: {
- // psx_pad_button_release(screen->pad, 0, PSXI_SW_GUNCON_TRIGGER);
- // } break;
- // }
- // } break;
-
- case SDL_TEXTINPUT: {
- psx_exp2_atcons_put(screen->psx->exp2, event.text.text[0]);
- } break;
-
- case SDL_KEYUP: {
- uint32_t mask = screen_get_button(event.key.keysym.sym);
-
- psx_pad_button_release(screen->pad, 0, mask);
- } break;
- }
- }
-}
-
-void psxe_screen_set_scale(psxe_screen_t* screen, unsigned int scale) {
- if (screen->debug_mode) {
- screen->scale = 1;
- } else {
- screen->scale = scale;
- screen->saved_scale = scale;
- }
-}
-
-void psxe_screen_destroy(psxe_screen_t* screen) {
- SDL_DestroyTexture(screen->texture);
- SDL_DestroyRenderer(screen->renderer);
- SDL_DestroyWindow(screen->window);
-
- SDL_Quit();
-
- free(screen);
-}
-
-void psxe_gpu_dmode_event_cb(psx_gpu_t* gpu) {
- psxe_screen_t* screen = gpu->udata[0];
-
- // printf("res=(%u,%u) off=(%u,%u) disp=(%u,%u-%u,%u) draw=(%u,%u-%u,%u) vres=%u\n",
- // screen->texture_width,
- // screen->texture_height,
- // screen->psx->gpu->disp_x,
- // screen->psx->gpu->disp_y,
- // screen->psx->gpu->disp_x1,
- // screen->psx->gpu->disp_y1,
- // screen->psx->gpu->disp_x2,
- // screen->psx->gpu->disp_y2,
- // screen->psx->gpu->draw_x1,
- // screen->psx->gpu->draw_y1,
- // screen->psx->gpu->draw_x2,
- // screen->psx->gpu->draw_y2,
- // screen->psx->gpu->disp_y2 - screen->psx->gpu->disp_y1
- // );
-
- screen->format = psx_get_display_format(screen->psx) ?
- SDL_PIXELFORMAT_RGB24 : SDL_PIXELFORMAT_BGR555;
-
- if (screen->debug_mode) {
- screen->width = PSX_GPU_FB_WIDTH;
- screen->height = PSX_GPU_FB_HEIGHT;
- screen->texture_width = PSX_GPU_FB_WIDTH;
- screen->texture_height = PSX_GPU_FB_HEIGHT;
- } else {
- if (screen->fullscreen) {
- SDL_DisplayMode dm;
- SDL_GetCurrentDisplayMode(0, &dm);
-
- screen->width = dm.w;
- screen->height = dm.h;
-
- if (screen->vertical_mode) {
- screen->image_width = screen->height;
- screen->image_height = (double)screen->height / psx_get_display_aspect(screen->psx);
-
- int off = (screen->image_width - screen->image_height) / 2;
-
- screen->image_xoff = (screen->width / 2) - (screen->image_width / 2);
- screen->image_yoff = off;
- } else {
- screen->image_width = (double)screen->height * psx_get_display_aspect(screen->psx);
- screen->image_height = screen->height;
- screen->image_xoff = (screen->width / 2) - (screen->image_width / 2);
- screen->image_yoff = 0;
- }
- } else {
- if (screen->vertical_mode) {
- screen->width = 240 * screen->scale;
- screen->height = screen_get_base_width(screen) * screen->scale;
- screen->image_width = screen->height;
- screen->image_height = screen->width;
-
- int off = (screen->image_width - screen->image_height) / 2;
-
- screen->image_xoff = -off;
- screen->image_yoff = off;
- } else {
- screen->width = screen_get_base_width(screen) * screen->scale;
- screen->height = 240 * screen->scale;
- screen->image_width = screen->width;
- screen->image_height = screen->height;
- screen->image_xoff = 0;
- screen->image_yoff = 0;
- }
- }
-
- screen->texture_width = psx_get_display_width(screen->psx);
- screen->texture_height = psx_get_display_height(screen->psx);
- }
-
- SDL_DestroyTexture(screen->texture);
-
- screen->texture = SDL_CreateTexture(
- screen->renderer,
- screen->format,
- SDL_TEXTUREACCESS_STREAMING,
- screen->texture_width, screen->texture_height
- );
-
-#if SDL_VERSION_ATLEAST(2, 0, 12)
- SDL_SetTextureScaleMode(screen->texture, screen->bilinear);
-#endif
-
- SDL_SetWindowSize(screen->window, screen->width, screen->height);
-}
-
-void psxe_gpu_vblank_event_cb(psx_gpu_t* gpu) {
- psxe_screen_t* screen = gpu->udata[0];
-
- psxe_screen_update(screen);
-
- psxe_gpu_vblank_timer_event_cb(gpu);
+#include "screen.h"
+
+#include "input/sda.h"
+#include "input/guncon.h"
+
+uint32_t screen_get_button(SDL_Keycode k) {+ if (k == SDLK_x ) return PSXI_SW_SDA_CROSS;
+ if (k == SDLK_a ) return PSXI_SW_SDA_SQUARE;
+ if (k == SDLK_w ) return PSXI_SW_SDA_TRIANGLE;
+ if (k == SDLK_d ) return PSXI_SW_SDA_CIRCLE;
+ if (k == SDLK_RETURN) return PSXI_SW_SDA_START;
+ if (k == SDLK_s ) return PSXI_SW_SDA_SELECT;
+ if (k == SDLK_UP ) return PSXI_SW_SDA_PAD_UP;
+ if (k == SDLK_DOWN ) return PSXI_SW_SDA_PAD_DOWN;
+ if (k == SDLK_LEFT ) return PSXI_SW_SDA_PAD_LEFT;
+ if (k == SDLK_RIGHT ) return PSXI_SW_SDA_PAD_RIGHT;
+ if (k == SDLK_q ) return PSXI_SW_SDA_L1;
+ if (k == SDLK_e ) return PSXI_SW_SDA_R1;
+ if (k == SDLK_1 ) return PSXI_SW_SDA_L2;
+ if (k == SDLK_3 ) return PSXI_SW_SDA_R2;
+ if (k == SDLK_z ) return PSXI_SW_SDA_L3;
+ if (k == SDLK_c ) return PSXI_SW_SDA_R3;
+ if (k == SDLK_2 ) return PSXI_SW_SDA_ANALOG;
+
+ return 0;
+}
+
+uint32_t screen_get_button_joystick(uint8_t b) {+ if (b == SDL_CONTROLLER_BUTTON_A ) return PSXI_SW_SDA_CROSS;
+ if (b == SDL_CONTROLLER_BUTTON_X ) return PSXI_SW_SDA_SQUARE;
+ if (b == SDL_CONTROLLER_BUTTON_Y ) return PSXI_SW_SDA_TRIANGLE;
+ if (b == SDL_CONTROLLER_BUTTON_B ) return PSXI_SW_SDA_CIRCLE;
+ if (b == SDL_CONTROLLER_BUTTON_START ) return PSXI_SW_SDA_START;
+ if (b == SDL_CONTROLLER_BUTTON_GUIDE ) return PSXI_SW_SDA_SELECT;
+ if (b == SDL_CONTROLLER_BUTTON_DPAD_UP ) return PSXI_SW_SDA_PAD_UP;
+ if (b == SDL_CONTROLLER_BUTTON_DPAD_DOWN ) return PSXI_SW_SDA_PAD_DOWN;
+ if (b == SDL_CONTROLLER_BUTTON_DPAD_LEFT ) return PSXI_SW_SDA_PAD_LEFT;
+ if (b == SDL_CONTROLLER_BUTTON_DPAD_RIGHT ) return PSXI_SW_SDA_PAD_RIGHT;
+ if (b == SDL_CONTROLLER_BUTTON_LEFTSHOULDER ) return PSXI_SW_SDA_L1;
+ if (b == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) return PSXI_SW_SDA_R1;
+ if (b == SDL_CONTROLLER_AXIS_TRIGGERLEFT ) return PSXI_SW_SDA_L2; // Can't map these yet
+ if (b == SDL_CONTROLLER_AXIS_TRIGGERRIGHT ) return PSXI_SW_SDA_R2; // Can't map these yet
+ if (b == SDL_CONTROLLER_BUTTON_LEFTSTICK ) return PSXI_SW_SDA_L3;
+ if (b == SDL_CONTROLLER_BUTTON_RIGHTSTICK ) return PSXI_SW_SDA_R3;
+
+ return 0;
+}
+
+SDL_GameController* screen_find_controller(void) {+ for (int i = 0; i < SDL_NumJoysticks(); i++)
+ if (SDL_IsGameController(i))
+ return SDL_GameControllerOpen(i);
+
+ return NULL;
+}
+
+int screen_get_base_width(psxe_screen_t* screen) {+ int width = psx_get_dmode_width(screen->psx);
+
+ switch (width) {+ case 256: return 256;
+ case 320: return 320;
+ case 368: return 384;
+ }
+
+ return 320;
+}
+
+psxe_screen_t* psxe_screen_create(void) {+ return (psxe_screen_t*)malloc(sizeof(psxe_screen_t));
+}
+
+void psxe_screen_init(psxe_screen_t* screen, psx_t* psx) {+ memset(screen, 0, sizeof(psxe_screen_t));
+
+ if (screen->debug_mode) {+ screen->width = PSX_GPU_FB_WIDTH;
+ screen->height = PSX_GPU_FB_HEIGHT;
+ } else {+ screen->width = 320;
+ screen->height = 240;
+ }
+
+ screen->scale = 1;
+ screen->open = 1;
+ screen->format = SDL_PIXELFORMAT_BGR555;
+ screen->psx = psx;
+ screen->pad = psx_get_pad(psx);
+
+ screen->texture_width = PSX_GPU_FB_WIDTH;
+ screen->texture_height = PSX_GPU_FB_HEIGHT;
+
+ SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_GAMECONTROLLER);
+ SDL_SetRenderDrawColor(screen->renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
+
+ screen->controller = screen_find_controller();
+}
+
+void psxe_screen_reload(psxe_screen_t* screen) {+ if (screen->texture) SDL_DestroyTexture(screen->texture);
+ if (screen->renderer) SDL_DestroyRenderer(screen->renderer);
+ if (screen->window) SDL_DestroyWindow(screen->window);
+
+ if (screen->debug_mode) {+ screen->width = PSX_GPU_FB_WIDTH;
+ screen->height = PSX_GPU_FB_HEIGHT;
+ } else {+ if (screen->vertical_mode) {+ screen->width = 240;
+ screen->height = screen_get_base_width(screen);
+ } else {+ screen->width = screen_get_base_width(screen);
+ screen->height = 240;
+ }
+ }
+
+ screen->window = SDL_CreateWindow(
+ "psxe " STR(REP_VERSION) "-" STR(REP_COMMIT_HASH),
+ SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
+ screen->width * screen->scale,
+ screen->height * screen->scale,
+ 0
+ );
+
+ screen->renderer = SDL_CreateRenderer(
+ screen->window,
+ -1,
+ SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC
+ );
+
+ screen->texture = SDL_CreateTexture(
+ screen->renderer,
+ screen->format,
+ SDL_TEXTUREACCESS_STREAMING,
+ screen->texture_width, screen->texture_height
+ );
+
+#if SDL_VERSION_ATLEAST(2, 0, 12)
+ SDL_SetTextureScaleMode(screen->texture, screen->bilinear);
+#endif
+
+ // Check for retina displays
+ int width = 0, height = 0;
+
+ SDL_GetRendererOutputSize(screen->renderer, &width, &height);
+
+ if (width != (screen->width * screen->scale)) {+ float width_scale = (float)width / (float)(screen->width * screen->scale);
+ float height_scale = (float)height / (float)(screen->height * screen->scale);
+
+ SDL_RenderSetScale(screen->renderer, width_scale, height_scale);
+ }
+
+ screen->open = 1;
+}
+
+int psxe_screen_is_open(psxe_screen_t* screen) {+ return screen->open;
+}
+
+void psxe_screen_toggle_debug_mode(psxe_screen_t* screen) {+ screen->debug_mode = !screen->debug_mode;
+
+ psxe_screen_set_scale(screen, screen->saved_scale);
+
+ screen->texture_width = PSX_GPU_FB_WIDTH;
+ screen->texture_height = PSX_GPU_FB_HEIGHT;
+
+ psxe_gpu_dmode_event_cb(screen->psx->gpu);
+}
+
+// int frame = 0;
+
+void psxe_screen_update(psxe_screen_t* screen) {+ void* display_buf = screen->debug_mode ?
+ psx_get_vram(screen->psx) : psx_get_display_buffer(screen->psx);
+
+ // printf("res=(%u,%u) off=(%u,%u) disp=(%u,%u-%u,%u) draw=(%u,%u-%u,%u) vres=%u\n",+ // screen->texture_width,
+ // screen->texture_height,
+ // screen->psx->gpu->disp_x,
+ // screen->psx->gpu->disp_y,
+ // screen->psx->gpu->disp_x1,
+ // screen->psx->gpu->disp_y1,
+ // screen->psx->gpu->disp_x2,
+ // screen->psx->gpu->disp_y2,
+ // screen->psx->gpu->draw_x1,
+ // screen->psx->gpu->draw_y1,
+ // screen->psx->gpu->draw_x2,
+ // screen->psx->gpu->draw_y2,
+ // screen->psx->gpu->disp_y2 - screen->psx->gpu->disp_y1
+ // );
+
+ if ((screen->psx->gpu->disp_y + screen->texture_height) > 512)
+ display_buf = psx_get_vram(screen->psx);
+
+ SDL_UpdateTexture(screen->texture, NULL, display_buf, PSX_GPU_FB_STRIDE);
+ SDL_RenderClear(screen->renderer);
+
+ if (!screen->debug_mode) {+ SDL_Rect dstrect;
+
+ dstrect.x = screen->image_xoff;
+ dstrect.y = screen->image_yoff;
+ dstrect.w = screen->image_width;
+ dstrect.h = screen->image_height;
+
+ SDL_RenderCopyEx(
+ screen->renderer,
+ screen->texture,
+ NULL, &dstrect,
+ screen->vertical_mode ? 270 : 0,
+ NULL, SDL_FLIP_NONE
+ );
+ } else {+ SDL_RenderCopy(screen->renderer, screen->texture, NULL, NULL);
+ }
+
+ SDL_RenderPresent(screen->renderer);
+
+ SDL_Event event;
+
+ while (SDL_PollEvent(&event)) {+ switch (event.type) {+ case SDL_QUIT: {+ screen->open = 0;
+ } break;
+
+ case SDL_KEYDOWN: {+ switch (event.key.keysym.sym) {+ case SDLK_F1: {+ psxe_screen_toggle_debug_mode(screen);
+
+ return;
+ } break;
+
+ case SDLK_F2: {+ SDL_Surface* surface = SDL_CreateRGBSurfaceWithFormat(
+ 0,
+ screen->width,
+ screen->height,
+ 16,
+ SDL_PIXELFORMAT_BGR555
+ );
+
+ SDL_RenderReadPixels(
+ screen->renderer,
+ NULL,
+ SDL_PIXELFORMAT_BGR555,
+ surface->pixels, surface->pitch
+ );
+
+ SDL_SaveBMP(surface, "snap/screenshot.bmp");
+
+ SDL_FreeSurface(surface);
+ } break;
+
+ case SDLK_F3: {+ screen->vertical_mode = !screen->vertical_mode;
+
+ psxe_gpu_dmode_event_cb(screen->psx->gpu);
+ } break;
+
+ case SDLK_F4: {+ screen->bilinear = !screen->bilinear;
+
+ psxe_gpu_dmode_event_cb(screen->psx->gpu);
+ } break;
+
+ case SDLK_F11: {+ screen->fullscreen = !screen->fullscreen;
+
+ SDL_SetWindowFullscreen(
+ screen->window,
+ screen->fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0
+ );
+
+ psxe_gpu_dmode_event_cb(screen->psx->gpu);
+
+ SDL_SetRenderDrawColor(screen->renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
+ SDL_RenderClear(screen->renderer);
+ } break;
+
+ case SDLK_F5: {+ psx_soft_reset(screen->psx);
+ } break;
+
+ case SDLK_F6: {+ psx_swap_disc(screen->psx, ".\\roms\\Street Fighter II Movie (Japan) (Disc 2)\\Street Fighter II Movie (Japan) (Disc 2).cue");
+ } break;
+ }
+
+ uint32_t mask = screen_get_button(event.key.keysym.sym);
+
+ psx_pad_button_press(screen->pad, 0, mask);
+
+ if (event.key.keysym.sym == SDLK_RETURN)
+ psx_exp2_atcons_put(screen->psx->exp2, 13);
+ } break;
+
+ case SDL_CONTROLLERDEVICEADDED: {+ if (!screen->controller)
+ screen->controller = SDL_GameControllerOpen(event.cdevice.which);
+ } break;
+
+ case SDL_CONTROLLERDEVICEREMOVED: {+ SDL_Joystick* joy = SDL_GameControllerGetJoystick(screen->controller);
+ SDL_JoystickID id = SDL_JoystickInstanceID(joy);
+
+ if (screen->controller && (event.cdevice.which == id)) {+ SDL_GameControllerClose(screen->controller);
+
+ screen->controller = screen_find_controller();
+ }
+ } break;
+
+ case SDL_CONTROLLERBUTTONDOWN: {+ SDL_Joystick* joy = SDL_GameControllerGetJoystick(screen->controller);
+ SDL_JoystickID id = SDL_JoystickInstanceID(joy);
+
+ if (screen->controller && (event.cdevice.which == id)) {+ uint32_t mask = screen_get_button_joystick(event.cbutton.button);
+
+ psx_pad_button_press(screen->pad, 0, mask);
+ }
+ } break;
+
+ case SDL_CONTROLLERBUTTONUP: {+ SDL_Joystick* joy = SDL_GameControllerGetJoystick(screen->controller);
+ SDL_JoystickID id = SDL_JoystickInstanceID(joy);
+
+ if (screen->controller && (event.cdevice.which == id)) {+ uint32_t mask = screen_get_button_joystick(event.cbutton.button);
+
+ psx_pad_button_release(screen->pad, 0, mask);
+ }
+ } break;
+
+ case SDL_CONTROLLERAXISMOTION: {+ SDL_Joystick* joy = SDL_GameControllerGetJoystick(screen->controller);
+ SDL_JoystickID id = SDL_JoystickInstanceID(joy);
+
+ if (screen->controller && (event.cdevice.which == id)) {+ int mapped_axis = ((int)event.caxis.value + INT16_MAX + 1) / 0x100;
+
+ switch (event.caxis.axis) {+ case SDL_CONTROLLER_AXIS_RIGHTX:
+ psx_pad_analog_change(screen->pad, 0, PSXI_AX_SDA_RIGHT_HORZ, mapped_axis);
+ break;
+
+ case SDL_CONTROLLER_AXIS_RIGHTY:
+ psx_pad_analog_change(screen->pad, 0, PSXI_AX_SDA_RIGHT_VERT, mapped_axis);
+ break;
+
+ case SDL_CONTROLLER_AXIS_LEFTX:
+ psx_pad_analog_change(screen->pad, 0, PSXI_AX_SDA_LEFT_HORZ, mapped_axis);
+ break;
+
+ case SDL_CONTROLLER_AXIS_LEFTY:
+ psx_pad_analog_change(screen->pad, 0, PSXI_AX_SDA_LEFT_VERT, mapped_axis);
+ break;
+ }
+ }
+ } break;
+
+ // To-do: GunCon
+ // case SDL_MOUSEMOTION: {+ // psx_pad_analog_change(screen->pad, 0, PSXI_AX_GUNCON_SX, psx_get_dmode_width(screen->psx));
+ // psx_pad_analog_change(screen->pad, 0, PSXI_AX_GUNCON_SY, psx_get_dmode_height(screen->psx));
+ // psx_pad_analog_change(screen->pad, 0, PSXI_AX_GUNCON_X, event.motion.x * (1.0f / (float)screen->scale));
+ // psx_pad_analog_change(screen->pad, 0, PSXI_AX_GUNCON_Y, event.motion.y * (1.0f / (float)screen->scale));
+ // } break;
+
+ // case SDL_MOUSEBUTTONDOWN: {+ // switch (event.button.button) {+ // case SDL_BUTTON_LEFT: {+ // psx_pad_button_press(screen->pad, 0, PSXI_SW_GUNCON_A);
+ // } break;
+
+ // case SDL_BUTTON_RIGHT: {+ // psx_pad_button_press(screen->pad, 0, PSXI_SW_GUNCON_B);
+ // } break;
+
+ // case SDL_BUTTON_MIDDLE: {+ // psx_pad_button_press(screen->pad, 0, PSXI_SW_GUNCON_TRIGGER);
+ // } break;
+ // }
+ // } break;
+
+ // case SDL_MOUSEBUTTONUP: {+ // switch (event.button.button) {+ // case SDL_BUTTON_LEFT: {+ // psx_pad_button_release(screen->pad, 0, PSXI_SW_GUNCON_A);
+ // } break;
+
+ // case SDL_BUTTON_RIGHT: {+ // psx_pad_button_release(screen->pad, 0, PSXI_SW_GUNCON_B);
+ // } break;
+
+ // case SDL_BUTTON_MIDDLE: {+ // psx_pad_button_release(screen->pad, 0, PSXI_SW_GUNCON_TRIGGER);
+ // } break;
+ // }
+ // } break;
+
+ case SDL_TEXTINPUT: {+ psx_exp2_atcons_put(screen->psx->exp2, event.text.text[0]);
+ } break;
+
+ case SDL_KEYUP: {+ uint32_t mask = screen_get_button(event.key.keysym.sym);
+
+ psx_pad_button_release(screen->pad, 0, mask);
+ } break;
+ }
+ }
+}
+
+void psxe_screen_set_scale(psxe_screen_t* screen, unsigned int scale) {+ if (screen->debug_mode) {+ screen->scale = 1;
+ } else {+ screen->scale = scale;
+ screen->saved_scale = scale;
+ }
+}
+
+void psxe_screen_destroy(psxe_screen_t* screen) {+ SDL_DestroyTexture(screen->texture);
+ SDL_DestroyRenderer(screen->renderer);
+ SDL_DestroyWindow(screen->window);
+
+ SDL_Quit();
+
+ free(screen);
+}
+
+void psxe_gpu_dmode_event_cb(psx_gpu_t* gpu) {+ psxe_screen_t* screen = gpu->udata[0];
+
+ // printf("res=(%u,%u) off=(%u,%u) disp=(%u,%u-%u,%u) draw=(%u,%u-%u,%u) vres=%u\n",+ // screen->texture_width,
+ // screen->texture_height,
+ // screen->psx->gpu->disp_x,
+ // screen->psx->gpu->disp_y,
+ // screen->psx->gpu->disp_x1,
+ // screen->psx->gpu->disp_y1,
+ // screen->psx->gpu->disp_x2,
+ // screen->psx->gpu->disp_y2,
+ // screen->psx->gpu->draw_x1,
+ // screen->psx->gpu->draw_y1,
+ // screen->psx->gpu->draw_x2,
+ // screen->psx->gpu->draw_y2,
+ // screen->psx->gpu->disp_y2 - screen->psx->gpu->disp_y1
+ // );
+
+ screen->format = psx_get_display_format(screen->psx) ?
+ SDL_PIXELFORMAT_RGB24 : SDL_PIXELFORMAT_BGR555;
+
+ if (screen->debug_mode) {+ screen->width = PSX_GPU_FB_WIDTH;
+ screen->height = PSX_GPU_FB_HEIGHT;
+ screen->texture_width = PSX_GPU_FB_WIDTH;
+ screen->texture_height = PSX_GPU_FB_HEIGHT;
+ } else {+ if (screen->fullscreen) {+ SDL_DisplayMode dm;
+ SDL_GetCurrentDisplayMode(0, &dm);
+
+ screen->width = dm.w;
+ screen->height = dm.h;
+
+ if (screen->vertical_mode) {+ screen->image_width = screen->height;
+ screen->image_height = (double)screen->height / psx_get_display_aspect(screen->psx);
+
+ int off = (screen->image_width - screen->image_height) / 2;
+
+ screen->image_xoff = (screen->width / 2) - (screen->image_width / 2);
+ screen->image_yoff = off;
+ } else {+ screen->image_width = (double)screen->height * psx_get_display_aspect(screen->psx);
+ screen->image_height = screen->height;
+ screen->image_xoff = (screen->width / 2) - (screen->image_width / 2);
+ screen->image_yoff = 0;
+ }
+ } else {+ if (screen->vertical_mode) {+ screen->width = 240 * screen->scale;
+ screen->height = screen_get_base_width(screen) * screen->scale;
+ screen->image_width = screen->height;
+ screen->image_height = screen->width;
+
+ int off = (screen->image_width - screen->image_height) / 2;
+
+ screen->image_xoff = -off;
+ screen->image_yoff = off;
+ } else {+ screen->width = screen_get_base_width(screen) * screen->scale;
+ screen->height = 240 * screen->scale;
+ screen->image_width = screen->width;
+ screen->image_height = screen->height;
+ screen->image_xoff = 0;
+ screen->image_yoff = 0;
+ }
+ }
+
+ screen->texture_width = psx_get_display_width(screen->psx);
+ screen->texture_height = psx_get_display_height(screen->psx);
+ }
+
+ SDL_DestroyTexture(screen->texture);
+
+ screen->texture = SDL_CreateTexture(
+ screen->renderer,
+ screen->format,
+ SDL_TEXTUREACCESS_STREAMING,
+ screen->texture_width, screen->texture_height
+ );
+
+#if SDL_VERSION_ATLEAST(2, 0, 12)
+ SDL_SetTextureScaleMode(screen->texture, screen->bilinear);
+#endif
+
+ SDL_SetWindowSize(screen->window, screen->width, screen->height);
+}
+
+void psxe_gpu_vblank_event_cb(psx_gpu_t* gpu) {+ psxe_screen_t* screen = gpu->udata[0];
+
+ psxe_screen_update(screen);
+
+ psxe_gpu_vblank_timer_event_cb(gpu);
}
\ No newline at end of file
--- a/frontend/screen.h
+++ b/frontend/screen.h
@@ -1,50 +1,50 @@
-#ifndef SCREEN_H
-#define SCREEN_H
-
-#include "../psx/psx.h"
-#include "common.h"
-
-#include <string.h>
-
-#include "SDL.h"
-#include "SDL_version.h"
-#include "SDL_gamecontroller.h"
-
-typedef struct {
- SDL_Window* window;
- SDL_Renderer* renderer;
- SDL_Texture* texture;
-
- psx_t* psx;
- psx_pad_t* pad;
-
- unsigned int saved_scale;
- unsigned int width, height, scale;
- unsigned int image_width, image_height;
- unsigned int image_xoff, image_yoff;
- unsigned int format;
- unsigned int texture_width, texture_height;
-
- int bilinear;
- int fullscreen;
- int vertical_mode;
- int debug_mode;
- int open;
-
- SDL_GameController* controller;
-} psxe_screen_t;
-
-psxe_screen_t* psxe_screen_create(void);
-void psxe_screen_init(psxe_screen_t*, psx_t*);
-void psxe_screen_reload(psxe_screen_t*);
-int psxe_screen_is_open(psxe_screen_t*);
-void psxe_screen_update(psxe_screen_t*);
-void psxe_screen_destroy(psxe_screen_t*);
-void psxe_screen_set_scale(psxe_screen_t*, unsigned int);
-void psxe_screen_toggle_debug_mode(psxe_screen_t*);
-
-// GPU event handlers
-void psxe_gpu_dmode_event_cb(psx_gpu_t*);
-void psxe_gpu_vblank_event_cb(psx_gpu_t*);
-
+#ifndef SCREEN_H
+#define SCREEN_H
+
+#include "../psx/psx.h"
+#include "common.h"
+
+#include <string.h>
+
+#include "SDL.h"
+#include "SDL_version.h"
+#include "SDL_gamecontroller.h"
+
+typedef struct {+ SDL_Window* window;
+ SDL_Renderer* renderer;
+ SDL_Texture* texture;
+
+ psx_t* psx;
+ psx_pad_t* pad;
+
+ unsigned int saved_scale;
+ unsigned int width, height, scale;
+ unsigned int image_width, image_height;
+ unsigned int image_xoff, image_yoff;
+ unsigned int format;
+ unsigned int texture_width, texture_height;
+
+ int bilinear;
+ int fullscreen;
+ int vertical_mode;
+ int debug_mode;
+ int open;
+
+ SDL_GameController* controller;
+} psxe_screen_t;
+
+psxe_screen_t* psxe_screen_create(void);
+void psxe_screen_init(psxe_screen_t*, psx_t*);
+void psxe_screen_reload(psxe_screen_t*);
+int psxe_screen_is_open(psxe_screen_t*);
+void psxe_screen_update(psxe_screen_t*);
+void psxe_screen_destroy(psxe_screen_t*);
+void psxe_screen_set_scale(psxe_screen_t*, unsigned int);
+void psxe_screen_toggle_debug_mode(psxe_screen_t*);
+
+// GPU event handlers
+void psxe_gpu_dmode_event_cb(psx_gpu_t*);
+void psxe_gpu_vblank_event_cb(psx_gpu_t*);
+
#endif
\ No newline at end of file
--- a/mkfile
+++ b/mkfile
@@ -3,6 +3,8 @@
BIN=/$objtype/bin/games
TARG=psxe
CFLAGS=$CFLAGS -I. -Ipsx
+# 9front: suppress object type-signature conflicts during link.
+LD=6l -S
HFILES=\
dat.h\
--- a/psx/bus.c
+++ b/psx/bus.c
@@ -45,7 +45,7 @@
void psx_mdec_write32(psx_mdec_t*, uint32_t, uint32_t);
void psx_mdec_write16(psx_mdec_t*, uint32_t, uint16_t);
void psx_mdec_write8(psx_mdec_t*, uint32_t, uint8_t);
-
+
#define RANGE(v, s, e) ((v >= s) && (v < e))
typedef struct psx_bus_iomap_t {@@ -71,25 +71,25 @@
return 1;
}
-
-const uint32_t g_psx_bus_region_mask_table[] = {
- 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
- 0x7fffffff, 0x1fffffff, 0xffffffff, 0xffffffff
-};
-
-psx_bus_t* psx_bus_create(void) {
- return (psx_bus_t*)malloc(sizeof(psx_bus_t));
-}
-
+
+const uint32_t g_psx_bus_region_mask_table[] = {+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x7fffffff, 0x1fffffff, 0xffffffff, 0xffffffff
+};
+
+psx_bus_t* psx_bus_create(void) {+ return (psx_bus_t*)malloc(sizeof(psx_bus_t));
+}
+
// Does nothing for now
void psx_bus_init(psx_bus_t* bus) {USED(bus);
}
-
-void psx_bus_destroy(psx_bus_t* bus) {
- free(bus);
-}
-
+
+void psx_bus_destroy(psx_bus_t* bus) {+ free(bus);
+}
+
#define HANDLE_READ_OP(dev, fn) do { \uint32_t off, cyc; \
if (bus_probe(bus->dev, addr, &off, &cyc)) { \@@ -105,16 +105,16 @@
return; \
} \
} while (0)
-
-uint32_t psx_bus_read32(psx_bus_t* bus, uint32_t addr) {
- uint32_t vaddr = addr;
-
- addr &= g_psx_bus_region_mask_table[addr >> 29];
-
- if (addr & 0x3) {
- log_fatal("Unaligned 32-bit read from %08x:%08x", vaddr, addr);
- }
-
+
+uint32_t psx_bus_read32(psx_bus_t* bus, uint32_t addr) {+ uint32_t vaddr = addr;
+
+ addr &= g_psx_bus_region_mask_table[addr >> 29];
+
+ if (addr & 0x3) {+ log_fatal("Unaligned 32-bit read from %08x:%08x", vaddr, addr);+ }
+
HANDLE_READ_OP(bios, psx_bios_read32);
HANDLE_READ_OP(ram, psx_ram_read32);
HANDLE_READ_OP(dma, psx_dma_read32);
@@ -131,27 +131,27 @@
HANDLE_READ_OP(cdrom, psx_cdrom_read32);
HANDLE_READ_OP(pad, psx_pad_read32);
HANDLE_READ_OP(mdec, psx_mdec_read32);
-
- log_fatal("Unhandled 32-bit read from %08x:%08x", vaddr, addr);
-
- //exit(1);
-
- return 0x00000000;
-}
-
-static uint16_t sio_ctrl;
-
-uint16_t psx_bus_read16(psx_bus_t* bus, uint32_t addr) {
- bus->access_cycles = 2;
-
- uint32_t vaddr = addr;
-
- addr &= g_psx_bus_region_mask_table[addr >> 29];
-
- if (addr & 0x1) {
- log_fatal("Unaligned 16-bit read from %08x:%08x", vaddr, addr);
- }
-
+
+ log_fatal("Unhandled 32-bit read from %08x:%08x", vaddr, addr);+
+ //exit(1);
+
+ return 0x00000000;
+}
+
+static uint16_t sio_ctrl;
+
+uint16_t psx_bus_read16(psx_bus_t* bus, uint32_t addr) {+ bus->access_cycles = 2;
+
+ uint32_t vaddr = addr;
+
+ addr &= g_psx_bus_region_mask_table[addr >> 29];
+
+ if (addr & 0x1) {+ log_fatal("Unaligned 16-bit read from %08x:%08x", vaddr, addr);+ }
+
HANDLE_READ_OP(bios, psx_bios_read16);
HANDLE_READ_OP(ram, psx_ram_read16);
HANDLE_READ_OP(dma, psx_dma_read16);
@@ -168,33 +168,33 @@
HANDLE_READ_OP(cdrom, psx_cdrom_read16);
HANDLE_READ_OP(pad, psx_pad_read16);
HANDLE_READ_OP(mdec, psx_mdec_read16);
-
- if (addr == 0x1f80105a)
- return sio_ctrl;
-
- if (addr == 0x1f801054)
- return 0x05;
-
- if (addr == 0x1f400004)
- return 0xc8;
-
- if (addr == 0x1f400006)
- return 0x1fe0;
-
+
+ if (addr == 0x1f80105a)
+ return sio_ctrl;
+
+ if (addr == 0x1f801054)
+ return 0x05;
+
+ if (addr == 0x1f400004)
+ return 0xc8;
+
+ if (addr == 0x1f400006)
+ return 0x1fe0;
+
print("Unhandled 16-bit read from %08x:%08x\n", vaddr, addr);-
- // exit(1);
-
- return 0x0000;
-}
-
-uint8_t psx_bus_read8(psx_bus_t* bus, uint32_t addr) {
- bus->access_cycles = 2;
-
- // uint32_t vaddr = addr;
-
- addr &= g_psx_bus_region_mask_table[addr >> 29];
-
+
+ // exit(1);
+
+ return 0x0000;
+}
+
+uint8_t psx_bus_read8(psx_bus_t* bus, uint32_t addr) {+ bus->access_cycles = 2;
+
+ // uint32_t vaddr = addr;
+
+ addr &= g_psx_bus_region_mask_table[addr >> 29];
+
HANDLE_READ_OP(bios, psx_bios_read8);
HANDLE_READ_OP(ram, psx_ram_read8);
HANDLE_READ_OP(dma, psx_dma_read8);
@@ -211,25 +211,25 @@
HANDLE_READ_OP(cdrom, psx_cdrom_read8);
HANDLE_READ_OP(pad, psx_pad_read8);
HANDLE_READ_OP(mdec, psx_mdec_read8);
-
- // printf("Unhandled 8-bit read from %08x:%08x\n", vaddr, addr);
-
- //exit(1);
-
- return 0x00;
-}
-
-void psx_bus_write32(psx_bus_t* bus, uint32_t addr, uint32_t value) {
- bus->access_cycles = 0;
-
- uint32_t vaddr = addr;
-
- addr &= g_psx_bus_region_mask_table[addr >> 29];
-
- if (addr & 0x3) {
- log_fatal("Unaligned 32-bit write to %08x:%08x (%08x)", vaddr, addr, value);
- }
-
+
+ // printf("Unhandled 8-bit read from %08x:%08x\n", vaddr, addr);+
+ //exit(1);
+
+ return 0x00;
+}
+
+void psx_bus_write32(psx_bus_t* bus, uint32_t addr, uint32_t value) {+ bus->access_cycles = 0;
+
+ uint32_t vaddr = addr;
+
+ addr &= g_psx_bus_region_mask_table[addr >> 29];
+
+ if (addr & 0x3) {+ log_fatal("Unaligned 32-bit write to %08x:%08x (%08x)", vaddr, addr, value);+ }
+
HANDLE_WRITE_OP(bios, psx_bios_write32);
HANDLE_WRITE_OP(ram, psx_ram_write32);
HANDLE_WRITE_OP(dma, psx_dma_write32);
@@ -246,24 +246,24 @@
HANDLE_WRITE_OP(cdrom, psx_cdrom_write32);
HANDLE_WRITE_OP(pad, psx_pad_write32);
HANDLE_WRITE_OP(mdec, psx_mdec_write32);
-
+
print("Unhandled 32-bit write to %08x:%08x (%08x)\n", vaddr, addr, value);-
- //exit(1);
-}
-
-
-void psx_bus_write16(psx_bus_t* bus, uint32_t addr, uint32_t value) {
- bus->access_cycles = 0;
-
- uint32_t vaddr = addr;
-
- addr &= g_psx_bus_region_mask_table[addr >> 29];
-
- if (addr & 0x1) {
- log_fatal("Unaligned 16-bit write to %08x:%08x (%04x)", vaddr, addr, value);
- }
-
+
+ //exit(1);
+}
+
+
+void psx_bus_write16(psx_bus_t* bus, uint32_t addr, uint32_t value) {+ bus->access_cycles = 0;
+
+ uint32_t vaddr = addr;
+
+ addr &= g_psx_bus_region_mask_table[addr >> 29];
+
+ if (addr & 0x1) {+ log_fatal("Unaligned 16-bit write to %08x:%08x (%04x)", vaddr, addr, value);+ }
+
HANDLE_WRITE_OP(bios, psx_bios_write16);
HANDLE_WRITE_OP(ram, psx_ram_write16);
HANDLE_WRITE_OP(dma, psx_dma_write16);
@@ -280,21 +280,21 @@
HANDLE_WRITE_OP(cdrom, psx_cdrom_write16);
HANDLE_WRITE_OP(pad, psx_pad_write16);
HANDLE_WRITE_OP(mdec, psx_mdec_write16);
-
- // if (addr == 0x1f80105a) { sio_ctrl = value; return; }
-
+
+ // if (addr == 0x1f80105a) { sio_ctrl = value; return; }+
print("Unhandled 16-bit write to %08x:%08x (%04x)\n", vaddr, addr, value);-
- //exit(1);
-}
-
-void psx_bus_write8(psx_bus_t* bus, uint32_t addr, uint32_t value) {
- bus->access_cycles = 0;
-
- uint32_t vaddr = addr;
-
- addr &= g_psx_bus_region_mask_table[addr >> 29];
-
+
+ //exit(1);
+}
+
+void psx_bus_write8(psx_bus_t* bus, uint32_t addr, uint32_t value) {+ bus->access_cycles = 0;
+
+ uint32_t vaddr = addr;
+
+ addr &= g_psx_bus_region_mask_table[addr >> 29];
+
HANDLE_WRITE_OP(bios, psx_bios_write8);
HANDLE_WRITE_OP(ram, psx_ram_write8);
HANDLE_WRITE_OP(dma, psx_dma_write8);
@@ -311,83 +311,83 @@
HANDLE_WRITE_OP(cdrom, psx_cdrom_write8);
HANDLE_WRITE_OP(pad, psx_pad_write8);
HANDLE_WRITE_OP(mdec, psx_mdec_write8);
-
+
print("Unhandled 8-bit write to %08x:%08x (%02x)\n", vaddr, addr, value);-
- //exit(1);
-}
-
-void psx_bus_init_bios(psx_bus_t* bus, psx_bios_t* bios) {
- bus->bios = bios;
-}
-
-void psx_bus_init_ram(psx_bus_t* bus, psx_ram_t* ram) {
- bus->ram = ram;
-}
-
-void psx_bus_init_dma(psx_bus_t* bus, psx_dma_t* dma) {
- bus->dma = dma;
-}
-
-void psx_bus_init_exp1(psx_bus_t* bus, psx_exp1_t* exp1) {
- bus->exp1 = exp1;
-}
-
-void psx_bus_init_exp2(psx_bus_t* bus, psx_exp2_t* exp2) {
- bus->exp2 = exp2;
-}
-
-void psx_bus_init_mc1(psx_bus_t* bus, psx_mc1_t* mc1) {
- bus->mc1 = mc1;
-}
-
-void psx_bus_init_mc2(psx_bus_t* bus, psx_mc2_t* mc2) {
- bus->mc2 = mc2;
-}
-
-void psx_bus_init_mc3(psx_bus_t* bus, psx_mc3_t* mc3) {
- bus->mc3 = mc3;
-}
-
-void psx_bus_init_ic(psx_bus_t* bus, psx_ic_t* ic) {
- bus->ic = ic;
-}
-
-void psx_bus_init_scratchpad(psx_bus_t* bus, psx_scratchpad_t* scratchpad) {
- bus->scratchpad = scratchpad;
-}
-
-void psx_bus_init_gpu(psx_bus_t* bus, psx_gpu_t* gpu) {
- bus->gpu = gpu;
-}
-
+
+ //exit(1);
+}
+
+void psx_bus_init_bios(psx_bus_t* bus, psx_bios_t* bios) {+ bus->bios = bios;
+}
+
+void psx_bus_init_ram(psx_bus_t* bus, psx_ram_t* ram) {+ bus->ram = ram;
+}
+
+void psx_bus_init_dma(psx_bus_t* bus, psx_dma_t* dma) {+ bus->dma = dma;
+}
+
+void psx_bus_init_exp1(psx_bus_t* bus, psx_exp1_t* exp1) {+ bus->exp1 = exp1;
+}
+
+void psx_bus_init_exp2(psx_bus_t* bus, psx_exp2_t* exp2) {+ bus->exp2 = exp2;
+}
+
+void psx_bus_init_mc1(psx_bus_t* bus, psx_mc1_t* mc1) {+ bus->mc1 = mc1;
+}
+
+void psx_bus_init_mc2(psx_bus_t* bus, psx_mc2_t* mc2) {+ bus->mc2 = mc2;
+}
+
+void psx_bus_init_mc3(psx_bus_t* bus, psx_mc3_t* mc3) {+ bus->mc3 = mc3;
+}
+
+void psx_bus_init_ic(psx_bus_t* bus, psx_ic_t* ic) {+ bus->ic = ic;
+}
+
+void psx_bus_init_scratchpad(psx_bus_t* bus, psx_scratchpad_t* scratchpad) {+ bus->scratchpad = scratchpad;
+}
+
+void psx_bus_init_gpu(psx_bus_t* bus, psx_gpu_t* gpu) {+ bus->gpu = gpu;
+}
+
void psx_bus_init_spu(psx_bus_t* bus, struct psx_spu_t* spu) {bus->spu = spu;
}
-
+
void psx_bus_init_timer(psx_bus_t* bus, struct psx_timer_t* timer) {bus->timer = timer;
}
-
-void psx_bus_init_cdrom(psx_bus_t* bus, psx_cdrom_t* cdrom) {
- bus->cdrom = cdrom;
-}
-
+
+void psx_bus_init_cdrom(psx_bus_t* bus, psx_cdrom_t* cdrom) {+ bus->cdrom = cdrom;
+}
+
void psx_bus_init_pad(psx_bus_t* bus, struct psx_pad_t* pad) {bus->pad = pad;
}
-
+
void psx_bus_init_mdec(psx_bus_t* bus, struct psx_mdec_t* mdec) {bus->mdec = mdec;
}
-
-uint32_t psx_bus_get_access_cycles(psx_bus_t* bus) {
- uint32_t cycles = bus->access_cycles;
-
- bus->access_cycles = 0;
-
- return cycles;
-}
-
+
+uint32_t psx_bus_get_access_cycles(psx_bus_t* bus) {+ uint32_t cycles = bus->access_cycles;
+
+ bus->access_cycles = 0;
+
+ return cycles;
+}
+
#undef HANDLE_READ_OP
#undef HANDLE_WRITE_OP
--- a/psx/bus.h
+++ b/psx/bus.h
@@ -3,16 +3,16 @@
#include "p9.h"
#include "bus_init.h"
-
-psx_bus_t* psx_bus_create(void);
-void psx_bus_init(psx_bus_t*);
-uint32_t psx_bus_read32(psx_bus_t*, uint32_t);
-uint16_t psx_bus_read16(psx_bus_t*, uint32_t);
-uint8_t psx_bus_read8(psx_bus_t*, uint32_t);
-void psx_bus_write32(psx_bus_t*, uint32_t, uint32_t);
-void psx_bus_write16(psx_bus_t*, uint32_t, uint32_t);
-void psx_bus_write8(psx_bus_t*, uint32_t, uint32_t);
-uint32_t psx_bus_get_access_cycles(psx_bus_t*);
-void psx_bus_destroy(psx_bus_t*);
-
+
+psx_bus_t* psx_bus_create(void);
+void psx_bus_init(psx_bus_t*);
+uint32_t psx_bus_read32(psx_bus_t*, uint32_t);
+uint16_t psx_bus_read16(psx_bus_t*, uint32_t);
+uint8_t psx_bus_read8(psx_bus_t*, uint32_t);
+void psx_bus_write32(psx_bus_t*, uint32_t, uint32_t);
+void psx_bus_write16(psx_bus_t*, uint32_t, uint32_t);
+void psx_bus_write8(psx_bus_t*, uint32_t, uint32_t);
+uint32_t psx_bus_get_access_cycles(psx_bus_t*);
+void psx_bus_destroy(psx_bus_t*);
+
#endif
--- a/psx/bus_init.h
+++ b/psx/bus_init.h
@@ -38,7 +38,7 @@
typedef struct psx_mdec_t psx_mdec_t;
typedef struct psx_bus_t psx_bus_t;
-
+
struct psx_bus_t {struct psx_bios_t* bios;
struct psx_ram_t* ram;
@@ -76,5 +76,5 @@
void psx_bus_init_cdrom(psx_bus_t*, struct psx_cdrom_t*);
void psx_bus_init_pad(psx_bus_t*, struct psx_pad_t*);
void psx_bus_init_mdec(psx_bus_t*, struct psx_mdec_t*);
-
+
#endif
--- a/psx/config.c
+++ b/psx/config.c
@@ -1,9 +1,9 @@
-/*
- This file should contain definitions for our
- global configuration variables and implementations
- for accessor methods
-*/
-
-// Suppress "empty translation unit" warning until
-// we implement core configuration
+/*
+ This file should contain definitions for our
+ global configuration variables and implementations
+ for accessor methods
+*/
+
+// Suppress "empty translation unit" warning until
+// we implement core configuration
int dummy;
\ No newline at end of file
--- a/psx/config.h
+++ b/psx/config.h
@@ -1,8 +1,8 @@
-#ifndef CONFIG_H
-#define CONFIG_H
-
-/*
- This file should contain accessor method definitions
-*/
-
+#ifndef CONFIG_H
+#define CONFIG_H
+
+/*
+ This file should contain accessor method definitions
+*/
+
#endif
\ No newline at end of file
--- a/psx/cpu.c
+++ b/psx/cpu.c
@@ -7,116 +7,116 @@
#include "cpu_debug.h"
static const uint32_t g_psx_cpu_cop0_write_mask_table[] = {- 0x00000000, // cop0r0 - N/A
- 0x00000000, // cop0r1 - N/A
- 0x00000000, // cop0r2 - N/A
- 0xffffffff, // BPC - Breakpoint on execute (R/W)
- 0x00000000, // cop0r4 - N/A
- 0xffffffff, // BDA - Breakpoint on data access (R/W)
- 0x00000000, // JUMPDEST - Randomly memorized jump address (R)
- 0xffc0f03f, // DCIC - Breakpoint control (R/W)
- 0x00000000, // BadVaddr - Bad Virtual Address (R)
- 0xffffffff, // BDAM - Data Access breakpoint mask (R/W)
- 0x00000000, // cop0r10 - N/A
- 0xffffffff, // BPCM - Execute breakpoint mask (R/W)
- 0xffffffff, // SR - System status register (R/W)
- 0x00000300, // CAUSE - Describes the most recently recognised exception (R)
- 0x00000000, // EPC - Return Address from Trap (R)
- 0x00000000 // PRID - Processor ID (R)
-};
-
-static const uint8_t g_psx_gte_unr_table[] = {
- 0xff, 0xfd, 0xfb, 0xf9, 0xf7, 0xf5, 0xf3, 0xf1,
- 0xef, 0xee, 0xec, 0xea, 0xe8, 0xe6, 0xe4, 0xe3,
- 0xe1, 0xdf, 0xdd, 0xdc, 0xda, 0xd8, 0xd6, 0xd5,
- 0xd3, 0xd1, 0xd0, 0xce, 0xcd, 0xcb, 0xc9, 0xc8,
- 0xc6, 0xc5, 0xc3, 0xc1, 0xc0, 0xbe, 0xbd, 0xbb,
- 0xba, 0xb8, 0xb7, 0xb5, 0xb4, 0xb2, 0xb1, 0xb0,
- 0xae, 0xad, 0xab, 0xaa, 0xa9, 0xa7, 0xa6, 0xa4,
- 0xa3, 0xa2, 0xa0, 0x9f, 0x9e, 0x9c, 0x9b, 0x9a,
- 0x99, 0x97, 0x96, 0x95, 0x94, 0x92, 0x91, 0x90,
- 0x8f, 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x87, 0x86,
- 0x85, 0x84, 0x83, 0x82, 0x81, 0x7f, 0x7e, 0x7d,
- 0x7c, 0x7b, 0x7a, 0x79, 0x78, 0x77, 0x75, 0x74,
- 0x73, 0x72, 0x71, 0x70, 0x6f, 0x6e, 0x6d, 0x6c,
- 0x6b, 0x6a, 0x69, 0x68, 0x67, 0x66, 0x65, 0x64,
- 0x63, 0x62, 0x61, 0x60, 0x5f, 0x5e, 0x5d, 0x5d,
- 0x5c, 0x5b, 0x5a, 0x59, 0x58, 0x57, 0x56, 0x55,
- 0x54, 0x53, 0x53, 0x52, 0x51, 0x50, 0x4f, 0x4e,
- 0x4d, 0x4d, 0x4c, 0x4b, 0x4a, 0x49, 0x48, 0x48,
- 0x47, 0x46, 0x45, 0x44, 0x43, 0x43, 0x42, 0x41,
- 0x40, 0x3f, 0x3f, 0x3e, 0x3d, 0x3c, 0x3c, 0x3b,
- 0x3a, 0x39, 0x39, 0x38, 0x37, 0x36, 0x36, 0x35,
- 0x34, 0x33, 0x33, 0x32, 0x31, 0x31, 0x30, 0x2f,
- 0x2e, 0x2e, 0x2d, 0x2c, 0x2c, 0x2b, 0x2a, 0x2a,
- 0x29, 0x28, 0x28, 0x27, 0x26, 0x26, 0x25, 0x24,
- 0x24, 0x23, 0x22, 0x22, 0x21, 0x20, 0x20, 0x1f,
- 0x1e, 0x1e, 0x1d, 0x1d, 0x1c, 0x1b, 0x1b, 0x1a,
- 0x19, 0x19, 0x18, 0x18, 0x17, 0x16, 0x16, 0x15,
- 0x15, 0x14, 0x14, 0x13, 0x12, 0x12, 0x11, 0x11,
- 0x10, 0x0f, 0x0f, 0x0e, 0x0e, 0x0d, 0x0d, 0x0c,
- 0x0c, 0x0b, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08,
- 0x07, 0x07, 0x06, 0x06, 0x05, 0x05, 0x04, 0x04,
- 0x03, 0x03, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00,
- 0x00
-};
-
-static inline void psx_gte_i_rtps(psx_cpu_t*);
-static inline void psx_gte_i_nclip(psx_cpu_t*);
-static inline void psx_gte_i_op(psx_cpu_t*);
-static inline void psx_gte_i_dpcs(psx_cpu_t*);
-static inline void psx_gte_i_intpl(psx_cpu_t*);
-static inline void psx_gte_i_mvmva(psx_cpu_t*);
-static inline void psx_gte_i_ncds(psx_cpu_t*);
-static inline void psx_gte_i_cdp(psx_cpu_t*);
-static inline void psx_gte_i_ncdt(psx_cpu_t*);
-static inline void psx_gte_i_nccs(psx_cpu_t*);
-static inline void psx_gte_i_cc(psx_cpu_t*);
-static inline void psx_gte_i_ncs(psx_cpu_t*);
-static inline void psx_gte_i_nct(psx_cpu_t*);
-static inline void psx_gte_i_sqr(psx_cpu_t*);
-static inline void psx_gte_i_dcpl(psx_cpu_t*);
-static inline void psx_gte_i_dpct(psx_cpu_t*);
-static inline void psx_gte_i_avsz3(psx_cpu_t*);
-static inline void psx_gte_i_avsz4(psx_cpu_t*);
-static inline void psx_gte_i_rtpt(psx_cpu_t*);
-static inline void psx_gte_i_gpf(psx_cpu_t*);
-static inline void psx_gte_i_gpl(psx_cpu_t*);
-static inline void psx_gte_i_ncct(psx_cpu_t*);
-
-#define OP ((cpu->opcode >> 26) & 0x3f)
-#define S ((cpu->opcode >> 21) & 0x1f)
-#define T ((cpu->opcode >> 16) & 0x1f)
-#define D ((cpu->opcode >> 11) & 0x1f)
-#define IMM5 ((cpu->opcode >> 6) & 0x1f)
-#define CMT ((cpu->opcode >> 6) & 0xfffff)
-#define SOP (cpu->opcode & 0x3f)
-#define IMM26 (cpu->opcode & 0x3ffffff)
-#define IMM16 (cpu->opcode & 0xffff)
-#define IMM16S ((int32_t)((int16_t)IMM16))
-
-#define COP2_DR(idx) ((uint32_t*)(&cpu->cop2_dr))[idx]
-#define COP2_CR(idx) ((uint32_t*)(&cpu->cop2_cr))[idx]
-
-#define R_R0 (cpu->r[0])
-#define R_A0 (cpu->r[4])
-#define R_RA (cpu->r[31])
-
-#define DO_PENDING_LOAD { \
- cpu->r[cpu->load_d] = cpu->load_v; \
- R_R0 = 0; \
- cpu->load_v = 0xffffffff; \
- cpu->load_d = 0; }
-
-#define SE8(v) ((int32_t)((int8_t)v))
-#define SE16(v) ((int32_t)((int16_t)v))
-
-#define BRANCH(offset) { \
- cpu->next_pc = cpu->next_pc + (offset); \
- cpu->next_pc = cpu->next_pc - 4; \
- cpu->branch = 1; \
- cpu->branch_taken = 1; }
-
+ 0x00000000, // cop0r0 - N/A
+ 0x00000000, // cop0r1 - N/A
+ 0x00000000, // cop0r2 - N/A
+ 0xffffffff, // BPC - Breakpoint on execute (R/W)
+ 0x00000000, // cop0r4 - N/A
+ 0xffffffff, // BDA - Breakpoint on data access (R/W)
+ 0x00000000, // JUMPDEST - Randomly memorized jump address (R)
+ 0xffc0f03f, // DCIC - Breakpoint control (R/W)
+ 0x00000000, // BadVaddr - Bad Virtual Address (R)
+ 0xffffffff, // BDAM - Data Access breakpoint mask (R/W)
+ 0x00000000, // cop0r10 - N/A
+ 0xffffffff, // BPCM - Execute breakpoint mask (R/W)
+ 0xffffffff, // SR - System status register (R/W)
+ 0x00000300, // CAUSE - Describes the most recently recognised exception (R)
+ 0x00000000, // EPC - Return Address from Trap (R)
+ 0x00000000 // PRID - Processor ID (R)
+};
+
+static const uint8_t g_psx_gte_unr_table[] = {+ 0xff, 0xfd, 0xfb, 0xf9, 0xf7, 0xf5, 0xf3, 0xf1,
+ 0xef, 0xee, 0xec, 0xea, 0xe8, 0xe6, 0xe4, 0xe3,
+ 0xe1, 0xdf, 0xdd, 0xdc, 0xda, 0xd8, 0xd6, 0xd5,
+ 0xd3, 0xd1, 0xd0, 0xce, 0xcd, 0xcb, 0xc9, 0xc8,
+ 0xc6, 0xc5, 0xc3, 0xc1, 0xc0, 0xbe, 0xbd, 0xbb,
+ 0xba, 0xb8, 0xb7, 0xb5, 0xb4, 0xb2, 0xb1, 0xb0,
+ 0xae, 0xad, 0xab, 0xaa, 0xa9, 0xa7, 0xa6, 0xa4,
+ 0xa3, 0xa2, 0xa0, 0x9f, 0x9e, 0x9c, 0x9b, 0x9a,
+ 0x99, 0x97, 0x96, 0x95, 0x94, 0x92, 0x91, 0x90,
+ 0x8f, 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x87, 0x86,
+ 0x85, 0x84, 0x83, 0x82, 0x81, 0x7f, 0x7e, 0x7d,
+ 0x7c, 0x7b, 0x7a, 0x79, 0x78, 0x77, 0x75, 0x74,
+ 0x73, 0x72, 0x71, 0x70, 0x6f, 0x6e, 0x6d, 0x6c,
+ 0x6b, 0x6a, 0x69, 0x68, 0x67, 0x66, 0x65, 0x64,
+ 0x63, 0x62, 0x61, 0x60, 0x5f, 0x5e, 0x5d, 0x5d,
+ 0x5c, 0x5b, 0x5a, 0x59, 0x58, 0x57, 0x56, 0x55,
+ 0x54, 0x53, 0x53, 0x52, 0x51, 0x50, 0x4f, 0x4e,
+ 0x4d, 0x4d, 0x4c, 0x4b, 0x4a, 0x49, 0x48, 0x48,
+ 0x47, 0x46, 0x45, 0x44, 0x43, 0x43, 0x42, 0x41,
+ 0x40, 0x3f, 0x3f, 0x3e, 0x3d, 0x3c, 0x3c, 0x3b,
+ 0x3a, 0x39, 0x39, 0x38, 0x37, 0x36, 0x36, 0x35,
+ 0x34, 0x33, 0x33, 0x32, 0x31, 0x31, 0x30, 0x2f,
+ 0x2e, 0x2e, 0x2d, 0x2c, 0x2c, 0x2b, 0x2a, 0x2a,
+ 0x29, 0x28, 0x28, 0x27, 0x26, 0x26, 0x25, 0x24,
+ 0x24, 0x23, 0x22, 0x22, 0x21, 0x20, 0x20, 0x1f,
+ 0x1e, 0x1e, 0x1d, 0x1d, 0x1c, 0x1b, 0x1b, 0x1a,
+ 0x19, 0x19, 0x18, 0x18, 0x17, 0x16, 0x16, 0x15,
+ 0x15, 0x14, 0x14, 0x13, 0x12, 0x12, 0x11, 0x11,
+ 0x10, 0x0f, 0x0f, 0x0e, 0x0e, 0x0d, 0x0d, 0x0c,
+ 0x0c, 0x0b, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08,
+ 0x07, 0x07, 0x06, 0x06, 0x05, 0x05, 0x04, 0x04,
+ 0x03, 0x03, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00,
+ 0x00
+};
+
+static inline void psx_gte_i_rtps(psx_cpu_t*);
+static inline void psx_gte_i_nclip(psx_cpu_t*);
+static inline void psx_gte_i_op(psx_cpu_t*);
+static inline void psx_gte_i_dpcs(psx_cpu_t*);
+static inline void psx_gte_i_intpl(psx_cpu_t*);
+static inline void psx_gte_i_mvmva(psx_cpu_t*);
+static inline void psx_gte_i_ncds(psx_cpu_t*);
+static inline void psx_gte_i_cdp(psx_cpu_t*);
+static inline void psx_gte_i_ncdt(psx_cpu_t*);
+static inline void psx_gte_i_nccs(psx_cpu_t*);
+static inline void psx_gte_i_cc(psx_cpu_t*);
+static inline void psx_gte_i_ncs(psx_cpu_t*);
+static inline void psx_gte_i_nct(psx_cpu_t*);
+static inline void psx_gte_i_sqr(psx_cpu_t*);
+static inline void psx_gte_i_dcpl(psx_cpu_t*);
+static inline void psx_gte_i_dpct(psx_cpu_t*);
+static inline void psx_gte_i_avsz3(psx_cpu_t*);
+static inline void psx_gte_i_avsz4(psx_cpu_t*);
+static inline void psx_gte_i_rtpt(psx_cpu_t*);
+static inline void psx_gte_i_gpf(psx_cpu_t*);
+static inline void psx_gte_i_gpl(psx_cpu_t*);
+static inline void psx_gte_i_ncct(psx_cpu_t*);
+
+#define OP ((cpu->opcode >> 26) & 0x3f)
+#define S ((cpu->opcode >> 21) & 0x1f)
+#define T ((cpu->opcode >> 16) & 0x1f)
+#define D ((cpu->opcode >> 11) & 0x1f)
+#define IMM5 ((cpu->opcode >> 6) & 0x1f)
+#define CMT ((cpu->opcode >> 6) & 0xfffff)
+#define SOP (cpu->opcode & 0x3f)
+#define IMM26 (cpu->opcode & 0x3ffffff)
+#define IMM16 (cpu->opcode & 0xffff)
+#define IMM16S ((int32_t)((int16_t)IMM16))
+
+#define COP2_DR(idx) ((uint32_t*)(&cpu->cop2_dr))[idx]
+#define COP2_CR(idx) ((uint32_t*)(&cpu->cop2_cr))[idx]
+
+#define R_R0 (cpu->r[0])
+#define R_A0 (cpu->r[4])
+#define R_RA (cpu->r[31])
+
+#define DO_PENDING_LOAD { \+ cpu->r[cpu->load_d] = cpu->load_v; \
+ R_R0 = 0; \
+ cpu->load_v = 0xffffffff; \
+ cpu->load_d = 0; }
+
+#define SE8(v) ((int32_t)((int8_t)v))
+#define SE16(v) ((int32_t)((int16_t)v))
+
+#define BRANCH(offset) { \+ cpu->next_pc = cpu->next_pc + (offset); \
+ cpu->next_pc = cpu->next_pc - 4; \
+ cpu->branch = 1; \
+ cpu->branch_taken = 1; }
+
void cpu_a_kcall_hook(psx_cpu_t* cpu) { switch (cpu->r[9]) { case 0x09: print("%c", R_A0); break;@@ -151,27 +151,27 @@
}
} break;
}
-}
-
-psx_cpu_t* psx_cpu_create(void) {
- return (psx_cpu_t*)malloc(sizeof(psx_cpu_t));
-}
-
-void cpu_a_kcall_hook(psx_cpu_t*);
-void cpu_b_kcall_hook(psx_cpu_t*);
-
-void psx_cpu_destroy(psx_cpu_t* cpu) {
- free(cpu);
-}
-
-void psx_cpu_set_a_kcall_hook(psx_cpu_t* cpu, psx_cpu_kcall_hook_t hook) {
- cpu->a_function_hook = hook;
-}
-
-void psx_cpu_set_b_kcall_hook(psx_cpu_t* cpu, psx_cpu_kcall_hook_t hook) {
- cpu->b_function_hook = hook;
-}
-
+}
+
+psx_cpu_t* psx_cpu_create(void) {+ return (psx_cpu_t*)malloc(sizeof(psx_cpu_t));
+}
+
+void cpu_a_kcall_hook(psx_cpu_t*);
+void cpu_b_kcall_hook(psx_cpu_t*);
+
+void psx_cpu_destroy(psx_cpu_t* cpu) {+ free(cpu);
+}
+
+void psx_cpu_set_a_kcall_hook(psx_cpu_t* cpu, psx_cpu_kcall_hook_t hook) {+ cpu->a_function_hook = hook;
+}
+
+void psx_cpu_set_b_kcall_hook(psx_cpu_t* cpu, psx_cpu_kcall_hook_t hook) {+ cpu->b_function_hook = hook;
+}
+
void psx_cpu_save_state(psx_cpu_t* cpu, void* file) {USED(cpu);
USED(file);
@@ -181,2165 +181,2165 @@
USED(cpu);
USED(file);
}
-
-void psx_cpu_init(psx_cpu_t* cpu, psx_bus_t* bus) {
- memset(cpu, 0, sizeof(psx_cpu_t));
-
- psx_cpu_set_a_kcall_hook(cpu, cpu_a_kcall_hook);
- psx_cpu_set_b_kcall_hook(cpu, cpu_b_kcall_hook);
-
- cpu->bus = bus;
- cpu->pc = 0xbfc00000;
- cpu->next_pc = cpu->pc + 4;
-
- cpu->cop0_r[COP0_SR] = 0x10900000;
- cpu->cop0_r[COP0_PRID] = 0x00000002;
-}
-
-static inline int psx_cpu_check_irq(psx_cpu_t* cpu) {
- return (cpu->cop0_r[COP0_SR] & SR_IEC) &&
- (cpu->cop0_r[COP0_SR] & cpu->cop0_r[COP0_CAUSE] & 0x00000700);
-}
-
-static inline void psx_cpu_exception(psx_cpu_t* cpu, uint32_t cause) {
- // Set excode and clear 3 LSBs
- cpu->cop0_r[COP0_CAUSE] &= 0xffffff80;
- cpu->cop0_r[COP0_CAUSE] |= cause;
-
- cpu->cop0_r[COP0_EPC] = cpu->saved_pc;
-
- if (cpu->delay_slot) {
- cpu->cop0_r[COP0_EPC] -= 4;
- cpu->cop0_r[COP0_CAUSE] |= 0x80000000;
- }
-
- // Do exception stack push
- uint32_t mode = cpu->cop0_r[COP0_SR] & 0x3f;
-
- cpu->cop0_r[COP0_SR] &= 0xffffffc0;
- cpu->cop0_r[COP0_SR] |= (mode << 2) & 0x3f;
-
- // Set PC to the vector selected on BEV
- cpu->pc = (cpu->cop0_r[COP0_SR] & SR_BEV) ? 0xbfc00180 : 0x80000080;
-
- cpu->next_pc = cpu->pc + 4;
-}
-
-void psx_cpu_cycle(psx_cpu_t* cpu) {
- cpu->last_cycles = 0;
-
- if ((cpu->pc & 0x3fffffff) == 0x000000b4)
- if (cpu->b_function_hook)
- cpu->b_function_hook(cpu);
-
- cpu->saved_pc = cpu->pc;
- cpu->delay_slot = cpu->branch;
- cpu->branch = 0;
- cpu->branch_taken = 0;
-
- if (cpu->saved_pc & 3)
- psx_cpu_exception(cpu, CAUSE_ADEL);
-
- cpu->opcode = psx_bus_read32(cpu->bus, cpu->pc);
- cpu->last_cycles = psx_bus_get_access_cycles(cpu->bus);
-
- cpu->pc = cpu->next_pc;
- cpu->next_pc += 4;
-
- if (psx_cpu_check_irq(cpu)) {
- // GTE instructions "win" over interrupts (fast path)
- if ((cpu->opcode & 0xfe000000) == 0x4a000000) {
- DO_PENDING_LOAD;
-
- cpu->gte_sf = ((cpu->opcode & 0x80000) != 0) * 12;
- cpu->gte_lm = (cpu->opcode & 0x400) != 0;
- cpu->gte_cv = (cpu->opcode >> 13) & 3;
- cpu->gte_v = (cpu->opcode >> 15) & 3;
- cpu->gte_mx = (cpu->opcode >> 17) & 3;
-
- switch (cpu->opcode & 0x3f) {
- case 0x01: psx_gte_i_rtps(cpu); cpu->last_cycles += 15; break;
- case 0x06: psx_gte_i_nclip(cpu); cpu->last_cycles += 8; break;
- case 0x0c: psx_gte_i_op(cpu); cpu->last_cycles += 6; break;
- case 0x10: psx_gte_i_dpcs(cpu); cpu->last_cycles += 8; break;
- case 0x11: psx_gte_i_intpl(cpu); cpu->last_cycles += 8; break;
- case 0x12: psx_gte_i_mvmva(cpu); cpu->last_cycles += 8; break;
- case 0x13: psx_gte_i_ncds(cpu); cpu->last_cycles += 19; break;
- case 0x14: psx_gte_i_cdp(cpu); cpu->last_cycles += 13; break;
- case 0x16: psx_gte_i_ncdt(cpu); cpu->last_cycles += 44; break;
- case 0x1b: psx_gte_i_nccs(cpu); cpu->last_cycles += 17; break;
- case 0x1c: psx_gte_i_cc(cpu); cpu->last_cycles += 11; break;
- case 0x1e: psx_gte_i_ncs(cpu); cpu->last_cycles += 14; break;
- case 0x20: psx_gte_i_nct(cpu); cpu->last_cycles += 30; break;
- case 0x28: psx_gte_i_sqr(cpu); cpu->last_cycles += 5; break;
- case 0x29: psx_gte_i_dcpl(cpu); cpu->last_cycles += 8; break;
- case 0x2a: psx_gte_i_dpct(cpu); cpu->last_cycles += 17; break;
- case 0x2d: psx_gte_i_avsz3(cpu); cpu->last_cycles += 5; break;
- case 0x2e: psx_gte_i_avsz4(cpu); cpu->last_cycles += 6; break;
- case 0x30: psx_gte_i_rtpt(cpu); cpu->last_cycles += 23; break;
- case 0x3d: psx_gte_i_gpf(cpu); cpu->last_cycles += 5; break;
- case 0x3e: psx_gte_i_gpl(cpu); cpu->last_cycles += 5; break;
- case 0x3f: psx_gte_i_ncct(cpu); cpu->last_cycles += 39; break;
- }
- }
-
- cpu->total_cycles += cpu->last_cycles;
-
- cpu->r[0] = 0;
-
- psx_cpu_exception(cpu, CAUSE_INT);
-
- return;
- }
-
- int cyc = psx_cpu_execute(cpu);
-
- if (!cyc) {
+
+void psx_cpu_init(psx_cpu_t* cpu, psx_bus_t* bus) {+ memset(cpu, 0, sizeof(psx_cpu_t));
+
+ psx_cpu_set_a_kcall_hook(cpu, cpu_a_kcall_hook);
+ psx_cpu_set_b_kcall_hook(cpu, cpu_b_kcall_hook);
+
+ cpu->bus = bus;
+ cpu->pc = 0xbfc00000;
+ cpu->next_pc = cpu->pc + 4;
+
+ cpu->cop0_r[COP0_SR] = 0x10900000;
+ cpu->cop0_r[COP0_PRID] = 0x00000002;
+}
+
+static inline int psx_cpu_check_irq(psx_cpu_t* cpu) {+ return (cpu->cop0_r[COP0_SR] & SR_IEC) &&
+ (cpu->cop0_r[COP0_SR] & cpu->cop0_r[COP0_CAUSE] & 0x00000700);
+}
+
+static inline void psx_cpu_exception(psx_cpu_t* cpu, uint32_t cause) {+ // Set excode and clear 3 LSBs
+ cpu->cop0_r[COP0_CAUSE] &= 0xffffff80;
+ cpu->cop0_r[COP0_CAUSE] |= cause;
+
+ cpu->cop0_r[COP0_EPC] = cpu->saved_pc;
+
+ if (cpu->delay_slot) {+ cpu->cop0_r[COP0_EPC] -= 4;
+ cpu->cop0_r[COP0_CAUSE] |= 0x80000000;
+ }
+
+ // Do exception stack push
+ uint32_t mode = cpu->cop0_r[COP0_SR] & 0x3f;
+
+ cpu->cop0_r[COP0_SR] &= 0xffffffc0;
+ cpu->cop0_r[COP0_SR] |= (mode << 2) & 0x3f;
+
+ // Set PC to the vector selected on BEV
+ cpu->pc = (cpu->cop0_r[COP0_SR] & SR_BEV) ? 0xbfc00180 : 0x80000080;
+
+ cpu->next_pc = cpu->pc + 4;
+}
+
+void psx_cpu_cycle(psx_cpu_t* cpu) {+ cpu->last_cycles = 0;
+
+ if ((cpu->pc & 0x3fffffff) == 0x000000b4)
+ if (cpu->b_function_hook)
+ cpu->b_function_hook(cpu);
+
+ cpu->saved_pc = cpu->pc;
+ cpu->delay_slot = cpu->branch;
+ cpu->branch = 0;
+ cpu->branch_taken = 0;
+
+ if (cpu->saved_pc & 3)
+ psx_cpu_exception(cpu, CAUSE_ADEL);
+
+ cpu->opcode = psx_bus_read32(cpu->bus, cpu->pc);
+ cpu->last_cycles = psx_bus_get_access_cycles(cpu->bus);
+
+ cpu->pc = cpu->next_pc;
+ cpu->next_pc += 4;
+
+ if (psx_cpu_check_irq(cpu)) {+ // GTE instructions "win" over interrupts (fast path)
+ if ((cpu->opcode & 0xfe000000) == 0x4a000000) {+ DO_PENDING_LOAD;
+
+ cpu->gte_sf = ((cpu->opcode & 0x80000) != 0) * 12;
+ cpu->gte_lm = (cpu->opcode & 0x400) != 0;
+ cpu->gte_cv = (cpu->opcode >> 13) & 3;
+ cpu->gte_v = (cpu->opcode >> 15) & 3;
+ cpu->gte_mx = (cpu->opcode >> 17) & 3;
+
+ switch (cpu->opcode & 0x3f) {+ case 0x01: psx_gte_i_rtps(cpu); cpu->last_cycles += 15; break;
+ case 0x06: psx_gte_i_nclip(cpu); cpu->last_cycles += 8; break;
+ case 0x0c: psx_gte_i_op(cpu); cpu->last_cycles += 6; break;
+ case 0x10: psx_gte_i_dpcs(cpu); cpu->last_cycles += 8; break;
+ case 0x11: psx_gte_i_intpl(cpu); cpu->last_cycles += 8; break;
+ case 0x12: psx_gte_i_mvmva(cpu); cpu->last_cycles += 8; break;
+ case 0x13: psx_gte_i_ncds(cpu); cpu->last_cycles += 19; break;
+ case 0x14: psx_gte_i_cdp(cpu); cpu->last_cycles += 13; break;
+ case 0x16: psx_gte_i_ncdt(cpu); cpu->last_cycles += 44; break;
+ case 0x1b: psx_gte_i_nccs(cpu); cpu->last_cycles += 17; break;
+ case 0x1c: psx_gte_i_cc(cpu); cpu->last_cycles += 11; break;
+ case 0x1e: psx_gte_i_ncs(cpu); cpu->last_cycles += 14; break;
+ case 0x20: psx_gte_i_nct(cpu); cpu->last_cycles += 30; break;
+ case 0x28: psx_gte_i_sqr(cpu); cpu->last_cycles += 5; break;
+ case 0x29: psx_gte_i_dcpl(cpu); cpu->last_cycles += 8; break;
+ case 0x2a: psx_gte_i_dpct(cpu); cpu->last_cycles += 17; break;
+ case 0x2d: psx_gte_i_avsz3(cpu); cpu->last_cycles += 5; break;
+ case 0x2e: psx_gte_i_avsz4(cpu); cpu->last_cycles += 6; break;
+ case 0x30: psx_gte_i_rtpt(cpu); cpu->last_cycles += 23; break;
+ case 0x3d: psx_gte_i_gpf(cpu); cpu->last_cycles += 5; break;
+ case 0x3e: psx_gte_i_gpl(cpu); cpu->last_cycles += 5; break;
+ case 0x3f: psx_gte_i_ncct(cpu); cpu->last_cycles += 39; break;
+ }
+ }
+
+ cpu->total_cycles += cpu->last_cycles;
+
+ cpu->r[0] = 0;
+
+ psx_cpu_exception(cpu, CAUSE_INT);
+
+ return;
+ }
+
+ int cyc = psx_cpu_execute(cpu);
+
+ if (!cyc) { print("psxe: Illegal instruction %08x at %08x (next=%08x, saved=%08x)\n", cpu->opcode, cpu->pc, cpu->next_pc, cpu->saved_pc);-
- psx_cpu_exception(cpu, CAUSE_RI);
- }
-
- cpu->last_cycles += cyc;
- cpu->total_cycles += cpu->last_cycles;
-
- cpu->r[0] = 0;
-}
-
-void psx_cpu_set_irq_pending(psx_cpu_t* cpu) {
- cpu->cop0_r[COP0_CAUSE] |= SR_IM2;
-}
-
-static inline void psx_cpu_i_invalid(psx_cpu_t* cpu) {
- log_fatal("%08x: Illegal instruction %08x", cpu->pc - 8, cpu->opcode);
-
- psx_cpu_exception(cpu, CAUSE_RI);
-}
-
-// BXX
-static inline void psx_cpu_i_bltz(psx_cpu_t* cpu) {
- TRACE_B("bltz");
-
- int32_t s = (int32_t)cpu->r[S];
-
- DO_PENDING_LOAD;
-
- if ((int32_t)s < (int32_t)0)
- BRANCH(IMM16S << 2);
-}
-
-static inline void psx_cpu_i_bgez(psx_cpu_t* cpu) {
- TRACE_B("bgez");
-
- int32_t s = (int32_t)cpu->r[S];
-
- DO_PENDING_LOAD;
-
- if ((int32_t)s >= (int32_t)0)
- BRANCH(IMM16S << 2);
-}
-
-static inline void psx_cpu_i_bltzal(psx_cpu_t* cpu) {
- TRACE_B("bltzal");
-
- int32_t s = (int32_t)cpu->r[S];
-
- DO_PENDING_LOAD;
-
- R_RA = cpu->next_pc;
-
- if ((int32_t)s < (int32_t)0)
- BRANCH(IMM16S << 2);
-}
-
-static inline void psx_cpu_i_bgezal(psx_cpu_t* cpu) {
- TRACE_B("bgezal");
-
- int32_t s = (int32_t)cpu->r[S];
-
- DO_PENDING_LOAD;
-
- R_RA = cpu->next_pc;
-
- if ((int32_t)s >= (int32_t)0)
- BRANCH(IMM16S << 2);
-}
-
-static inline void psx_cpu_i_j(psx_cpu_t* cpu) {
- cpu->branch = 1;
-
- TRACE_I26("j");
-
- DO_PENDING_LOAD;
-
- cpu->next_pc = (cpu->next_pc & 0xf0000000) | (IMM26 << 2);
-}
-
-static inline void psx_cpu_i_jal(psx_cpu_t* cpu) {
- cpu->branch = 1;
-
- TRACE_I26("jal");
-
- DO_PENDING_LOAD;
-
- R_RA = cpu->next_pc;
-
- cpu->next_pc = (cpu->next_pc & 0xf0000000) | (IMM26 << 2);
-}
-
-static inline void psx_cpu_i_beq(psx_cpu_t* cpu) {
- cpu->branch = 1;
- cpu->branch_taken = 0;
-
- TRACE_B("beq");
-
- uint32_t s = cpu->r[S];
- uint32_t t = cpu->r[T];
-
- DO_PENDING_LOAD;
-
- if (s == t)
- BRANCH(IMM16S << 2);
-}
-
-static inline void psx_cpu_i_bne(psx_cpu_t* cpu) {
- cpu->branch = 1;
- cpu->branch_taken = 0;
-
- TRACE_B("bne");
-
- uint32_t s = cpu->r[S];
- uint32_t t = cpu->r[T];
-
- DO_PENDING_LOAD;
-
- if (s != t)
- BRANCH(IMM16S << 2);
-}
-
-static inline void psx_cpu_i_blez(psx_cpu_t* cpu) {
- cpu->branch = 1;
- cpu->branch_taken = 0;
-
- TRACE_B("blez");
-
- int32_t s = (int32_t)cpu->r[S];
-
- DO_PENDING_LOAD;
-
- if ((int32_t)s <= (int32_t)0)
- BRANCH(IMM16S << 2);
-}
-
-static inline void psx_cpu_i_bgtz(psx_cpu_t* cpu) {
- cpu->branch = 1;
- cpu->branch_taken = 0;
-
- TRACE_B("bgtz");
-
- int32_t s = (int32_t)cpu->r[S];
-
- DO_PENDING_LOAD;
-
- if ((int32_t)s > (int32_t)0)
- BRANCH(IMM16S << 2);
-}
-
-static inline void psx_cpu_i_addi(psx_cpu_t* cpu) {
- TRACE_I16D("addi");
-
- uint32_t s = cpu->r[S];
-
- DO_PENDING_LOAD;
-
- uint32_t i = IMM16S;
- uint32_t r = s + i;
- uint32_t o = (s ^ r) & (i ^ r);
-
- if (o & 0x80000000) {
- psx_cpu_exception(cpu, CAUSE_OV);
- } else {
- cpu->r[T] = r;
- }
-}
-
-static inline void psx_cpu_i_addiu(psx_cpu_t* cpu) {
- TRACE_I16D("addiu");
-
- uint32_t s = cpu->r[S];
-
- DO_PENDING_LOAD;
-
- cpu->r[T] = s + IMM16S;
-}
-
-static inline void psx_cpu_i_slti(psx_cpu_t* cpu) {
- TRACE_I16D("slti");
-
- int32_t s = (int32_t)cpu->r[S];
-
- DO_PENDING_LOAD;
-
- cpu->r[T] = s < IMM16S;
-}
-
-static inline void psx_cpu_i_sltiu(psx_cpu_t* cpu) {
- TRACE_I16D("sltiu");
-
- uint32_t s = cpu->r[S];
-
- DO_PENDING_LOAD;
-
- cpu->r[T] = s < IMM16S;
-}
-
-static inline void psx_cpu_i_andi(psx_cpu_t* cpu) {
- TRACE_I16D("andi");
-
- uint32_t s = cpu->r[S];
-
- DO_PENDING_LOAD;
-
- cpu->r[T] = s & IMM16;
-}
-
-static inline void psx_cpu_i_ori(psx_cpu_t* cpu) {
- TRACE_I16D("ori");
-
- uint32_t s = cpu->r[S];
-
- DO_PENDING_LOAD;
-
- cpu->r[T] = s | IMM16;
-}
-
-static inline void psx_cpu_i_xori(psx_cpu_t* cpu) {
- TRACE_I16D("xori");
-
- uint32_t s = cpu->r[S];
-
- DO_PENDING_LOAD;
-
- cpu->r[T] = s ^ IMM16;
-}
-
-static inline void psx_cpu_i_lui(psx_cpu_t* cpu) {
- TRACE_I16S("lui");
-
- DO_PENDING_LOAD;
-
- cpu->r[T] = IMM16 << 16;
-}
-
-static inline void psx_cpu_i_lb(psx_cpu_t* cpu) {
- TRACE_M("lb");
-
- uint32_t s = cpu->r[S];
-
- if (cpu->load_d != T)
- DO_PENDING_LOAD;
-
- cpu->load_d = T;
- cpu->load_v = SE8(psx_bus_read8(cpu->bus, s + IMM16S));
-}
-
-static inline void psx_cpu_i_lh(psx_cpu_t* cpu) {
- TRACE_M("lh");
-
- uint32_t s = cpu->r[S];
-
- if (cpu->load_d != T)
- DO_PENDING_LOAD;
-
- uint32_t addr = s + IMM16S;
-
- if (addr & 0x1) {
- psx_cpu_exception(cpu, CAUSE_ADEL);
- } else {
- cpu->load_d = T;
- cpu->load_v = SE16(psx_bus_read16(cpu->bus, addr));
- }
-}
-
-static inline void psx_cpu_i_lwl(psx_cpu_t* cpu) {
- TRACE_M("lwl");
-
- uint32_t rt = T;
- uint32_t s = cpu->r[S];
- uint32_t t = cpu->r[rt];
-
- uint32_t addr = s + IMM16S;
- uint32_t load = psx_bus_read32(cpu->bus, addr & 0xfffffffc);
-
- if (rt == cpu->load_d) {
- t = cpu->load_v;
- } else {
- DO_PENDING_LOAD;
- }
-
- int shift = (int)((addr & 0x3) << 3);
- uint32_t mask = (uint32_t)0x00FFFFFF >> shift;
- uint32_t value = (t & mask) | (load << (24 - shift));
-
- cpu->load_d = rt;
- cpu->load_v = value;
-
- // printf("lwl rt=%u s=%08x t=%08x addr=%08x load=%08x (%08x) shift=%u mask=%08x value=%08x\n",
- // rt, s, t, addr, load, addr & 0xfffffffc, shift, mask, value
- // );
-}
-
-static inline void psx_cpu_i_lw(psx_cpu_t* cpu) {
- TRACE_M("lw");
-
- uint32_t s = cpu->r[S];
- uint32_t addr = s + IMM16S;
-
- if (cpu->load_d != T)
- DO_PENDING_LOAD;
-
- if (addr & 0x3) {
- psx_cpu_exception(cpu, CAUSE_ADEL);
- } else {
- cpu->load_d = T;
- cpu->load_v = psx_bus_read32(cpu->bus, addr);
- }
-}
-
-static inline void psx_cpu_i_lbu(psx_cpu_t* cpu) {
- TRACE_M("lbu");
-
- uint32_t s = cpu->r[S];
-
- if (cpu->load_d != T)
- DO_PENDING_LOAD;
-
- cpu->load_d = T;
- cpu->load_v = psx_bus_read8(cpu->bus, s + IMM16S);
-}
-
-static inline void psx_cpu_i_lhu(psx_cpu_t* cpu) {
- TRACE_M("lhu");
-
- uint32_t s = cpu->r[S];
- uint32_t addr = s + IMM16S;
-
- if (cpu->load_d != T)
- DO_PENDING_LOAD;
-
- if (addr & 0x1) {
- psx_cpu_exception(cpu, CAUSE_ADEL);
- } else {
- cpu->load_d = T;
- cpu->load_v = psx_bus_read16(cpu->bus, addr);
- }
-}
-
-static inline void psx_cpu_i_lwr(psx_cpu_t* cpu) {
- TRACE_M("lwr");
-
- uint32_t rt = T;
- uint32_t s = cpu->r[S];
- uint32_t t = cpu->r[rt];
-
- uint32_t addr = s + IMM16S;
- uint32_t load = psx_bus_read32(cpu->bus, addr & 0xfffffffc);
-
- if (rt == cpu->load_d) {
- t = cpu->load_v;
- } else {
- DO_PENDING_LOAD;
- }
-
- int shift = (int)((addr & 0x3) << 3);
- uint32_t mask = 0xFFFFFF00 << (24 - shift);
- uint32_t value = (t & mask) | (load >> shift);
-
- cpu->load_d = rt;
- cpu->load_v = value;
-
- // printf("lwr rt=%u s=%08x t=%08x addr=%08x load=%08x (%08x) shift=%u mask=%08x value=%08x\n",
- // rt, s, t, addr, load, addr & 0xfffffffc, shift, mask, value
- // );
-}
-
-static inline void psx_cpu_i_sb(psx_cpu_t* cpu) {
- TRACE_M("sb");
-
- uint32_t s = cpu->r[S];
- uint32_t t = cpu->r[T];
-
- DO_PENDING_LOAD;
-
- // Cache isolated
- if (cpu->cop0_r[COP0_SR] & SR_ISC) {
- log_debug("Ignoring write while cache is isolated");
-
- return;
- }
-
- psx_bus_write8(cpu->bus, s + IMM16S, t);
-}
-
-static inline void psx_cpu_i_sh(psx_cpu_t* cpu) {
- TRACE_M("sh");
-
- uint32_t s = cpu->r[S];
- uint32_t t = cpu->r[T];
- uint32_t addr = s + IMM16S;
-
- DO_PENDING_LOAD;
-
- // Cache isolated
- if (cpu->cop0_r[COP0_SR] & SR_ISC) {
- log_debug("Ignoring write while cache is isolated");
-
- return;
- }
-
- if (addr & 0x1) {
- psx_cpu_exception(cpu, CAUSE_ADES);
- } else {
- psx_bus_write16(cpu->bus, addr, t);
- }
-}
-
-static inline void psx_cpu_i_swl(psx_cpu_t* cpu) {
- TRACE_M("swl");
-
- uint32_t s = cpu->r[S];
-
- DO_PENDING_LOAD;
-
- uint32_t addr = s + IMM16S;
- uint32_t aligned = addr & 0xfffffffc;
- uint32_t v = psx_bus_read32(cpu->bus, aligned);
-
- switch (addr & 0x3) {
- case 0: v = (v & 0xffffff00) | (cpu->r[T] >> 24); break;
- case 1: v = (v & 0xffff0000) | (cpu->r[T] >> 16); break;
- case 2: v = (v & 0xff000000) | (cpu->r[T] >> 8 ); break;
- case 3: v = cpu->r[T] ; break;
- }
-
- psx_bus_write32(cpu->bus, aligned, v);
-}
-
-static inline void psx_cpu_i_sw(psx_cpu_t* cpu) {
- TRACE_M("sw");
-
- uint32_t s = cpu->r[S];
- uint32_t t = cpu->r[T];
- uint32_t addr = s + IMM16S;
-
- DO_PENDING_LOAD;
-
- // Cache isolated
- if (cpu->cop0_r[COP0_SR] & SR_ISC) {
- log_debug("Ignoring write while cache is isolated");
-
- return;
- }
-
- if (addr & 0x3) {
- psx_cpu_exception(cpu, CAUSE_ADES);
- } else {
- psx_bus_write32(cpu->bus, addr, t);
- }
-}
-
-static inline void psx_cpu_i_swr(psx_cpu_t* cpu) {
- TRACE_M("swr");
-
- uint32_t s = cpu->r[S];
-
- DO_PENDING_LOAD;
-
- uint32_t addr = s + IMM16S;
- uint32_t aligned = addr & 0xfffffffc;
- uint32_t v = psx_bus_read32(cpu->bus, aligned);
-
- switch (addr & 0x3) {
- case 0: v = cpu->r[T] ; break;
- case 1: v = (v & 0x000000ff) | (cpu->r[T] << 8 ); break;
- case 2: v = (v & 0x0000ffff) | (cpu->r[T] << 16); break;
- case 3: v = (v & 0x00ffffff) | (cpu->r[T] << 24); break;
- }
-
- psx_bus_write32(cpu->bus, aligned, v);
-}
-
-static inline void psx_cpu_i_lwc0(psx_cpu_t* cpu) {
- psx_cpu_exception(cpu, CAUSE_CPU);
-}
-
-static inline void psx_cpu_i_lwc1(psx_cpu_t* cpu) {
- psx_cpu_exception(cpu, CAUSE_CPU);
-}
-
-static inline void psx_cpu_i_lwc3(psx_cpu_t* cpu) {
- psx_cpu_exception(cpu, CAUSE_CPU);
-}
-
-static inline void psx_cpu_i_swc0(psx_cpu_t* cpu) {
- psx_cpu_exception(cpu, CAUSE_CPU);
-}
-
-static inline void psx_cpu_i_swc1(psx_cpu_t* cpu) {
- psx_cpu_exception(cpu, CAUSE_CPU);
-}
-
-static inline void psx_cpu_i_swc3(psx_cpu_t* cpu) {
- psx_cpu_exception(cpu, CAUSE_CPU);
-}
-
-// Secondary
-static inline void psx_cpu_i_sll(psx_cpu_t* cpu) {
- TRACE_I5D("sll");
-
- uint32_t t = cpu->r[T];
-
- DO_PENDING_LOAD;
-
- cpu->r[D] = t << IMM5;
-}
-
-static inline void psx_cpu_i_srl(psx_cpu_t* cpu) {
- TRACE_I5D("srl");
-
- uint32_t t = cpu->r[T];
-
- DO_PENDING_LOAD;
-
- cpu->r[D] = t >> IMM5;
-}
-
-static inline void psx_cpu_i_sra(psx_cpu_t* cpu) {
- TRACE_I5D("sra");
-
- int32_t t = (int32_t)cpu->r[T];
-
- DO_PENDING_LOAD;
-
- cpu->r[D] = t >> IMM5;
-}
-
-static inline void psx_cpu_i_sllv(psx_cpu_t* cpu) {
- TRACE_RT("sllv");
-
- uint32_t s = cpu->r[S];
- uint32_t t = cpu->r[T];
-
- DO_PENDING_LOAD;
-
- cpu->r[D] = t << (s & 0x1f);
-}
-
-static inline void psx_cpu_i_srlv(psx_cpu_t* cpu) {
- TRACE_RT("srlv");
-
- uint32_t s = cpu->r[S];
- uint32_t t = cpu->r[T];
-
- DO_PENDING_LOAD;
-
- cpu->r[D] = t >> (s & 0x1f);
-}
-
-static inline void psx_cpu_i_srav(psx_cpu_t* cpu) {
- TRACE_RT("srav");
-
- uint32_t s = cpu->r[S];
- int32_t t = (int32_t)cpu->r[T];
-
- DO_PENDING_LOAD;
-
- cpu->r[D] = t >> (s & 0x1f);
-}
-
-static inline void psx_cpu_i_jr(psx_cpu_t* cpu) {
- cpu->branch = 1;
-
- TRACE_RS("jr");
-
- uint32_t s = cpu->r[S];
-
- DO_PENDING_LOAD;
-
- cpu->next_pc = s;
-}
-
-static inline void psx_cpu_i_jalr(psx_cpu_t* cpu) {
- cpu->branch = 1;
-
- TRACE_RD("jalr");
-
- uint32_t s = cpu->r[S];
-
- DO_PENDING_LOAD;
-
- cpu->r[D] = cpu->next_pc;
-
- cpu->next_pc = s;
-}
-
-static inline void psx_cpu_i_syscall(psx_cpu_t* cpu) {
- TRACE_I20("syscall");
-
- DO_PENDING_LOAD;
-
- psx_cpu_exception(cpu, CAUSE_SYSCALL);
-}
-
-static inline void psx_cpu_i_break(psx_cpu_t* cpu) {
- TRACE_I20("break");
-
- DO_PENDING_LOAD;
-
- psx_cpu_exception(cpu, CAUSE_BP);
-}
-
-static inline void psx_cpu_i_mfhi(psx_cpu_t* cpu) {
- TRACE_MTF("mfhi");
-
- DO_PENDING_LOAD;
-
- cpu->r[D] = cpu->hi;
-}
-
-static inline void psx_cpu_i_mthi(psx_cpu_t* cpu) {
- TRACE_MTF("mthi");
-
- DO_PENDING_LOAD;
-
- cpu->hi = cpu->r[S];
-}
-
-static inline void psx_cpu_i_mflo(psx_cpu_t* cpu) {
- TRACE_MTF("mflo");
-
- DO_PENDING_LOAD;
-
- cpu->r[D] = cpu->lo;
-}
-
-static inline void psx_cpu_i_mtlo(psx_cpu_t* cpu) {
- TRACE_MTF("mtlo");
-
- DO_PENDING_LOAD;
-
- cpu->lo = cpu->r[S];
-}
-
-static inline void psx_cpu_i_mult(psx_cpu_t* cpu) {
- TRACE_MD("mult");
-
- int64_t s = (int64_t)((int32_t)cpu->r[S]);
- int64_t t = (int64_t)((int32_t)cpu->r[T]);
-
- DO_PENDING_LOAD;
-
- uint64_t r = s * t;
-
- cpu->hi = r >> 32;
- cpu->lo = r & 0xffffffff;
-}
-
-static inline void psx_cpu_i_multu(psx_cpu_t* cpu) {
- TRACE_MD("multu");
-
- uint64_t s = (uint64_t)cpu->r[S];
- uint64_t t = (uint64_t)cpu->r[T];
-
- DO_PENDING_LOAD;
-
- uint64_t r = s * t;
-
- cpu->hi = r >> 32;
- cpu->lo = r & 0xffffffff;
-}
-
-static inline void psx_cpu_i_div(psx_cpu_t* cpu) {
- TRACE_MD("div");
-
- int32_t s = (int32_t)cpu->r[S];
- int32_t t = (int32_t)cpu->r[T];
-
- DO_PENDING_LOAD;
-
- if (!t) {
- cpu->hi = s;
- cpu->lo = (s >= 0) ? 0xffffffff : 1;
- } else if ((((uint32_t)s) == 0x80000000) && (t == -1)) {
- cpu->hi = 0;
- cpu->lo = 0x80000000;
- } else {
- cpu->hi = (uint32_t)(s % t);
- cpu->lo = (uint32_t)(s / t);
- }
-}
-
-static inline void psx_cpu_i_divu(psx_cpu_t* cpu) {
- TRACE_MD("divu");
-
- uint32_t s = cpu->r[S];
- uint32_t t = cpu->r[T];
-
- DO_PENDING_LOAD;
-
- if (!t) {
- cpu->hi = s;
- cpu->lo = 0xffffffff;
- } else {
- cpu->hi = s % t;
- cpu->lo = s / t;
- }
-}
-
-static inline void psx_cpu_i_add(psx_cpu_t* cpu) {
- TRACE_RT("add");
-
- int32_t s = cpu->r[S];
- int32_t t = cpu->r[T];
-
- DO_PENDING_LOAD;
-
- int32_t r = s + t;
- uint32_t o = (s ^ r) & (t ^ r);
-
- if (o & 0x80000000) {
- psx_cpu_exception(cpu, CAUSE_OV);
- } else {
- cpu->r[D] = (uint32_t)r;
- }
-}
-
-static inline void psx_cpu_i_addu(psx_cpu_t* cpu) {
- TRACE_RT("addu");
-
- uint32_t s = cpu->r[S];
- uint32_t t = cpu->r[T];
-
- DO_PENDING_LOAD;
-
- cpu->r[D] = s + t;
-}
-
-static inline void psx_cpu_i_sub(psx_cpu_t* cpu) {
- TRACE_RT("sub");
-
- int32_t s = (int32_t)cpu->r[S];
- int32_t t = (int32_t)cpu->r[T];
- int32_t r;
-
- DO_PENDING_LOAD;
-
- int o = __builtin_ssub_overflow(s, t, &r);
-
- if (o) {
- psx_cpu_exception(cpu, CAUSE_OV);
- } else {
- cpu->r[D] = r;
- }
-}
-
-static inline void psx_cpu_i_subu(psx_cpu_t* cpu) {
- TRACE_RT("subu");
-
- uint32_t s = cpu->r[S];
- uint32_t t = cpu->r[T];
-
- DO_PENDING_LOAD;
-
- cpu->r[D] = s - t;
-}
-
-static inline void psx_cpu_i_and(psx_cpu_t* cpu) {
- TRACE_RT("and");
-
- uint32_t s = cpu->r[S];
- uint32_t t = cpu->r[T];
-
- DO_PENDING_LOAD;
-
- cpu->r[D] = s & t;
-}
-
-static inline void psx_cpu_i_or(psx_cpu_t* cpu) {
- TRACE_RT("or");
-
- uint32_t s = cpu->r[S];
- uint32_t t = cpu->r[T];
-
- DO_PENDING_LOAD;
-
- cpu->r[D] = s | t;
-}
-
-static inline void psx_cpu_i_xor(psx_cpu_t* cpu) {
- TRACE_RT("xor");
-
- uint32_t s = cpu->r[S];
- uint32_t t = cpu->r[T];
-
- DO_PENDING_LOAD;
-
- cpu->r[D] = (s ^ t);
-}
-
-static inline void psx_cpu_i_nor(psx_cpu_t* cpu) {
- TRACE_RT("nor");
-
- uint32_t s = cpu->r[S];
- uint32_t t = cpu->r[T];
-
- DO_PENDING_LOAD;
-
- cpu->r[D] = ~(s | t);
-}
-
-static inline void psx_cpu_i_slt(psx_cpu_t* cpu) {
- TRACE_RT("slt");
-
- int32_t s = (int32_t)cpu->r[S];
- int32_t t = (int32_t)cpu->r[T];
-
- DO_PENDING_LOAD;
-
- cpu->r[D] = s < t;
-}
-
-static inline void psx_cpu_i_sltu(psx_cpu_t* cpu) {
- TRACE_RT("sltu");
-
- uint32_t s = cpu->r[S];
- uint32_t t = cpu->r[T];
-
- DO_PENDING_LOAD;
-
- cpu->r[D] = s < t;
-}
-
-// COP0
-static inline void psx_cpu_i_mfc0(psx_cpu_t* cpu) {
- TRACE_C0M("mfc0");
-
- DO_PENDING_LOAD;
-
- cpu->load_v = cpu->cop0_r[D];
- cpu->load_d = T;
-}
-
-static inline void psx_cpu_i_mtc0(psx_cpu_t* cpu) {
- TRACE_C0M("mtc0");
-
- uint32_t t = cpu->r[T];
-
- DO_PENDING_LOAD;
-
- cpu->cop0_r[D] = t & g_psx_cpu_cop0_write_mask_table[D];
-}
-
-static inline void psx_cpu_i_rfe(psx_cpu_t* cpu) {
- TRACE_N("rfe");
-
- DO_PENDING_LOAD;
-
- uint32_t mode = cpu->cop0_r[COP0_SR] & 0x3f;
-
- cpu->cop0_r[COP0_SR] &= 0xfffffff0;
- cpu->cop0_r[COP0_SR] |= mode >> 2;
-}
-
-// COP2
-#define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#define CLAMP(v, a, b) (((v) < (a)) ? (a) : (((v) > (b)) ? (b) : (v)))
-
-static inline void gte_handle_irgb_write(psx_cpu_t* cpu) {
- cpu->cop2_dr.ir[1] = ((cpu->cop2_dr.irgb >> 0) & 0x1f) * 0x80;
- cpu->cop2_dr.ir[2] = ((cpu->cop2_dr.irgb >> 5) & 0x1f) * 0x80;
- cpu->cop2_dr.ir[3] = ((cpu->cop2_dr.irgb >> 10) & 0x1f) * 0x80;
-}
-
-static inline void gte_handle_irgb_read(psx_cpu_t* cpu) {
- int r = CLAMP(cpu->cop2_dr.ir[1] >> 7, 0x00, 0x1f);
- int g = CLAMP(cpu->cop2_dr.ir[2] >> 7, 0x00, 0x1f);
- int b = CLAMP(cpu->cop2_dr.ir[3] >> 7, 0x00, 0x1f);
-
- cpu->cop2_dr.irgb = r | (g << 5) | (b << 10);
-}
-
-static inline void gte_handle_sxyp_write(psx_cpu_t* cpu) {
- cpu->cop2_dr.sxy[0] = cpu->cop2_dr.sxy[1];
- cpu->cop2_dr.sxy[1] = cpu->cop2_dr.sxy[2];
- cpu->cop2_dr.sxy[2] = cpu->cop2_dr.sxy[3];
-}
-
-static inline void gte_handle_lzcs_write(psx_cpu_t* cpu) {
- if ((cpu->cop2_dr.lzcs == 0xffffffff) || !cpu->cop2_dr.lzcs) {
- cpu->cop2_dr.lzcr = 32;
-
- return;
- }
-
- int b = (cpu->cop2_dr.lzcs >> 31) & 1;
-
- cpu->cop2_dr.lzcr = __builtin_clz(b ? ~cpu->cop2_dr.lzcs : cpu->cop2_dr.lzcs);
-}
-
-uint32_t gte_read_register(psx_cpu_t* cpu, uint32_t r) {
- switch (r) {
- case 0 : return cpu->cop2_dr.v[0].xy;
- case 1 : return (int32_t)cpu->cop2_dr.v[0].z;
- case 2 : return cpu->cop2_dr.v[1].xy;
- case 3 : return (int32_t)cpu->cop2_dr.v[1].z;
- case 4 : return cpu->cop2_dr.v[2].xy;
- case 5 : return (int32_t)cpu->cop2_dr.v[2].z;
- case 6 : return cpu->cop2_dr.rgbc.rgbc;
- case 7 : return cpu->cop2_dr.otz;
- case 8 : return (int32_t)cpu->cop2_dr.ir[0];
- case 9 : return (int32_t)cpu->cop2_dr.ir[1];
- case 10: return (int32_t)cpu->cop2_dr.ir[2];
- case 11: return (int32_t)cpu->cop2_dr.ir[3];
- case 12: return cpu->cop2_dr.sxy[0].xy;
- case 13: return cpu->cop2_dr.sxy[1].xy;
- case 14: return cpu->cop2_dr.sxy[2].xy;
- case 15: return cpu->cop2_dr.sxy[2].xy; // SXY2 Mirror
- case 16: return cpu->cop2_dr.sz[0];
- case 17: return cpu->cop2_dr.sz[1];
- case 18: return cpu->cop2_dr.sz[2];
- case 19: return cpu->cop2_dr.sz[3];
- case 20: return cpu->cop2_dr.rgb[0].rgbc;
- case 21: return cpu->cop2_dr.rgb[1].rgbc;
- case 22: return cpu->cop2_dr.rgb[2].rgbc;
- case 23: return cpu->cop2_dr.res1;
- case 24: return cpu->cop2_dr.mac[0];
- case 25: return cpu->cop2_dr.mac[1];
- case 26: return cpu->cop2_dr.mac[2];
- case 27: return cpu->cop2_dr.mac[3];
- case 28: gte_handle_irgb_read(cpu); return cpu->cop2_dr.irgb;
- case 29: return cpu->cop2_dr.irgb; // IRGB mirror
- case 30: return cpu->cop2_dr.lzcs;
- case 31: return cpu->cop2_dr.lzcr;
- case 32: return cpu->cop2_cr.rt.m[0].u32;
- case 33: return cpu->cop2_cr.rt.m[1].u32;
- case 34: return cpu->cop2_cr.rt.m[2].u32;
- case 35: return cpu->cop2_cr.rt.m[3].u32;
- case 36: return (int32_t)cpu->cop2_cr.rt.m33;
- case 37: return cpu->cop2_cr.tr.x;
- case 38: return cpu->cop2_cr.tr.y;
- case 39: return cpu->cop2_cr.tr.z;
- case 40: return cpu->cop2_cr.l.m[0].u32;
- case 41: return cpu->cop2_cr.l.m[1].u32;
- case 42: return cpu->cop2_cr.l.m[2].u32;
- case 43: return cpu->cop2_cr.l.m[3].u32;
- case 44: return (int32_t)cpu->cop2_cr.l.m33;
- case 45: return cpu->cop2_cr.bk.x;
- case 46: return cpu->cop2_cr.bk.y;
- case 47: return cpu->cop2_cr.bk.z;
- case 48: return cpu->cop2_cr.lr.m[0].u32;
- case 49: return cpu->cop2_cr.lr.m[1].u32;
- case 50: return cpu->cop2_cr.lr.m[2].u32;
- case 51: return cpu->cop2_cr.lr.m[3].u32;
- case 52: return (int32_t)cpu->cop2_cr.lr.m33;
- case 53: return cpu->cop2_cr.fc.x;
- case 54: return cpu->cop2_cr.fc.y;
- case 55: return cpu->cop2_cr.fc.z;
- case 56: return cpu->cop2_cr.ofx;
- case 57: return cpu->cop2_cr.ofy;
- case 58: return (int32_t)(int16_t)cpu->cop2_cr.h;
- case 59: return cpu->cop2_cr.dqa;
- case 60: return cpu->cop2_cr.dqb;
- case 61: return cpu->cop2_cr.zsf3;
- case 62: return cpu->cop2_cr.zsf4;
- case 63: return (cpu->cop2_cr.flag & 0x7ffff000) |
- (((cpu->cop2_cr.flag & 0x7f87e000) != 0) << 31);
- }
-
- return 0x00000000;
-}
-
-static inline void gte_write_register(psx_cpu_t* cpu, uint32_t r, uint32_t value) {
- switch (r) {
- case 0 : cpu->cop2_dr.v[0].xy = value; break;
- case 1 : cpu->cop2_dr.v[0].z = value; break;
- case 2 : cpu->cop2_dr.v[1].xy = value; break;
- case 3 : cpu->cop2_dr.v[1].z = value; break;
- case 4 : cpu->cop2_dr.v[2].xy = value; break;
- case 5 : cpu->cop2_dr.v[2].z = value; break;
- case 6 : cpu->cop2_dr.rgbc.rgbc = value; break;
- case 7 : cpu->cop2_dr.otz = value; break;
- case 8 : cpu->cop2_dr.ir[0] = value; break;
- case 9 : cpu->cop2_dr.ir[1] = value; break;
- case 10: cpu->cop2_dr.ir[2] = value; break;
- case 11: cpu->cop2_dr.ir[3] = value; break;
- case 12: cpu->cop2_dr.sxy[0].xy = value; break;
- case 13: cpu->cop2_dr.sxy[1].xy = value; break;
- case 14: cpu->cop2_dr.sxy[2].xy = value; break;
- case 15: cpu->cop2_dr.sxy[3].xy = value; gte_handle_sxyp_write(cpu); break;
- case 16: cpu->cop2_dr.sz[0] = value; break;
- case 17: cpu->cop2_dr.sz[1] = value; break;
- case 18: cpu->cop2_dr.sz[2] = value; break;
- case 19: cpu->cop2_dr.sz[3] = value; break;
- case 20: cpu->cop2_dr.rgb[0].rgbc = value; break;
- case 21: cpu->cop2_dr.rgb[1].rgbc = value; break;
- case 22: cpu->cop2_dr.rgb[2].rgbc = value; break;
- case 23: cpu->cop2_dr.res1 = value; break;
- case 24: cpu->cop2_dr.mac[0] = value; break;
- case 25: cpu->cop2_dr.mac[1] = value; break;
- case 26: cpu->cop2_dr.mac[2] = value; break;
- case 27: cpu->cop2_dr.mac[3] = value; break;
- case 28: cpu->cop2_dr.irgb = value & 0x7fff; gte_handle_irgb_write(cpu); break;
- case 29: /* ORGB RO */ break;
- case 30: cpu->cop2_dr.lzcs = value; gte_handle_lzcs_write(cpu); break;
- case 31: /* LZCR RO */ break;
- case 32: cpu->cop2_cr.rt.m[0].u32 = value; break;
- case 33: cpu->cop2_cr.rt.m[1].u32 = value; break;
- case 34: cpu->cop2_cr.rt.m[2].u32 = value; break;
- case 35: cpu->cop2_cr.rt.m[3].u32 = value; break;
- case 36: cpu->cop2_cr.rt.m33 = value; break;
- case 37: cpu->cop2_cr.tr.x = value; break;
- case 38: cpu->cop2_cr.tr.y = value; break;
- case 39: cpu->cop2_cr.tr.z = value; break;
- case 40: cpu->cop2_cr.l.m[0].u32 = value; break;
- case 41: cpu->cop2_cr.l.m[1].u32 = value; break;
- case 42: cpu->cop2_cr.l.m[2].u32 = value; break;
- case 43: cpu->cop2_cr.l.m[3].u32 = value; break;
- case 44: cpu->cop2_cr.l.m33 = value; break;
- case 45: cpu->cop2_cr.bk.x = value; break;
- case 46: cpu->cop2_cr.bk.y = value; break;
- case 47: cpu->cop2_cr.bk.z = value; break;
- case 48: cpu->cop2_cr.lr.m[0].u32 = value; break;
- case 49: cpu->cop2_cr.lr.m[1].u32 = value; break;
- case 50: cpu->cop2_cr.lr.m[2].u32 = value; break;
- case 51: cpu->cop2_cr.lr.m[3].u32 = value; break;
- case 52: cpu->cop2_cr.lr.m33 = value; break;
- case 53: cpu->cop2_cr.fc.x = value; break;
- case 54: cpu->cop2_cr.fc.y = value; break;
- case 55: cpu->cop2_cr.fc.z = value; break;
- case 56: cpu->cop2_cr.ofx = value; break;
- case 57: cpu->cop2_cr.ofy = value; break;
- case 58: cpu->cop2_cr.h = value; break;
- case 59: cpu->cop2_cr.dqa = value; break;
- case 60: cpu->cop2_cr.dqb = value; break;
- case 61: cpu->cop2_cr.zsf3 = value; break;
- case 62: cpu->cop2_cr.zsf4 = value; break;
- case 63: cpu->cop2_cr.flag = value & 0x7ffff000; break;
- }
-}
-
-static inline void psx_cpu_i_lwc2(psx_cpu_t* cpu) {
- uint32_t s = cpu->r[S];
- uint32_t addr = s + IMM16S;
-
- DO_PENDING_LOAD;
-
- if (addr & 0x3) {
- psx_cpu_exception(cpu, CAUSE_ADEL);
- } else {
- gte_write_register(cpu, T, psx_bus_read32(cpu->bus, addr));
- }
-}
-
-static inline void psx_cpu_i_swc2(psx_cpu_t* cpu) {
- uint32_t s = cpu->r[S];
- uint32_t addr = s + IMM16S;
-
- DO_PENDING_LOAD;
-
- // Cache isolated
- if (cpu->cop0_r[COP0_SR] & SR_ISC) {
- log_debug("Ignoring write while cache is isolated");
-
- return;
- }
-
- if (addr & 0x3) {
- psx_cpu_exception(cpu, CAUSE_ADES);
- } else {
- psx_bus_write32(cpu->bus, addr, gte_read_register(cpu, T));
- }
-}
-
-static inline void psx_cpu_i_mfc2(psx_cpu_t* cpu) {
- TRACE_C2M("mfc2");
-
- DO_PENDING_LOAD;
-
- cpu->load_v = gte_read_register(cpu, D);
- cpu->load_d = T;
-}
-
-static inline void psx_cpu_i_cfc2(psx_cpu_t* cpu) {
- TRACE_C2MC("cfc2");
-
- DO_PENDING_LOAD;
-
- cpu->load_v = gte_read_register(cpu, D + 32);
- cpu->load_d = T;
-}
-
-static inline void psx_cpu_i_mtc2(psx_cpu_t* cpu) {
- TRACE_C2M("mtc2");
-
- uint32_t t = cpu->r[T];
-
- DO_PENDING_LOAD;
-
- gte_write_register(cpu, D, t);
-}
-
-static inline void psx_cpu_i_ctc2(psx_cpu_t* cpu) {
- TRACE_C2MC("ctc2");
-
- uint32_t t = cpu->r[T];
-
- DO_PENDING_LOAD;
-
- gte_write_register(cpu, D + 32, t);
-}
-
-#define R_FLAG cpu->cop2_cr.flag
-
-static inline int64_t gte_clamp_mac0(psx_cpu_t* cpu, int64_t value) {
- cpu->s_mac0 = value;
-
- if (value < (-0x80000000ll)) {
- R_FLAG |= 0x8000;
- } else if (value > (0x7fffffffll)) {
- R_FLAG |= 0x10000;
- }
-
- return value;
-}
-
-static inline int32_t gte_clamp_mac(psx_cpu_t* cpu, int i, int64_t value) {
- if (i == 3)
- cpu->s_mac3 = value;
-
- if (value < -0x80000000000ll) {
- R_FLAG |= 0x8000000 >> (i - 1);
- } else if (value > 0x7ffffffffffll) {
- R_FLAG |= 0x40000000 >> (i - 1);
- }
-
- return (int32_t)(((value << 20) >> 20) >> cpu->gte_sf);
-}
-
-static inline int64_t gte_check_mac(psx_cpu_t* cpu, int i, int64_t value) {
- if (value < -0x80000000000ll) {
- R_FLAG |= 0x8000000 >> (i - 1);
- } else if (value > 0x7ffffffffffll) {
- R_FLAG |= 0x40000000 >> (i - 1);
- }
-
- return (value << 20) >> 20;
-}
-
-static inline int32_t gte_clamp_ir0(psx_cpu_t* cpu, int32_t value) {
- if (value < 0) {
- R_FLAG |= 0x1000;
-
- return 0;
- } else if (value > 0x1000) {
- R_FLAG |= 0x1000;
-
- return 0x1000;
- }
-
- return value;
-}
-
-static inline int64_t gte_clamp_sxy(psx_cpu_t* cpu, int i, int64_t value) {
- if (value < -0x400) {
- R_FLAG |= (uint32_t)(0x4000 >> (i - 1));
-
- return -0x400;
- } else if (value > 0x3ff) {
- R_FLAG |= (uint32_t)(0x4000 >> (i - 1));
-
- return 0x3ff;
- }
-
- return value;
-}
-
-static inline int32_t gte_clamp_sz3(psx_cpu_t* cpu, int32_t value) {
- if (value < 0) {
- R_FLAG |= 0x40000;
-
- return 0;
- } else if (value > 0xffff) {
- R_FLAG |= 0x40000;
-
- return 0xffff;
- }
-
- return value;
-}
-
-static inline uint8_t gte_clamp_rgb(psx_cpu_t* cpu, int i, int value) {
- if (value < 0) {
- R_FLAG |= (uint32_t)0x200000 >> (i - 1);
-
- return 0;
- } else if (value > 0xff) {
- R_FLAG |= (uint32_t)0x200000 >> (i - 1);
-
- return 0xff;
- }
-
- return (uint8_t)value;
-}
-
-static inline int32_t gte_clamp_ir(psx_cpu_t* cpu, int i, int64_t value, int lm) {
- if (lm && (value < 0)) {
- R_FLAG |= (uint32_t)(0x1000000 >> (i - 1));
-
- return 0;
- } else if ((value < -0x8000) && !lm) {
- R_FLAG |= (uint32_t)(0x1000000 >> (i - 1));
-
- return -0x8000;
- } else if (value > 0x7fff) {
- R_FLAG |= (uint32_t)(0x1000000 >> (i - 1));
-
- return 0x7fff;
- }
-
- return (int32_t)value;
-}
-
-static inline int32_t gte_clamp_ir_z(psx_cpu_t* cpu, int64_t value, int sf, int lm) {
- int32_t value_sf = value >> sf;
- int32_t value_12 = value >> 12;
- int32_t min = 0;
-
- if (lm == 0)
- min = -((int32_t)0x8000);
-
- if (value_12 < (-((int32_t)0x8000)) || value_12 > 0x7fffl)
- R_FLAG |= (1 << 22);
-
- return (int32_t)CLAMP(value_sf, min, 0x7fffl);
-}
-
-static inline int clz(uint32_t value) {
- if (!value)
- return 32;
-
- return __builtin_clz(value);
-}
-
-static inline uint32_t gte_divide(psx_cpu_t* cpu, uint16_t n, uint16_t d) {
- // Overflow
- if (n >= d * 2) {
- R_FLAG |= (1 << 31) | (1 << 17);
-
- return 0x1ffff;
- }
-
- int shift = clz(d) - 16;
-
- int r1 = (d << shift) & 0x7fff;
- int r2 = g_psx_gte_unr_table[((r1 + 0x40) >> 7)] + 0x101;
- int r3 = ((0x80 - (r2 * (r1 + 0x8000))) >> 8) & 0x1ffff;
-
- uint32_t reciprocal = ((r2 * r3) + 0x80) >> 8;
- uint32_t res = ((((uint64_t)reciprocal * (n << shift)) + 0x8000) >> 16);
-
- return MIN(0x1ffff, res);
-}
-
-static inline void psx_gte_i_invalid(psx_cpu_t* cpu) {
- log_fatal("invalid: Unimplemented GTE instruction %02x, %02x", cpu->opcode & 0x3f, cpu->opcode >> 25);
-}
-
-#define I64(v) ((int64_t)v)
-#define R_TRX cpu->cop2_cr.tr.x
-#define R_TRY cpu->cop2_cr.tr.y
-#define R_TRZ cpu->cop2_cr.tr.z
+
+ psx_cpu_exception(cpu, CAUSE_RI);
+ }
+
+ cpu->last_cycles += cyc;
+ cpu->total_cycles += cpu->last_cycles;
+
+ cpu->r[0] = 0;
+}
+
+void psx_cpu_set_irq_pending(psx_cpu_t* cpu) {+ cpu->cop0_r[COP0_CAUSE] |= SR_IM2;
+}
+
+static inline void psx_cpu_i_invalid(psx_cpu_t* cpu) {+ log_fatal("%08x: Illegal instruction %08x", cpu->pc - 8, cpu->opcode);+
+ psx_cpu_exception(cpu, CAUSE_RI);
+}
+
+// BXX
+static inline void psx_cpu_i_bltz(psx_cpu_t* cpu) {+ TRACE_B("bltz");+
+ int32_t s = (int32_t)cpu->r[S];
+
+ DO_PENDING_LOAD;
+
+ if ((int32_t)s < (int32_t)0)
+ BRANCH(IMM16S << 2);
+}
+
+static inline void psx_cpu_i_bgez(psx_cpu_t* cpu) {+ TRACE_B("bgez");+
+ int32_t s = (int32_t)cpu->r[S];
+
+ DO_PENDING_LOAD;
+
+ if ((int32_t)s >= (int32_t)0)
+ BRANCH(IMM16S << 2);
+}
+
+static inline void psx_cpu_i_bltzal(psx_cpu_t* cpu) {+ TRACE_B("bltzal");+
+ int32_t s = (int32_t)cpu->r[S];
+
+ DO_PENDING_LOAD;
+
+ R_RA = cpu->next_pc;
+
+ if ((int32_t)s < (int32_t)0)
+ BRANCH(IMM16S << 2);
+}
+
+static inline void psx_cpu_i_bgezal(psx_cpu_t* cpu) {+ TRACE_B("bgezal");+
+ int32_t s = (int32_t)cpu->r[S];
+
+ DO_PENDING_LOAD;
+
+ R_RA = cpu->next_pc;
+
+ if ((int32_t)s >= (int32_t)0)
+ BRANCH(IMM16S << 2);
+}
+
+static inline void psx_cpu_i_j(psx_cpu_t* cpu) {+ cpu->branch = 1;
+
+ TRACE_I26("j");+
+ DO_PENDING_LOAD;
+
+ cpu->next_pc = (cpu->next_pc & 0xf0000000) | (IMM26 << 2);
+}
+
+static inline void psx_cpu_i_jal(psx_cpu_t* cpu) {+ cpu->branch = 1;
+
+ TRACE_I26("jal");+
+ DO_PENDING_LOAD;
+
+ R_RA = cpu->next_pc;
+
+ cpu->next_pc = (cpu->next_pc & 0xf0000000) | (IMM26 << 2);
+}
+
+static inline void psx_cpu_i_beq(psx_cpu_t* cpu) {+ cpu->branch = 1;
+ cpu->branch_taken = 0;
+
+ TRACE_B("beq");+
+ uint32_t s = cpu->r[S];
+ uint32_t t = cpu->r[T];
+
+ DO_PENDING_LOAD;
+
+ if (s == t)
+ BRANCH(IMM16S << 2);
+}
+
+static inline void psx_cpu_i_bne(psx_cpu_t* cpu) {+ cpu->branch = 1;
+ cpu->branch_taken = 0;
+
+ TRACE_B("bne");+
+ uint32_t s = cpu->r[S];
+ uint32_t t = cpu->r[T];
+
+ DO_PENDING_LOAD;
+
+ if (s != t)
+ BRANCH(IMM16S << 2);
+}
+
+static inline void psx_cpu_i_blez(psx_cpu_t* cpu) {+ cpu->branch = 1;
+ cpu->branch_taken = 0;
+
+ TRACE_B("blez");+
+ int32_t s = (int32_t)cpu->r[S];
+
+ DO_PENDING_LOAD;
+
+ if ((int32_t)s <= (int32_t)0)
+ BRANCH(IMM16S << 2);
+}
+
+static inline void psx_cpu_i_bgtz(psx_cpu_t* cpu) {+ cpu->branch = 1;
+ cpu->branch_taken = 0;
+
+ TRACE_B("bgtz");+
+ int32_t s = (int32_t)cpu->r[S];
+
+ DO_PENDING_LOAD;
+
+ if ((int32_t)s > (int32_t)0)
+ BRANCH(IMM16S << 2);
+}
+
+static inline void psx_cpu_i_addi(psx_cpu_t* cpu) {+ TRACE_I16D("addi");+
+ uint32_t s = cpu->r[S];
+
+ DO_PENDING_LOAD;
+
+ uint32_t i = IMM16S;
+ uint32_t r = s + i;
+ uint32_t o = (s ^ r) & (i ^ r);
+
+ if (o & 0x80000000) {+ psx_cpu_exception(cpu, CAUSE_OV);
+ } else {+ cpu->r[T] = r;
+ }
+}
+
+static inline void psx_cpu_i_addiu(psx_cpu_t* cpu) {+ TRACE_I16D("addiu");+
+ uint32_t s = cpu->r[S];
+
+ DO_PENDING_LOAD;
+
+ cpu->r[T] = s + IMM16S;
+}
+
+static inline void psx_cpu_i_slti(psx_cpu_t* cpu) {+ TRACE_I16D("slti");+
+ int32_t s = (int32_t)cpu->r[S];
+
+ DO_PENDING_LOAD;
+
+ cpu->r[T] = s < IMM16S;
+}
+
+static inline void psx_cpu_i_sltiu(psx_cpu_t* cpu) {+ TRACE_I16D("sltiu");+
+ uint32_t s = cpu->r[S];
+
+ DO_PENDING_LOAD;
+
+ cpu->r[T] = s < IMM16S;
+}
+
+static inline void psx_cpu_i_andi(psx_cpu_t* cpu) {+ TRACE_I16D("andi");+
+ uint32_t s = cpu->r[S];
+
+ DO_PENDING_LOAD;
+
+ cpu->r[T] = s & IMM16;
+}
+
+static inline void psx_cpu_i_ori(psx_cpu_t* cpu) {+ TRACE_I16D("ori");+
+ uint32_t s = cpu->r[S];
+
+ DO_PENDING_LOAD;
+
+ cpu->r[T] = s | IMM16;
+}
+
+static inline void psx_cpu_i_xori(psx_cpu_t* cpu) {+ TRACE_I16D("xori");+
+ uint32_t s = cpu->r[S];
+
+ DO_PENDING_LOAD;
+
+ cpu->r[T] = s ^ IMM16;
+}
+
+static inline void psx_cpu_i_lui(psx_cpu_t* cpu) {+ TRACE_I16S("lui");+
+ DO_PENDING_LOAD;
+
+ cpu->r[T] = IMM16 << 16;
+}
+
+static inline void psx_cpu_i_lb(psx_cpu_t* cpu) {+ TRACE_M("lb");+
+ uint32_t s = cpu->r[S];
+
+ if (cpu->load_d != T)
+ DO_PENDING_LOAD;
+
+ cpu->load_d = T;
+ cpu->load_v = SE8(psx_bus_read8(cpu->bus, s + IMM16S));
+}
+
+static inline void psx_cpu_i_lh(psx_cpu_t* cpu) {+ TRACE_M("lh");+
+ uint32_t s = cpu->r[S];
+
+ if (cpu->load_d != T)
+ DO_PENDING_LOAD;
+
+ uint32_t addr = s + IMM16S;
+
+ if (addr & 0x1) {+ psx_cpu_exception(cpu, CAUSE_ADEL);
+ } else {+ cpu->load_d = T;
+ cpu->load_v = SE16(psx_bus_read16(cpu->bus, addr));
+ }
+}
+
+static inline void psx_cpu_i_lwl(psx_cpu_t* cpu) {+ TRACE_M("lwl");+
+ uint32_t rt = T;
+ uint32_t s = cpu->r[S];
+ uint32_t t = cpu->r[rt];
+
+ uint32_t addr = s + IMM16S;
+ uint32_t load = psx_bus_read32(cpu->bus, addr & 0xfffffffc);
+
+ if (rt == cpu->load_d) {+ t = cpu->load_v;
+ } else {+ DO_PENDING_LOAD;
+ }
+
+ int shift = (int)((addr & 0x3) << 3);
+ uint32_t mask = (uint32_t)0x00FFFFFF >> shift;
+ uint32_t value = (t & mask) | (load << (24 - shift));
+
+ cpu->load_d = rt;
+ cpu->load_v = value;
+
+ // printf("lwl rt=%u s=%08x t=%08x addr=%08x load=%08x (%08x) shift=%u mask=%08x value=%08x\n",+ // rt, s, t, addr, load, addr & 0xfffffffc, shift, mask, value
+ // );
+}
+
+static inline void psx_cpu_i_lw(psx_cpu_t* cpu) {+ TRACE_M("lw");+
+ uint32_t s = cpu->r[S];
+ uint32_t addr = s + IMM16S;
+
+ if (cpu->load_d != T)
+ DO_PENDING_LOAD;
+
+ if (addr & 0x3) {+ psx_cpu_exception(cpu, CAUSE_ADEL);
+ } else {+ cpu->load_d = T;
+ cpu->load_v = psx_bus_read32(cpu->bus, addr);
+ }
+}
+
+static inline void psx_cpu_i_lbu(psx_cpu_t* cpu) {+ TRACE_M("lbu");+
+ uint32_t s = cpu->r[S];
+
+ if (cpu->load_d != T)
+ DO_PENDING_LOAD;
+
+ cpu->load_d = T;
+ cpu->load_v = psx_bus_read8(cpu->bus, s + IMM16S);
+}
+
+static inline void psx_cpu_i_lhu(psx_cpu_t* cpu) {+ TRACE_M("lhu");+
+ uint32_t s = cpu->r[S];
+ uint32_t addr = s + IMM16S;
+
+ if (cpu->load_d != T)
+ DO_PENDING_LOAD;
+
+ if (addr & 0x1) {+ psx_cpu_exception(cpu, CAUSE_ADEL);
+ } else {+ cpu->load_d = T;
+ cpu->load_v = psx_bus_read16(cpu->bus, addr);
+ }
+}
+
+static inline void psx_cpu_i_lwr(psx_cpu_t* cpu) {+ TRACE_M("lwr");+
+ uint32_t rt = T;
+ uint32_t s = cpu->r[S];
+ uint32_t t = cpu->r[rt];
+
+ uint32_t addr = s + IMM16S;
+ uint32_t load = psx_bus_read32(cpu->bus, addr & 0xfffffffc);
+
+ if (rt == cpu->load_d) {+ t = cpu->load_v;
+ } else {+ DO_PENDING_LOAD;
+ }
+
+ int shift = (int)((addr & 0x3) << 3);
+ uint32_t mask = 0xFFFFFF00 << (24 - shift);
+ uint32_t value = (t & mask) | (load >> shift);
+
+ cpu->load_d = rt;
+ cpu->load_v = value;
+
+ // printf("lwr rt=%u s=%08x t=%08x addr=%08x load=%08x (%08x) shift=%u mask=%08x value=%08x\n",+ // rt, s, t, addr, load, addr & 0xfffffffc, shift, mask, value
+ // );
+}
+
+static inline void psx_cpu_i_sb(psx_cpu_t* cpu) {+ TRACE_M("sb");+
+ uint32_t s = cpu->r[S];
+ uint32_t t = cpu->r[T];
+
+ DO_PENDING_LOAD;
+
+ // Cache isolated
+ if (cpu->cop0_r[COP0_SR] & SR_ISC) {+ log_debug("Ignoring write while cache is isolated");+
+ return;
+ }
+
+ psx_bus_write8(cpu->bus, s + IMM16S, t);
+}
+
+static inline void psx_cpu_i_sh(psx_cpu_t* cpu) {+ TRACE_M("sh");+
+ uint32_t s = cpu->r[S];
+ uint32_t t = cpu->r[T];
+ uint32_t addr = s + IMM16S;
+
+ DO_PENDING_LOAD;
+
+ // Cache isolated
+ if (cpu->cop0_r[COP0_SR] & SR_ISC) {+ log_debug("Ignoring write while cache is isolated");+
+ return;
+ }
+
+ if (addr & 0x1) {+ psx_cpu_exception(cpu, CAUSE_ADES);
+ } else {+ psx_bus_write16(cpu->bus, addr, t);
+ }
+}
+
+static inline void psx_cpu_i_swl(psx_cpu_t* cpu) {+ TRACE_M("swl");+
+ uint32_t s = cpu->r[S];
+
+ DO_PENDING_LOAD;
+
+ uint32_t addr = s + IMM16S;
+ uint32_t aligned = addr & 0xfffffffc;
+ uint32_t v = psx_bus_read32(cpu->bus, aligned);
+
+ switch (addr & 0x3) {+ case 0: v = (v & 0xffffff00) | (cpu->r[T] >> 24); break;
+ case 1: v = (v & 0xffff0000) | (cpu->r[T] >> 16); break;
+ case 2: v = (v & 0xff000000) | (cpu->r[T] >> 8 ); break;
+ case 3: v = cpu->r[T] ; break;
+ }
+
+ psx_bus_write32(cpu->bus, aligned, v);
+}
+
+static inline void psx_cpu_i_sw(psx_cpu_t* cpu) {+ TRACE_M("sw");+
+ uint32_t s = cpu->r[S];
+ uint32_t t = cpu->r[T];
+ uint32_t addr = s + IMM16S;
+
+ DO_PENDING_LOAD;
+
+ // Cache isolated
+ if (cpu->cop0_r[COP0_SR] & SR_ISC) {+ log_debug("Ignoring write while cache is isolated");+
+ return;
+ }
+
+ if (addr & 0x3) {+ psx_cpu_exception(cpu, CAUSE_ADES);
+ } else {+ psx_bus_write32(cpu->bus, addr, t);
+ }
+}
+
+static inline void psx_cpu_i_swr(psx_cpu_t* cpu) {+ TRACE_M("swr");+
+ uint32_t s = cpu->r[S];
+
+ DO_PENDING_LOAD;
+
+ uint32_t addr = s + IMM16S;
+ uint32_t aligned = addr & 0xfffffffc;
+ uint32_t v = psx_bus_read32(cpu->bus, aligned);
+
+ switch (addr & 0x3) {+ case 0: v = cpu->r[T] ; break;
+ case 1: v = (v & 0x000000ff) | (cpu->r[T] << 8 ); break;
+ case 2: v = (v & 0x0000ffff) | (cpu->r[T] << 16); break;
+ case 3: v = (v & 0x00ffffff) | (cpu->r[T] << 24); break;
+ }
+
+ psx_bus_write32(cpu->bus, aligned, v);
+}
+
+static inline void psx_cpu_i_lwc0(psx_cpu_t* cpu) {+ psx_cpu_exception(cpu, CAUSE_CPU);
+}
+
+static inline void psx_cpu_i_lwc1(psx_cpu_t* cpu) {+ psx_cpu_exception(cpu, CAUSE_CPU);
+}
+
+static inline void psx_cpu_i_lwc3(psx_cpu_t* cpu) {+ psx_cpu_exception(cpu, CAUSE_CPU);
+}
+
+static inline void psx_cpu_i_swc0(psx_cpu_t* cpu) {+ psx_cpu_exception(cpu, CAUSE_CPU);
+}
+
+static inline void psx_cpu_i_swc1(psx_cpu_t* cpu) {+ psx_cpu_exception(cpu, CAUSE_CPU);
+}
+
+static inline void psx_cpu_i_swc3(psx_cpu_t* cpu) {+ psx_cpu_exception(cpu, CAUSE_CPU);
+}
+
+// Secondary
+static inline void psx_cpu_i_sll(psx_cpu_t* cpu) {+ TRACE_I5D("sll");+
+ uint32_t t = cpu->r[T];
+
+ DO_PENDING_LOAD;
+
+ cpu->r[D] = t << IMM5;
+}
+
+static inline void psx_cpu_i_srl(psx_cpu_t* cpu) {+ TRACE_I5D("srl");+
+ uint32_t t = cpu->r[T];
+
+ DO_PENDING_LOAD;
+
+ cpu->r[D] = t >> IMM5;
+}
+
+static inline void psx_cpu_i_sra(psx_cpu_t* cpu) {+ TRACE_I5D("sra");+
+ int32_t t = (int32_t)cpu->r[T];
+
+ DO_PENDING_LOAD;
+
+ cpu->r[D] = t >> IMM5;
+}
+
+static inline void psx_cpu_i_sllv(psx_cpu_t* cpu) {+ TRACE_RT("sllv");+
+ uint32_t s = cpu->r[S];
+ uint32_t t = cpu->r[T];
+
+ DO_PENDING_LOAD;
+
+ cpu->r[D] = t << (s & 0x1f);
+}
+
+static inline void psx_cpu_i_srlv(psx_cpu_t* cpu) {+ TRACE_RT("srlv");+
+ uint32_t s = cpu->r[S];
+ uint32_t t = cpu->r[T];
+
+ DO_PENDING_LOAD;
+
+ cpu->r[D] = t >> (s & 0x1f);
+}
+
+static inline void psx_cpu_i_srav(psx_cpu_t* cpu) {+ TRACE_RT("srav");+
+ uint32_t s = cpu->r[S];
+ int32_t t = (int32_t)cpu->r[T];
+
+ DO_PENDING_LOAD;
+
+ cpu->r[D] = t >> (s & 0x1f);
+}
+
+static inline void psx_cpu_i_jr(psx_cpu_t* cpu) {+ cpu->branch = 1;
+
+ TRACE_RS("jr");+
+ uint32_t s = cpu->r[S];
+
+ DO_PENDING_LOAD;
+
+ cpu->next_pc = s;
+}
+
+static inline void psx_cpu_i_jalr(psx_cpu_t* cpu) {+ cpu->branch = 1;
+
+ TRACE_RD("jalr");+
+ uint32_t s = cpu->r[S];
+
+ DO_PENDING_LOAD;
+
+ cpu->r[D] = cpu->next_pc;
+
+ cpu->next_pc = s;
+}
+
+static inline void psx_cpu_i_syscall(psx_cpu_t* cpu) {+ TRACE_I20("syscall");+
+ DO_PENDING_LOAD;
+
+ psx_cpu_exception(cpu, CAUSE_SYSCALL);
+}
+
+static inline void psx_cpu_i_break(psx_cpu_t* cpu) {+ TRACE_I20("break");+
+ DO_PENDING_LOAD;
+
+ psx_cpu_exception(cpu, CAUSE_BP);
+}
+
+static inline void psx_cpu_i_mfhi(psx_cpu_t* cpu) {+ TRACE_MTF("mfhi");+
+ DO_PENDING_LOAD;
+
+ cpu->r[D] = cpu->hi;
+}
+
+static inline void psx_cpu_i_mthi(psx_cpu_t* cpu) {+ TRACE_MTF("mthi");+
+ DO_PENDING_LOAD;
+
+ cpu->hi = cpu->r[S];
+}
+
+static inline void psx_cpu_i_mflo(psx_cpu_t* cpu) {+ TRACE_MTF("mflo");+
+ DO_PENDING_LOAD;
+
+ cpu->r[D] = cpu->lo;
+}
+
+static inline void psx_cpu_i_mtlo(psx_cpu_t* cpu) {+ TRACE_MTF("mtlo");+
+ DO_PENDING_LOAD;
+
+ cpu->lo = cpu->r[S];
+}
+
+static inline void psx_cpu_i_mult(psx_cpu_t* cpu) {+ TRACE_MD("mult");+
+ int64_t s = (int64_t)((int32_t)cpu->r[S]);
+ int64_t t = (int64_t)((int32_t)cpu->r[T]);
+
+ DO_PENDING_LOAD;
+
+ uint64_t r = s * t;
+
+ cpu->hi = r >> 32;
+ cpu->lo = r & 0xffffffff;
+}
+
+static inline void psx_cpu_i_multu(psx_cpu_t* cpu) {+ TRACE_MD("multu");+
+ uint64_t s = (uint64_t)cpu->r[S];
+ uint64_t t = (uint64_t)cpu->r[T];
+
+ DO_PENDING_LOAD;
+
+ uint64_t r = s * t;
+
+ cpu->hi = r >> 32;
+ cpu->lo = r & 0xffffffff;
+}
+
+static inline void psx_cpu_i_div(psx_cpu_t* cpu) {+ TRACE_MD("div");+
+ int32_t s = (int32_t)cpu->r[S];
+ int32_t t = (int32_t)cpu->r[T];
+
+ DO_PENDING_LOAD;
+
+ if (!t) {+ cpu->hi = s;
+ cpu->lo = (s >= 0) ? 0xffffffff : 1;
+ } else if ((((uint32_t)s) == 0x80000000) && (t == -1)) {+ cpu->hi = 0;
+ cpu->lo = 0x80000000;
+ } else {+ cpu->hi = (uint32_t)(s % t);
+ cpu->lo = (uint32_t)(s / t);
+ }
+}
+
+static inline void psx_cpu_i_divu(psx_cpu_t* cpu) {+ TRACE_MD("divu");+
+ uint32_t s = cpu->r[S];
+ uint32_t t = cpu->r[T];
+
+ DO_PENDING_LOAD;
+
+ if (!t) {+ cpu->hi = s;
+ cpu->lo = 0xffffffff;
+ } else {+ cpu->hi = s % t;
+ cpu->lo = s / t;
+ }
+}
+
+static inline void psx_cpu_i_add(psx_cpu_t* cpu) {+ TRACE_RT("add");+
+ int32_t s = cpu->r[S];
+ int32_t t = cpu->r[T];
+
+ DO_PENDING_LOAD;
+
+ int32_t r = s + t;
+ uint32_t o = (s ^ r) & (t ^ r);
+
+ if (o & 0x80000000) {+ psx_cpu_exception(cpu, CAUSE_OV);
+ } else {+ cpu->r[D] = (uint32_t)r;
+ }
+}
+
+static inline void psx_cpu_i_addu(psx_cpu_t* cpu) {+ TRACE_RT("addu");+
+ uint32_t s = cpu->r[S];
+ uint32_t t = cpu->r[T];
+
+ DO_PENDING_LOAD;
+
+ cpu->r[D] = s + t;
+}
+
+static inline void psx_cpu_i_sub(psx_cpu_t* cpu) {+ TRACE_RT("sub");+
+ int32_t s = (int32_t)cpu->r[S];
+ int32_t t = (int32_t)cpu->r[T];
+ int32_t r;
+
+ DO_PENDING_LOAD;
+
+ int o = __builtin_ssub_overflow(s, t, &r);
+
+ if (o) {+ psx_cpu_exception(cpu, CAUSE_OV);
+ } else {+ cpu->r[D] = r;
+ }
+}
+
+static inline void psx_cpu_i_subu(psx_cpu_t* cpu) {+ TRACE_RT("subu");+
+ uint32_t s = cpu->r[S];
+ uint32_t t = cpu->r[T];
+
+ DO_PENDING_LOAD;
+
+ cpu->r[D] = s - t;
+}
+
+static inline void psx_cpu_i_and(psx_cpu_t* cpu) {+ TRACE_RT("and");+
+ uint32_t s = cpu->r[S];
+ uint32_t t = cpu->r[T];
+
+ DO_PENDING_LOAD;
+
+ cpu->r[D] = s & t;
+}
+
+static inline void psx_cpu_i_or(psx_cpu_t* cpu) {+ TRACE_RT("or");+
+ uint32_t s = cpu->r[S];
+ uint32_t t = cpu->r[T];
+
+ DO_PENDING_LOAD;
+
+ cpu->r[D] = s | t;
+}
+
+static inline void psx_cpu_i_xor(psx_cpu_t* cpu) {+ TRACE_RT("xor");+
+ uint32_t s = cpu->r[S];
+ uint32_t t = cpu->r[T];
+
+ DO_PENDING_LOAD;
+
+ cpu->r[D] = (s ^ t);
+}
+
+static inline void psx_cpu_i_nor(psx_cpu_t* cpu) {+ TRACE_RT("nor");+
+ uint32_t s = cpu->r[S];
+ uint32_t t = cpu->r[T];
+
+ DO_PENDING_LOAD;
+
+ cpu->r[D] = ~(s | t);
+}
+
+static inline void psx_cpu_i_slt(psx_cpu_t* cpu) {+ TRACE_RT("slt");+
+ int32_t s = (int32_t)cpu->r[S];
+ int32_t t = (int32_t)cpu->r[T];
+
+ DO_PENDING_LOAD;
+
+ cpu->r[D] = s < t;
+}
+
+static inline void psx_cpu_i_sltu(psx_cpu_t* cpu) {+ TRACE_RT("sltu");+
+ uint32_t s = cpu->r[S];
+ uint32_t t = cpu->r[T];
+
+ DO_PENDING_LOAD;
+
+ cpu->r[D] = s < t;
+}
+
+// COP0
+static inline void psx_cpu_i_mfc0(psx_cpu_t* cpu) {+ TRACE_C0M("mfc0");+
+ DO_PENDING_LOAD;
+
+ cpu->load_v = cpu->cop0_r[D];
+ cpu->load_d = T;
+}
+
+static inline void psx_cpu_i_mtc0(psx_cpu_t* cpu) {+ TRACE_C0M("mtc0");+
+ uint32_t t = cpu->r[T];
+
+ DO_PENDING_LOAD;
+
+ cpu->cop0_r[D] = t & g_psx_cpu_cop0_write_mask_table[D];
+}
+
+static inline void psx_cpu_i_rfe(psx_cpu_t* cpu) {+ TRACE_N("rfe");+
+ DO_PENDING_LOAD;
+
+ uint32_t mode = cpu->cop0_r[COP0_SR] & 0x3f;
+
+ cpu->cop0_r[COP0_SR] &= 0xfffffff0;
+ cpu->cop0_r[COP0_SR] |= mode >> 2;
+}
+
+// COP2
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#define CLAMP(v, a, b) (((v) < (a)) ? (a) : (((v) > (b)) ? (b) : (v)))
+
+static inline void gte_handle_irgb_write(psx_cpu_t* cpu) {+ cpu->cop2_dr.ir[1] = ((cpu->cop2_dr.irgb >> 0) & 0x1f) * 0x80;
+ cpu->cop2_dr.ir[2] = ((cpu->cop2_dr.irgb >> 5) & 0x1f) * 0x80;
+ cpu->cop2_dr.ir[3] = ((cpu->cop2_dr.irgb >> 10) & 0x1f) * 0x80;
+}
+
+static inline void gte_handle_irgb_read(psx_cpu_t* cpu) {+ int r = CLAMP(cpu->cop2_dr.ir[1] >> 7, 0x00, 0x1f);
+ int g = CLAMP(cpu->cop2_dr.ir[2] >> 7, 0x00, 0x1f);
+ int b = CLAMP(cpu->cop2_dr.ir[3] >> 7, 0x00, 0x1f);
+
+ cpu->cop2_dr.irgb = r | (g << 5) | (b << 10);
+}
+
+static inline void gte_handle_sxyp_write(psx_cpu_t* cpu) {+ cpu->cop2_dr.sxy[0] = cpu->cop2_dr.sxy[1];
+ cpu->cop2_dr.sxy[1] = cpu->cop2_dr.sxy[2];
+ cpu->cop2_dr.sxy[2] = cpu->cop2_dr.sxy[3];
+}
+
+static inline void gte_handle_lzcs_write(psx_cpu_t* cpu) {+ if ((cpu->cop2_dr.lzcs == 0xffffffff) || !cpu->cop2_dr.lzcs) {+ cpu->cop2_dr.lzcr = 32;
+
+ return;
+ }
+
+ int b = (cpu->cop2_dr.lzcs >> 31) & 1;
+
+ cpu->cop2_dr.lzcr = __builtin_clz(b ? ~cpu->cop2_dr.lzcs : cpu->cop2_dr.lzcs);
+}
+
+uint32_t gte_read_register(psx_cpu_t* cpu, uint32_t r) {+ switch (r) {+ case 0 : return cpu->cop2_dr.v[0].xy;
+ case 1 : return (int32_t)cpu->cop2_dr.v[0].z;
+ case 2 : return cpu->cop2_dr.v[1].xy;
+ case 3 : return (int32_t)cpu->cop2_dr.v[1].z;
+ case 4 : return cpu->cop2_dr.v[2].xy;
+ case 5 : return (int32_t)cpu->cop2_dr.v[2].z;
+ case 6 : return cpu->cop2_dr.rgbc.rgbc;
+ case 7 : return cpu->cop2_dr.otz;
+ case 8 : return (int32_t)cpu->cop2_dr.ir[0];
+ case 9 : return (int32_t)cpu->cop2_dr.ir[1];
+ case 10: return (int32_t)cpu->cop2_dr.ir[2];
+ case 11: return (int32_t)cpu->cop2_dr.ir[3];
+ case 12: return cpu->cop2_dr.sxy[0].xy;
+ case 13: return cpu->cop2_dr.sxy[1].xy;
+ case 14: return cpu->cop2_dr.sxy[2].xy;
+ case 15: return cpu->cop2_dr.sxy[2].xy; // SXY2 Mirror
+ case 16: return cpu->cop2_dr.sz[0];
+ case 17: return cpu->cop2_dr.sz[1];
+ case 18: return cpu->cop2_dr.sz[2];
+ case 19: return cpu->cop2_dr.sz[3];
+ case 20: return cpu->cop2_dr.rgb[0].rgbc;
+ case 21: return cpu->cop2_dr.rgb[1].rgbc;
+ case 22: return cpu->cop2_dr.rgb[2].rgbc;
+ case 23: return cpu->cop2_dr.res1;
+ case 24: return cpu->cop2_dr.mac[0];
+ case 25: return cpu->cop2_dr.mac[1];
+ case 26: return cpu->cop2_dr.mac[2];
+ case 27: return cpu->cop2_dr.mac[3];
+ case 28: gte_handle_irgb_read(cpu); return cpu->cop2_dr.irgb;
+ case 29: return cpu->cop2_dr.irgb; // IRGB mirror
+ case 30: return cpu->cop2_dr.lzcs;
+ case 31: return cpu->cop2_dr.lzcr;
+ case 32: return cpu->cop2_cr.rt.m[0].u32;
+ case 33: return cpu->cop2_cr.rt.m[1].u32;
+ case 34: return cpu->cop2_cr.rt.m[2].u32;
+ case 35: return cpu->cop2_cr.rt.m[3].u32;
+ case 36: return (int32_t)cpu->cop2_cr.rt.m33;
+ case 37: return cpu->cop2_cr.tr.x;
+ case 38: return cpu->cop2_cr.tr.y;
+ case 39: return cpu->cop2_cr.tr.z;
+ case 40: return cpu->cop2_cr.l.m[0].u32;
+ case 41: return cpu->cop2_cr.l.m[1].u32;
+ case 42: return cpu->cop2_cr.l.m[2].u32;
+ case 43: return cpu->cop2_cr.l.m[3].u32;
+ case 44: return (int32_t)cpu->cop2_cr.l.m33;
+ case 45: return cpu->cop2_cr.bk.x;
+ case 46: return cpu->cop2_cr.bk.y;
+ case 47: return cpu->cop2_cr.bk.z;
+ case 48: return cpu->cop2_cr.lr.m[0].u32;
+ case 49: return cpu->cop2_cr.lr.m[1].u32;
+ case 50: return cpu->cop2_cr.lr.m[2].u32;
+ case 51: return cpu->cop2_cr.lr.m[3].u32;
+ case 52: return (int32_t)cpu->cop2_cr.lr.m33;
+ case 53: return cpu->cop2_cr.fc.x;
+ case 54: return cpu->cop2_cr.fc.y;
+ case 55: return cpu->cop2_cr.fc.z;
+ case 56: return cpu->cop2_cr.ofx;
+ case 57: return cpu->cop2_cr.ofy;
+ case 58: return (int32_t)(int16_t)cpu->cop2_cr.h;
+ case 59: return cpu->cop2_cr.dqa;
+ case 60: return cpu->cop2_cr.dqb;
+ case 61: return cpu->cop2_cr.zsf3;
+ case 62: return cpu->cop2_cr.zsf4;
+ case 63: return (cpu->cop2_cr.flag & 0x7ffff000) |
+ (((cpu->cop2_cr.flag & 0x7f87e000) != 0) << 31);
+ }
+
+ return 0x00000000;
+}
+
+static inline void gte_write_register(psx_cpu_t* cpu, uint32_t r, uint32_t value) {+ switch (r) {+ case 0 : cpu->cop2_dr.v[0].xy = value; break;
+ case 1 : cpu->cop2_dr.v[0].z = value; break;
+ case 2 : cpu->cop2_dr.v[1].xy = value; break;
+ case 3 : cpu->cop2_dr.v[1].z = value; break;
+ case 4 : cpu->cop2_dr.v[2].xy = value; break;
+ case 5 : cpu->cop2_dr.v[2].z = value; break;
+ case 6 : cpu->cop2_dr.rgbc.rgbc = value; break;
+ case 7 : cpu->cop2_dr.otz = value; break;
+ case 8 : cpu->cop2_dr.ir[0] = value; break;
+ case 9 : cpu->cop2_dr.ir[1] = value; break;
+ case 10: cpu->cop2_dr.ir[2] = value; break;
+ case 11: cpu->cop2_dr.ir[3] = value; break;
+ case 12: cpu->cop2_dr.sxy[0].xy = value; break;
+ case 13: cpu->cop2_dr.sxy[1].xy = value; break;
+ case 14: cpu->cop2_dr.sxy[2].xy = value; break;
+ case 15: cpu->cop2_dr.sxy[3].xy = value; gte_handle_sxyp_write(cpu); break;
+ case 16: cpu->cop2_dr.sz[0] = value; break;
+ case 17: cpu->cop2_dr.sz[1] = value; break;
+ case 18: cpu->cop2_dr.sz[2] = value; break;
+ case 19: cpu->cop2_dr.sz[3] = value; break;
+ case 20: cpu->cop2_dr.rgb[0].rgbc = value; break;
+ case 21: cpu->cop2_dr.rgb[1].rgbc = value; break;
+ case 22: cpu->cop2_dr.rgb[2].rgbc = value; break;
+ case 23: cpu->cop2_dr.res1 = value; break;
+ case 24: cpu->cop2_dr.mac[0] = value; break;
+ case 25: cpu->cop2_dr.mac[1] = value; break;
+ case 26: cpu->cop2_dr.mac[2] = value; break;
+ case 27: cpu->cop2_dr.mac[3] = value; break;
+ case 28: cpu->cop2_dr.irgb = value & 0x7fff; gte_handle_irgb_write(cpu); break;
+ case 29: /* ORGB RO */ break;
+ case 30: cpu->cop2_dr.lzcs = value; gte_handle_lzcs_write(cpu); break;
+ case 31: /* LZCR RO */ break;
+ case 32: cpu->cop2_cr.rt.m[0].u32 = value; break;
+ case 33: cpu->cop2_cr.rt.m[1].u32 = value; break;
+ case 34: cpu->cop2_cr.rt.m[2].u32 = value; break;
+ case 35: cpu->cop2_cr.rt.m[3].u32 = value; break;
+ case 36: cpu->cop2_cr.rt.m33 = value; break;
+ case 37: cpu->cop2_cr.tr.x = value; break;
+ case 38: cpu->cop2_cr.tr.y = value; break;
+ case 39: cpu->cop2_cr.tr.z = value; break;
+ case 40: cpu->cop2_cr.l.m[0].u32 = value; break;
+ case 41: cpu->cop2_cr.l.m[1].u32 = value; break;
+ case 42: cpu->cop2_cr.l.m[2].u32 = value; break;
+ case 43: cpu->cop2_cr.l.m[3].u32 = value; break;
+ case 44: cpu->cop2_cr.l.m33 = value; break;
+ case 45: cpu->cop2_cr.bk.x = value; break;
+ case 46: cpu->cop2_cr.bk.y = value; break;
+ case 47: cpu->cop2_cr.bk.z = value; break;
+ case 48: cpu->cop2_cr.lr.m[0].u32 = value; break;
+ case 49: cpu->cop2_cr.lr.m[1].u32 = value; break;
+ case 50: cpu->cop2_cr.lr.m[2].u32 = value; break;
+ case 51: cpu->cop2_cr.lr.m[3].u32 = value; break;
+ case 52: cpu->cop2_cr.lr.m33 = value; break;
+ case 53: cpu->cop2_cr.fc.x = value; break;
+ case 54: cpu->cop2_cr.fc.y = value; break;
+ case 55: cpu->cop2_cr.fc.z = value; break;
+ case 56: cpu->cop2_cr.ofx = value; break;
+ case 57: cpu->cop2_cr.ofy = value; break;
+ case 58: cpu->cop2_cr.h = value; break;
+ case 59: cpu->cop2_cr.dqa = value; break;
+ case 60: cpu->cop2_cr.dqb = value; break;
+ case 61: cpu->cop2_cr.zsf3 = value; break;
+ case 62: cpu->cop2_cr.zsf4 = value; break;
+ case 63: cpu->cop2_cr.flag = value & 0x7ffff000; break;
+ }
+}
+
+static inline void psx_cpu_i_lwc2(psx_cpu_t* cpu) {+ uint32_t s = cpu->r[S];
+ uint32_t addr = s + IMM16S;
+
+ DO_PENDING_LOAD;
+
+ if (addr & 0x3) {+ psx_cpu_exception(cpu, CAUSE_ADEL);
+ } else {+ gte_write_register(cpu, T, psx_bus_read32(cpu->bus, addr));
+ }
+}
+
+static inline void psx_cpu_i_swc2(psx_cpu_t* cpu) {+ uint32_t s = cpu->r[S];
+ uint32_t addr = s + IMM16S;
+
+ DO_PENDING_LOAD;
+
+ // Cache isolated
+ if (cpu->cop0_r[COP0_SR] & SR_ISC) {+ log_debug("Ignoring write while cache is isolated");+
+ return;
+ }
+
+ if (addr & 0x3) {+ psx_cpu_exception(cpu, CAUSE_ADES);
+ } else {+ psx_bus_write32(cpu->bus, addr, gte_read_register(cpu, T));
+ }
+}
+
+static inline void psx_cpu_i_mfc2(psx_cpu_t* cpu) {+ TRACE_C2M("mfc2");+
+ DO_PENDING_LOAD;
+
+ cpu->load_v = gte_read_register(cpu, D);
+ cpu->load_d = T;
+}
+
+static inline void psx_cpu_i_cfc2(psx_cpu_t* cpu) {+ TRACE_C2MC("cfc2");+
+ DO_PENDING_LOAD;
+
+ cpu->load_v = gte_read_register(cpu, D + 32);
+ cpu->load_d = T;
+}
+
+static inline void psx_cpu_i_mtc2(psx_cpu_t* cpu) {+ TRACE_C2M("mtc2");+
+ uint32_t t = cpu->r[T];
+
+ DO_PENDING_LOAD;
+
+ gte_write_register(cpu, D, t);
+}
+
+static inline void psx_cpu_i_ctc2(psx_cpu_t* cpu) {+ TRACE_C2MC("ctc2");+
+ uint32_t t = cpu->r[T];
+
+ DO_PENDING_LOAD;
+
+ gte_write_register(cpu, D + 32, t);
+}
+
+#define R_FLAG cpu->cop2_cr.flag
+
+static inline int64_t gte_clamp_mac0(psx_cpu_t* cpu, int64_t value) {+ cpu->s_mac0 = value;
+
+ if (value < (-0x80000000ll)) {+ R_FLAG |= 0x8000;
+ } else if (value > (0x7fffffffll)) {+ R_FLAG |= 0x10000;
+ }
+
+ return value;
+}
+
+static inline int32_t gte_clamp_mac(psx_cpu_t* cpu, int i, int64_t value) {+ if (i == 3)
+ cpu->s_mac3 = value;
+
+ if (value < -0x80000000000ll) {+ R_FLAG |= 0x8000000 >> (i - 1);
+ } else if (value > 0x7ffffffffffll) {+ R_FLAG |= 0x40000000 >> (i - 1);
+ }
+
+ return (int32_t)(((value << 20) >> 20) >> cpu->gte_sf);
+}
+
+static inline int64_t gte_check_mac(psx_cpu_t* cpu, int i, int64_t value) {+ if (value < -0x80000000000ll) {+ R_FLAG |= 0x8000000 >> (i - 1);
+ } else if (value > 0x7ffffffffffll) {+ R_FLAG |= 0x40000000 >> (i - 1);
+ }
+
+ return (value << 20) >> 20;
+}
+
+static inline int32_t gte_clamp_ir0(psx_cpu_t* cpu, int32_t value) {+ if (value < 0) {+ R_FLAG |= 0x1000;
+
+ return 0;
+ } else if (value > 0x1000) {+ R_FLAG |= 0x1000;
+
+ return 0x1000;
+ }
+
+ return value;
+}
+
+static inline int64_t gte_clamp_sxy(psx_cpu_t* cpu, int i, int64_t value) {+ if (value < -0x400) {+ R_FLAG |= (uint32_t)(0x4000 >> (i - 1));
+
+ return -0x400;
+ } else if (value > 0x3ff) {+ R_FLAG |= (uint32_t)(0x4000 >> (i - 1));
+
+ return 0x3ff;
+ }
+
+ return value;
+}
+
+static inline int32_t gte_clamp_sz3(psx_cpu_t* cpu, int32_t value) {+ if (value < 0) {+ R_FLAG |= 0x40000;
+
+ return 0;
+ } else if (value > 0xffff) {+ R_FLAG |= 0x40000;
+
+ return 0xffff;
+ }
+
+ return value;
+}
+
+static inline uint8_t gte_clamp_rgb(psx_cpu_t* cpu, int i, int value) {+ if (value < 0) {+ R_FLAG |= (uint32_t)0x200000 >> (i - 1);
+
+ return 0;
+ } else if (value > 0xff) {+ R_FLAG |= (uint32_t)0x200000 >> (i - 1);
+
+ return 0xff;
+ }
+
+ return (uint8_t)value;
+}
+
+static inline int32_t gte_clamp_ir(psx_cpu_t* cpu, int i, int64_t value, int lm) {+ if (lm && (value < 0)) {+ R_FLAG |= (uint32_t)(0x1000000 >> (i - 1));
+
+ return 0;
+ } else if ((value < -0x8000) && !lm) {+ R_FLAG |= (uint32_t)(0x1000000 >> (i - 1));
+
+ return -0x8000;
+ } else if (value > 0x7fff) {+ R_FLAG |= (uint32_t)(0x1000000 >> (i - 1));
+
+ return 0x7fff;
+ }
+
+ return (int32_t)value;
+}
+
+static inline int32_t gte_clamp_ir_z(psx_cpu_t* cpu, int64_t value, int sf, int lm) {+ int32_t value_sf = value >> sf;
+ int32_t value_12 = value >> 12;
+ int32_t min = 0;
+
+ if (lm == 0)
+ min = -((int32_t)0x8000);
+
+ if (value_12 < (-((int32_t)0x8000)) || value_12 > 0x7fffl)
+ R_FLAG |= (1 << 22);
+
+ return (int32_t)CLAMP(value_sf, min, 0x7fffl);
+}
+
+static inline int clz(uint32_t value) {+ if (!value)
+ return 32;
+
+ return __builtin_clz(value);
+}
+
+static inline uint32_t gte_divide(psx_cpu_t* cpu, uint16_t n, uint16_t d) {+ // Overflow
+ if (n >= d * 2) {+ R_FLAG |= (1 << 31) | (1 << 17);
+
+ return 0x1ffff;
+ }
+
+ int shift = clz(d) - 16;
+
+ int r1 = (d << shift) & 0x7fff;
+ int r2 = g_psx_gte_unr_table[((r1 + 0x40) >> 7)] + 0x101;
+ int r3 = ((0x80 - (r2 * (r1 + 0x8000))) >> 8) & 0x1ffff;
+
+ uint32_t reciprocal = ((r2 * r3) + 0x80) >> 8;
+ uint32_t res = ((((uint64_t)reciprocal * (n << shift)) + 0x8000) >> 16);
+
+ return MIN(0x1ffff, res);
+}
+
+static inline void psx_gte_i_invalid(psx_cpu_t* cpu) {+ log_fatal("invalid: Unimplemented GTE instruction %02x, %02x", cpu->opcode & 0x3f, cpu->opcode >> 25);+}
+
+#define I64(v) ((int64_t)v)
+#define R_TRX cpu->cop2_cr.tr.x
+#define R_TRY cpu->cop2_cr.tr.y
+#define R_TRZ cpu->cop2_cr.tr.z
#define R_RT11 cpu->cop2_cr.rt.m[0].c[0]
-#define R_RT12 cpu->cop2_cr.rt.m[0].c[1]
-#define R_RT13 cpu->cop2_cr.rt.m[1].c[0]
-#define R_RT21 cpu->cop2_cr.rt.m[1].c[1]
-#define R_RT22 cpu->cop2_cr.rt.m[2].c[0]
-#define R_RT23 cpu->cop2_cr.rt.m[2].c[1]
-#define R_RT31 cpu->cop2_cr.rt.m[3].c[0]
-#define R_RT32 cpu->cop2_cr.rt.m[3].c[1]
-#define R_RT33 cpu->cop2_cr.rt.m33
-#define R_MAC0 cpu->cop2_dr.mac[0]
-#define R_MAC1 cpu->cop2_dr.mac[1]
-#define R_MAC2 cpu->cop2_dr.mac[2]
-#define R_MAC3 cpu->cop2_dr.mac[3]
-#define R_OFX cpu->cop2_cr.ofx
-#define R_OFY cpu->cop2_cr.ofy
-#define R_IR0 cpu->cop2_dr.ir[0]
-#define R_IR1 cpu->cop2_dr.ir[1]
-#define R_IR2 cpu->cop2_dr.ir[2]
-#define R_IR3 cpu->cop2_dr.ir[3]
-#define R_SXY0 cpu->cop2_dr.sxy[0].xy
-#define R_SX0 cpu->cop2_dr.sxy[0].p[0]
-#define R_SY0 cpu->cop2_dr.sxy[0].p[1]
-#define R_SZ0 cpu->cop2_dr.sz[0]
-#define R_SXY1 cpu->cop2_dr.sxy[1].xy
-#define R_SX1 cpu->cop2_dr.sxy[1].p[0]
-#define R_SY1 cpu->cop2_dr.sxy[1].p[1]
-#define R_SZ1 cpu->cop2_dr.sz[1]
-#define R_SXY2 cpu->cop2_dr.sxy[2].xy
-#define R_SX2 cpu->cop2_dr.sxy[2].p[0]
-#define R_SY2 cpu->cop2_dr.sxy[2].p[1]
-#define R_SZ2 cpu->cop2_dr.sz[2]
-#define R_SZ3 cpu->cop2_dr.sz[3]
-#define R_DQA cpu->cop2_cr.dqa
-#define R_DQB cpu->cop2_cr.dqb
-#define R_ZSF3 cpu->cop2_cr.zsf3
-#define R_ZSF4 cpu->cop2_cr.zsf4
-#define R_OTZ cpu->cop2_dr.otz
-#define R_H cpu->cop2_cr.h
-#define R_RC cpu->cop2_dr.rgbc.c[0]
-#define R_GC cpu->cop2_dr.rgbc.c[1]
-#define R_BC cpu->cop2_dr.rgbc.c[2]
-#define R_CODE cpu->cop2_dr.rgbc.c[3]
-#define R_RGBC cpu->cop2_dr.rgbc.rgbc
-#define R_RFC cpu->cop2_cr.fc.x
-#define R_GFC cpu->cop2_cr.fc.y
-#define R_BFC cpu->cop2_cr.fc.z
-#define R_RGB0 cpu->cop2_dr.rgb[0].rgbc
-#define R_RGB1 cpu->cop2_dr.rgb[1].rgbc
-#define R_RGB2 cpu->cop2_dr.rgb[2].rgbc
-#define R_RC0 cpu->cop2_dr.rgb[0].c[0]
-#define R_GC0 cpu->cop2_dr.rgb[0].c[1]
-#define R_BC0 cpu->cop2_dr.rgb[0].c[2]
-#define R_CD0 cpu->cop2_dr.rgb[0].c[3]
-#define R_RC1 cpu->cop2_dr.rgb[1].c[0]
-#define R_GC1 cpu->cop2_dr.rgb[1].c[1]
-#define R_BC1 cpu->cop2_dr.rgb[1].c[2]
-#define R_CD1 cpu->cop2_dr.rgb[1].c[3]
-#define R_RC2 cpu->cop2_dr.rgb[2].c[0]
-#define R_GC2 cpu->cop2_dr.rgb[2].c[1]
-#define R_BC2 cpu->cop2_dr.rgb[2].c[2]
-#define R_CD2 cpu->cop2_dr.rgb[2].c[3]
-#define R_L11 cpu->cop2_cr.l.m[0].c[0]
-#define R_L12 cpu->cop2_cr.l.m[0].c[1]
-#define R_L13 cpu->cop2_cr.l.m[1].c[0]
-#define R_L21 cpu->cop2_cr.l.m[1].c[1]
-#define R_L22 cpu->cop2_cr.l.m[2].c[0]
-#define R_L23 cpu->cop2_cr.l.m[2].c[1]
-#define R_L31 cpu->cop2_cr.l.m[3].c[0]
-#define R_L32 cpu->cop2_cr.l.m[3].c[1]
-#define R_L33 cpu->cop2_cr.l.m33
-#define R_RBK cpu->cop2_cr.bk.x
-#define R_GBK cpu->cop2_cr.bk.y
-#define R_BBK cpu->cop2_cr.bk.z
-#define R_LR1 cpu->cop2_cr.lr.m[0].c[0]
-#define R_LR2 cpu->cop2_cr.lr.m[0].c[1]
-#define R_LR3 cpu->cop2_cr.lr.m[1].c[0]
-#define R_LG1 cpu->cop2_cr.lr.m[1].c[1]
-#define R_LG2 cpu->cop2_cr.lr.m[2].c[0]
-#define R_LG3 cpu->cop2_cr.lr.m[2].c[1]
-#define R_LB1 cpu->cop2_cr.lr.m[3].c[0]
-#define R_LB2 cpu->cop2_cr.lr.m[3].c[1]
-#define R_LB3 cpu->cop2_cr.lr.m33
-
-#define GTE_RTP_DQ(i) { \
- int64_t vx = (int64_t)((int16_t)cpu->cop2_dr.v[i].p[0]); \
- int64_t vy = (int64_t)((int16_t)cpu->cop2_dr.v[i].p[1]); \
- int64_t vz = (int64_t)cpu->cop2_dr.v[i].z; \
- R_MAC1 = gte_clamp_mac(cpu, 1, gte_check_mac(cpu, 1, gte_check_mac(cpu, 1, (((int64_t)R_TRX) << 12) + (I64((int16_t)R_RT11) * vx)) + (I64((int16_t)R_RT12) * vy)) + (I64((int16_t)R_RT13) * vz)); \
- R_MAC2 = gte_clamp_mac(cpu, 2, gte_check_mac(cpu, 2, gte_check_mac(cpu, 2, (((int64_t)R_TRY) << 12) + (I64((int16_t)R_RT21) * vx)) + (I64((int16_t)R_RT22) * vy)) + (I64((int16_t)R_RT23) * vz)); \
- R_MAC3 = gte_clamp_mac(cpu, 3, gte_check_mac(cpu, 3, gte_check_mac(cpu, 3, (((int64_t)R_TRZ) << 12) + (I64((int16_t)R_RT31) * vx)) + (I64((int16_t)R_RT32) * vy)) + (I64((int16_t)R_RT33) * vz)); \
- R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm); \
- R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm); \
- R_IR3 = gte_clamp_ir_z(cpu, cpu->s_mac3, cpu->gte_sf, cpu->gte_lm); \
- R_SZ0 = R_SZ1; \
- R_SZ1 = R_SZ2; \
- R_SZ2 = R_SZ3; \
- R_SZ3 = gte_clamp_sz3(cpu, cpu->s_mac3 >> 12); \
- int32_t div = gte_divide(cpu, R_H, R_SZ3); \
- R_SXY0 = R_SXY1; \
- R_SXY1 = R_SXY2; \
- R_SX2 = gte_clamp_sxy(cpu, 1, (gte_clamp_mac0(cpu, (int64_t)((int32_t)R_OFX) + ((int64_t)R_IR1 * div)) >> 16)); \
- R_SY2 = gte_clamp_sxy(cpu, 2, (gte_clamp_mac0(cpu, (int64_t)((int32_t)R_OFY) + ((int64_t)R_IR2 * div)) >> 16)); \
- R_MAC0 = gte_clamp_mac0(cpu, ((int64_t)R_DQB) + (((int64_t)R_DQA) * div)); \
- R_IR0 = gte_clamp_ir0(cpu, cpu->s_mac0 >> 12); }
-
-#define GTE_RTP(i) { \
- int64_t vx = (int64_t)((int16_t)cpu->cop2_dr.v[i].p[0]); \
- int64_t vy = (int64_t)((int16_t)cpu->cop2_dr.v[i].p[1]); \
- int64_t vz = (int64_t)cpu->cop2_dr.v[i].z; \
- R_MAC1 = gte_clamp_mac(cpu, 1, gte_check_mac(cpu, 1, gte_check_mac(cpu, 1, (((int64_t)R_TRX) << 12) + (I64((int16_t)R_RT11) * vx)) + (I64((int16_t)R_RT12) * vy)) + (I64((int16_t)R_RT13) * vz)); \
- R_MAC2 = gte_clamp_mac(cpu, 2, gte_check_mac(cpu, 2, gte_check_mac(cpu, 2, (((int64_t)R_TRY) << 12) + (I64((int16_t)R_RT21) * vx)) + (I64((int16_t)R_RT22) * vy)) + (I64((int16_t)R_RT23) * vz)); \
- R_MAC3 = gte_clamp_mac(cpu, 3, gte_check_mac(cpu, 3, gte_check_mac(cpu, 3, (((int64_t)R_TRZ) << 12) + (I64((int16_t)R_RT31) * vx)) + (I64((int16_t)R_RT32) * vy)) + (I64((int16_t)R_RT33) * vz)); \
- R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm); \
- R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm); \
- R_IR3 = gte_clamp_ir_z(cpu, cpu->s_mac3, cpu->gte_sf, cpu->gte_lm); \
- R_SZ0 = R_SZ1; \
- R_SZ1 = R_SZ2; \
- R_SZ2 = R_SZ3; \
- R_SZ3 = gte_clamp_sz3(cpu, cpu->s_mac3 >> 12); \
- int32_t div = gte_divide(cpu, R_H, R_SZ3); \
- R_SXY0 = R_SXY1; \
- R_SXY1 = R_SXY2; \
- R_SX2 = gte_clamp_sxy(cpu, 1, (gte_clamp_mac0(cpu, (int64_t)((int32_t)R_OFX) + ((int64_t)R_IR1 * div)) >> 16)); \
- R_SY2 = gte_clamp_sxy(cpu, 2, (gte_clamp_mac0(cpu, (int64_t)((int32_t)R_OFY) + ((int64_t)R_IR2 * div)) >> 16)); }
-
-#define DPCT1 { \
- int64_t mac1 = gte_clamp_mac(cpu, 1, (((int64_t)R_RFC) << 12) - (((int64_t)cpu->cop2_dr.rgb[0].c[0]) << 16)); \
- int64_t mac2 = gte_clamp_mac(cpu, 2, (((int64_t)R_GFC) << 12) - (((int64_t)cpu->cop2_dr.rgb[0].c[1]) << 16)); \
- int64_t mac3 = gte_clamp_mac(cpu, 3, (((int64_t)R_BFC) << 12) - (((int64_t)cpu->cop2_dr.rgb[0].c[2]) << 16)); \
- int64_t ir1 = gte_clamp_ir(cpu, 1, mac1, 0); \
- int64_t ir2 = gte_clamp_ir(cpu, 2, mac2, 0); \
- int64_t ir3 = gte_clamp_ir(cpu, 3, mac3, 0); \
- R_MAC1 = gte_clamp_mac(cpu, 1, (((int64_t)cpu->cop2_dr.rgb[0].c[0]) << 16) + (R_IR0 * ir1)); \
- R_MAC2 = gte_clamp_mac(cpu, 2, (((int64_t)cpu->cop2_dr.rgb[0].c[1]) << 16) + (R_IR0 * ir2)); \
- R_MAC3 = gte_clamp_mac(cpu, 3, (((int64_t)cpu->cop2_dr.rgb[0].c[2]) << 16) + (R_IR0 * ir3)); \
- R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm); \
- R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm); \
- R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm); \
- R_RGB0 = R_RGB1; \
- R_RGB1 = R_RGB2; \
- R_CD2 = R_CODE; \
- R_RC2 = gte_clamp_rgb(cpu, 1, R_MAC1 >> 4); \
- R_GC2 = gte_clamp_rgb(cpu, 2, R_MAC2 >> 4); \
- R_BC2 = gte_clamp_rgb(cpu, 3, R_MAC3 >> 4); }
-
-#define NCCS(i) { \
- int64_t vx = (int64_t)((int16_t)cpu->cop2_dr.v[i].p[0]); \
- int64_t vy = (int64_t)((int16_t)cpu->cop2_dr.v[i].p[1]); \
- int64_t vz = (int64_t)cpu->cop2_dr.v[i].z; \
- R_MAC1 = gte_clamp_mac(cpu, 1, (I64(R_L11) * vx) + (I64(R_L12) * vy) + (I64(R_L13) * vz)); \
- R_MAC2 = gte_clamp_mac(cpu, 2, (I64(R_L21) * vx) + (I64(R_L22) * vy) + (I64(R_L23) * vz)); \
- R_MAC3 = gte_clamp_mac(cpu, 3, (I64(R_L31) * vx) + (I64(R_L32) * vy) + (I64(R_L33) * vz)); \
- R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm); \
- R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm); \
- R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm); \
- R_MAC1 = gte_clamp_mac(cpu, 1, gte_check_mac(cpu, 1, gte_check_mac(cpu, 1, (I64(R_RBK) << 12) + (I64(R_LR1) * I64(R_IR1))) + (I64(R_LR2) * I64(R_IR2))) + (I64(R_LR3) * I64(R_IR3))); \
- R_MAC2 = gte_clamp_mac(cpu, 2, gte_check_mac(cpu, 2, gte_check_mac(cpu, 2, (I64(R_GBK) << 12) + (I64(R_LG1) * I64(R_IR1))) + (I64(R_LG2) * I64(R_IR2))) + (I64(R_LG3) * I64(R_IR3))); \
- R_MAC3 = gte_clamp_mac(cpu, 3, gte_check_mac(cpu, 3, gte_check_mac(cpu, 3, (I64(R_BBK) << 12) + (I64(R_LB1) * I64(R_IR1))) + (I64(R_LB2) * I64(R_IR2))) + (I64(R_LB3) * I64(R_IR3))); \
- R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm); \
- R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm); \
- R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm); \
- R_MAC1 = gte_clamp_mac(cpu, 1, (I64(R_RC) * I64(R_IR1)) << 4); \
- R_MAC2 = gte_clamp_mac(cpu, 2, (I64(R_GC) * I64(R_IR2)) << 4); \
- R_MAC3 = gte_clamp_mac(cpu, 3, (I64(R_BC) * I64(R_IR3)) << 4); \
- R_RGB0 = R_RGB1; \
- R_RGB1 = R_RGB2; \
- R_CD2 = R_CODE; \
- R_RC2 = gte_clamp_rgb(cpu, 1, R_MAC1 >> 4); \
- R_GC2 = gte_clamp_rgb(cpu, 2, R_MAC2 >> 4); \
- R_BC2 = gte_clamp_rgb(cpu, 3, R_MAC3 >> 4); \
- R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm); \
- R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm); \
- R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm); }
-
-#define NCS(i) { \
- int64_t vx = (int64_t)((int16_t)cpu->cop2_dr.v[i].p[0]); \
- int64_t vy = (int64_t)((int16_t)cpu->cop2_dr.v[i].p[1]); \
- int64_t vz = (int64_t)cpu->cop2_dr.v[i].z; \
- R_MAC1 = gte_clamp_mac(cpu, 1, (I64(R_L11) * vx) + (I64(R_L12) * vy) + (I64(R_L13) * vz)); \
- R_MAC2 = gte_clamp_mac(cpu, 2, (I64(R_L21) * vx) + (I64(R_L22) * vy) + (I64(R_L23) * vz)); \
- R_MAC3 = gte_clamp_mac(cpu, 3, (I64(R_L31) * vx) + (I64(R_L32) * vy) + (I64(R_L33) * vz)); \
- R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm); \
- R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm); \
- R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm); \
- R_MAC1 = gte_clamp_mac(cpu, 1, gte_check_mac(cpu, 1, gte_check_mac(cpu, 1, (I64(R_RBK) << 12) + (I64(R_LR1) * I64(R_IR1))) + (I64(R_LR2) * I64(R_IR2))) + (I64(R_LR3) * I64(R_IR3))); \
- R_MAC2 = gte_clamp_mac(cpu, 2, gte_check_mac(cpu, 2, gte_check_mac(cpu, 2, (I64(R_GBK) << 12) + (I64(R_LG1) * I64(R_IR1))) + (I64(R_LG2) * I64(R_IR2))) + (I64(R_LG3) * I64(R_IR3))); \
- R_MAC3 = gte_clamp_mac(cpu, 3, gte_check_mac(cpu, 3, gte_check_mac(cpu, 3, (I64(R_BBK) << 12) + (I64(R_LB1) * I64(R_IR1))) + (I64(R_LB2) * I64(R_IR2))) + (I64(R_LB3) * I64(R_IR3))); \
- R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm); \
- R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm); \
- R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm); \
- R_RGB0 = R_RGB1; \
- R_RGB1 = R_RGB2; \
- R_CD2 = R_CODE; \
- R_RC2 = gte_clamp_rgb(cpu, 1, R_MAC1 >> 4); \
- R_GC2 = gte_clamp_rgb(cpu, 2, R_MAC2 >> 4); \
- R_BC2 = gte_clamp_rgb(cpu, 3, R_MAC3 >> 4); \
- R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm); \
- R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm); \
- R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm); }
-
-#define NCDS(i) { \
- int64_t vx = (int64_t)((int16_t)cpu->cop2_dr.v[i].p[0]); \
- int64_t vy = (int64_t)((int16_t)cpu->cop2_dr.v[i].p[1]); \
- int64_t vz = (int64_t)cpu->cop2_dr.v[i].z; \
- R_MAC1 = gte_clamp_mac(cpu, 1, (I64(R_L11) * vx) + (I64(R_L12) * vy) + (I64(R_L13) * vz)); \
- R_MAC2 = gte_clamp_mac(cpu, 2, (I64(R_L21) * vx) + (I64(R_L22) * vy) + (I64(R_L23) * vz)); \
- R_MAC3 = gte_clamp_mac(cpu, 3, (I64(R_L31) * vx) + (I64(R_L32) * vy) + (I64(R_L33) * vz)); \
- R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm); \
- R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm); \
- R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm); \
- R_MAC1 = gte_clamp_mac(cpu, 1, gte_check_mac(cpu, 1, gte_check_mac(cpu, 1, (I64(R_RBK) << 12) + (I64(R_LR1) * I64(R_IR1))) + (I64(R_LR2) * I64(R_IR2))) + (I64(R_LR3) * I64(R_IR3))); \
- R_MAC2 = gte_clamp_mac(cpu, 2, gte_check_mac(cpu, 2, gte_check_mac(cpu, 2, (I64(R_GBK) << 12) + (I64(R_LG1) * I64(R_IR1))) + (I64(R_LG2) * I64(R_IR2))) + (I64(R_LG3) * I64(R_IR3))); \
- R_MAC3 = gte_clamp_mac(cpu, 3, gte_check_mac(cpu, 3, gte_check_mac(cpu, 3, (I64(R_BBK) << 12) + (I64(R_LB1) * I64(R_IR1))) + (I64(R_LB2) * I64(R_IR2))) + (I64(R_LB3) * I64(R_IR3))); \
- R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm); \
- R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm); \
- R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm); \
- int64_t ir1 = gte_clamp_ir(cpu, 1, gte_clamp_mac(cpu, 1, ((I64(R_RFC) << 12) - ((I64(R_RC << 4)) * I64(R_IR1)))), 0); \
- int64_t ir2 = gte_clamp_ir(cpu, 2, gte_clamp_mac(cpu, 2, ((I64(R_GFC) << 12) - ((I64(R_GC << 4)) * I64(R_IR2)))), 0); \
- int64_t ir3 = gte_clamp_ir(cpu, 3, gte_clamp_mac(cpu, 3, ((I64(R_BFC) << 12) - ((I64(R_BC << 4)) * I64(R_IR3)))), 0); \
- R_MAC1 = gte_clamp_mac(cpu, 1, ((I64(R_RC << 4)) * I64(R_IR1)) + (I64(R_IR0) * ir1)); \
- R_MAC2 = gte_clamp_mac(cpu, 2, ((I64(R_GC << 4)) * I64(R_IR2)) + (I64(R_IR0) * ir2)); \
- R_MAC3 = gte_clamp_mac(cpu, 3, ((I64(R_BC << 4)) * I64(R_IR3)) + (I64(R_IR0) * ir3)); \
- R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm); \
- R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm); \
- R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm); \
- R_RGB0 = R_RGB1; \
- R_RGB1 = R_RGB2; \
- R_CD2 = R_CODE; \
- R_RC2 = gte_clamp_rgb(cpu, 1, R_MAC1 >> 4); \
- R_GC2 = gte_clamp_rgb(cpu, 2, R_MAC2 >> 4); \
- R_BC2 = gte_clamp_rgb(cpu, 3, R_MAC3 >> 4); }
-
-static inline void psx_gte_i_rtps(psx_cpu_t* cpu) {
- R_FLAG = 0;
- GTE_RTP_DQ(0);
-}
-
-static inline void psx_gte_i_nclip(psx_cpu_t* cpu) {
- R_FLAG = 0;
-
- int64_t value = I64((int16_t)R_SX0) * (I64((int16_t)R_SY1) - I64((int16_t)R_SY2));
- value += I64((int16_t)R_SX1) * (I64((int16_t)R_SY2) - I64((int16_t)R_SY0));
- value += I64((int16_t)R_SX2) * (I64((int16_t)R_SY0) - I64((int16_t)R_SY1));
-
- R_MAC0 = (int)gte_clamp_mac0(cpu, value);
-}
-
-static inline void psx_gte_i_op(psx_cpu_t* cpu) {
- R_FLAG = 0;
-
- R_MAC1 = gte_clamp_mac(cpu, 1, I64(I64((int16_t)R_RT22) * I64(R_IR3)) - I64((I64((int16_t)R_RT33) * I64(R_IR2))));
- R_MAC2 = gte_clamp_mac(cpu, 2, I64(I64((int16_t)R_RT33) * I64(R_IR1)) - I64((I64((int16_t)R_RT11) * I64(R_IR3))));
- R_MAC3 = gte_clamp_mac(cpu, 3, I64(I64((int16_t)R_RT11) * I64(R_IR2)) - I64((I64((int16_t)R_RT22) * I64(R_IR1))));
-
- R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm);
- R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm);
- R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm);
-}
-
-static inline void psx_gte_i_dpcs(psx_cpu_t* cpu) {
- R_FLAG = 0;
-
- int64_t mac1 = gte_clamp_mac(cpu, 1, (((int64_t)R_RFC) << 12) - (((int64_t)R_RC) << 16));
- int64_t mac2 = gte_clamp_mac(cpu, 2, (((int64_t)R_GFC) << 12) - (((int64_t)R_GC) << 16));
- int64_t mac3 = gte_clamp_mac(cpu, 3, (((int64_t)R_BFC) << 12) - (((int64_t)R_BC) << 16));
-
- int64_t ir1 = gte_clamp_ir(cpu, 1, mac1, 0);
- int64_t ir2 = gte_clamp_ir(cpu, 2, mac2, 0);
- int64_t ir3 = gte_clamp_ir(cpu, 3, mac3, 0);
-
- R_MAC1 = gte_clamp_mac(cpu, 1, (I64(R_RC) << 16) + (R_IR0 * ir1));
- R_MAC2 = gte_clamp_mac(cpu, 2, (I64(R_GC) << 16) + (R_IR0 * ir2));
- R_MAC3 = gte_clamp_mac(cpu, 3, (I64(R_BC) << 16) + (R_IR0 * ir3));
-
- R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm);
- R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm);
- R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm);
-
- R_RGB0 = R_RGB1;
- R_RGB1 = R_RGB2;
- R_CD2 = R_CODE;
-
- R_RC2 = gte_clamp_rgb(cpu, 1, R_MAC1 >> 4);
- R_GC2 = gte_clamp_rgb(cpu, 2, R_MAC2 >> 4);
- R_BC2 = gte_clamp_rgb(cpu, 3, R_MAC3 >> 4);
-}
-
-static inline void psx_gte_i_intpl(psx_cpu_t* cpu) {
- R_FLAG = 0;
-
- int64_t mac1 = gte_clamp_mac(cpu, 1, (((int64_t)R_RFC) << 12) - (I64(R_IR1) << 12));
- int64_t mac2 = gte_clamp_mac(cpu, 2, (((int64_t)R_GFC) << 12) - (I64(R_IR2) << 12));
- int64_t mac3 = gte_clamp_mac(cpu, 3, (((int64_t)R_BFC) << 12) - (I64(R_IR3) << 12));
-
- int64_t ir1 = gte_clamp_ir(cpu, 1, mac1, 0);
- int64_t ir2 = gte_clamp_ir(cpu, 2, mac2, 0);
- int64_t ir3 = gte_clamp_ir(cpu, 3, mac3, 0);
-
- R_MAC1 = gte_clamp_mac(cpu, 1, (I64(R_IR1) << 12) + (I64(R_IR0) * ir1));
- R_MAC2 = gte_clamp_mac(cpu, 2, (I64(R_IR2) << 12) + (I64(R_IR0) * ir2));
- R_MAC3 = gte_clamp_mac(cpu, 3, (I64(R_IR3) << 12) + (I64(R_IR0) * ir3));
-
- R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm);
- R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm);
- R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm);
-
- R_RGB0 = R_RGB1;
- R_RGB1 = R_RGB2;
- R_CD2 = R_CODE;
-
- R_RC2 = gte_clamp_rgb(cpu, 1, R_MAC1 >> 4);
- R_GC2 = gte_clamp_rgb(cpu, 2, R_MAC2 >> 4);
- R_BC2 = gte_clamp_rgb(cpu, 3, R_MAC3 >> 4);
-}
-
-#define R_VX v.p[0]
-#define R_VY v.p[1]
-#define R_VZ v.z
-#define R_MX11 mx.m[0].c[0]
-#define R_MX12 mx.m[0].c[1]
-#define R_MX13 mx.m[1].c[0]
-#define R_MX21 mx.m[1].c[1]
-#define R_MX22 mx.m[2].c[0]
-#define R_MX23 mx.m[2].c[1]
-#define R_MX31 mx.m[3].c[0]
-#define R_MX32 mx.m[3].c[1]
-#define R_MX33 mx.m33
-#define R_CV1 cv.x
-#define R_CV2 cv.y
-#define R_CV3 cv.z
-
-static inline void psx_gte_i_mvmva(psx_cpu_t* cpu) {
- R_FLAG = 0;
-
- gte_matrix_t mx = { 0 };
- gte_vertex_t v = { 0 };
- gte_vec3_t cv = { 0 };
-
- switch (cpu->gte_mx) {
- case 0: mx = cpu->cop2_cr.rt; break;
- case 1: mx = cpu->cop2_cr.l; break;
- case 2: mx = cpu->cop2_cr.lr; break;
- case 3: {
- R_MX11 = -(R_RC << 4);
- R_MX12 = R_RC << 4;
- R_MX13 = R_IR0;
- R_MX21 = R_RT13;
- R_MX22 = R_RT13;
- R_MX23 = R_RT13;
- R_MX31 = R_RT22;
- R_MX32 = R_RT22;
- R_MX33 = R_RT22;
- } break;
- }
-
- switch (cpu->gte_v) {
- case 0: case 1: case 2:
- v = cpu->cop2_dr.v[cpu->gte_v];
- break;
-
- case 3: {
- v.p[0] = R_IR1;
- v.p[1] = R_IR2;
- v.z = R_IR3;
- } break;
- }
-
- switch (cpu->gte_cv) {
- case 0: cv = cpu->cop2_cr.tr; break;
- case 1: cv = cpu->cop2_cr.bk; break;
- case 2: cv = cpu->cop2_cr.fc; break;
- case 3: {
- cv.x = 0;
- cv.y = 0;
- cv.z = 0;
- } break;
- }
-
- // Bugged case (CV=FC)
- if (cpu->gte_cv == 2) {
- R_MAC1 = gte_clamp_mac(cpu, 1, gte_check_mac(cpu, 1, I64(R_MX12) * I64(R_VY)) + (I64(R_MX13) * I64(R_VZ)));
- R_MAC2 = gte_clamp_mac(cpu, 2, gte_check_mac(cpu, 2, I64(R_MX22) * I64(R_VY)) + (I64(R_MX23) * I64(R_VZ)));
- R_MAC3 = gte_clamp_mac(cpu, 3, gte_check_mac(cpu, 3, I64(R_MX32) * I64(R_VY)) + (I64(R_MX33) * I64(R_VZ)));
-
- int64_t mac1 = gte_clamp_mac(cpu, 1, (I64(R_CV1) << 12) + (I64(R_MX11) * I64(R_VX)));
- int64_t mac2 = gte_clamp_mac(cpu, 2, (I64(R_CV2) << 12) + (I64(R_MX21) * I64(R_VX)));
- int64_t mac3 = gte_clamp_mac(cpu, 3, (I64(R_CV3) << 12) + (I64(R_MX31) * I64(R_VX)));
-
- gte_clamp_ir(cpu, 1, mac1, 0);
- gte_clamp_ir(cpu, 2, mac2, 0);
- gte_clamp_ir(cpu, 3, mac3, 0);
- } else {
- R_MAC1 = gte_clamp_mac(cpu, 1, gte_check_mac(cpu, 1, gte_check_mac(cpu, 1, (I64(R_CV1) << 12) + (I64(R_MX11) * I64(R_VX))) + (I64(R_MX12) * I64(R_VY))) + (I64(R_MX13) * I64(R_VZ)));
- R_MAC2 = gte_clamp_mac(cpu, 2, gte_check_mac(cpu, 2, gte_check_mac(cpu, 2, (I64(R_CV2) << 12) + (I64(R_MX21) * I64(R_VX))) + (I64(R_MX22) * I64(R_VY))) + (I64(R_MX23) * I64(R_VZ)));
- R_MAC3 = gte_clamp_mac(cpu, 3, gte_check_mac(cpu, 3, gte_check_mac(cpu, 3, (I64(R_CV3) << 12) + (I64(R_MX31) * I64(R_VX))) + (I64(R_MX32) * I64(R_VY))) + (I64(R_MX33) * I64(R_VZ)));
- }
-
- R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm);
- R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm);
- R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm);
-}
-
-#undef R_VX
-#undef R_VY
-#undef R_VZ
-#undef R_MX11
-#undef R_MX12
-#undef R_MX13
-#undef R_MX21
-#undef R_MX22
-#undef R_MX23
-#undef R_MX31
-#undef R_MX32
-#undef R_MX33
-#undef R_CV1
-#undef R_CV2
-#undef R_CV3
-
-// To-do: Fix flags
-static inline void psx_gte_i_ncds(psx_cpu_t* cpu) {
- R_FLAG = 0;
-
- NCDS(0);
-}
-
-static inline void psx_gte_i_cdp(psx_cpu_t* cpu) {
- R_FLAG = 0;
- R_MAC1 = gte_clamp_mac(cpu, 1, gte_check_mac(cpu, 1, gte_check_mac(cpu, 1, (I64(R_RBK) << 12) + (I64(R_LR1) * I64(R_IR1))) + (I64(R_LR2) * I64(R_IR2))) + (I64(R_LR3) * I64(R_IR3)));
- R_MAC2 = gte_clamp_mac(cpu, 2, gte_check_mac(cpu, 2, gte_check_mac(cpu, 2, (I64(R_GBK) << 12) + (I64(R_LG1) * I64(R_IR1))) + (I64(R_LG2) * I64(R_IR2))) + (I64(R_LG3) * I64(R_IR3)));
- R_MAC3 = gte_clamp_mac(cpu, 3, gte_check_mac(cpu, 3, gte_check_mac(cpu, 3, (I64(R_BBK) << 12) + (I64(R_LB1) * I64(R_IR1))) + (I64(R_LB2) * I64(R_IR2))) + (I64(R_LB3) * I64(R_IR3)));
- R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm);
- R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm);
- R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm);
- int64_t ir1 = gte_clamp_ir(cpu, 1, gte_clamp_mac(cpu, 1, ((I64(R_RFC) << 12) - ((I64(R_RC << 4)) * I64(R_IR1)))), 0);
- int64_t ir2 = gte_clamp_ir(cpu, 2, gte_clamp_mac(cpu, 2, ((I64(R_GFC) << 12) - ((I64(R_GC << 4)) * I64(R_IR2)))), 0);
- int64_t ir3 = gte_clamp_ir(cpu, 3, gte_clamp_mac(cpu, 3, ((I64(R_BFC) << 12) - ((I64(R_BC << 4)) * I64(R_IR3)))), 0);
- R_MAC1 = gte_clamp_mac(cpu, 1, (I64(R_RC << 4) * I64(R_IR1)) + (I64(R_IR0) * ir1));
- R_MAC2 = gte_clamp_mac(cpu, 2, (I64(R_GC << 4) * I64(R_IR2)) + (I64(R_IR0) * ir2));
- R_MAC3 = gte_clamp_mac(cpu, 3, (I64(R_BC << 4) * I64(R_IR3)) + (I64(R_IR0) * ir3));
- R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm);
- R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm);
- R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm);
- R_RGB0 = R_RGB1;
- R_RGB1 = R_RGB2;
- R_RC2 = gte_clamp_rgb(cpu, 1, R_MAC1 >> 4);
- R_GC2 = gte_clamp_rgb(cpu, 2, R_MAC2 >> 4);
- R_BC2 = gte_clamp_rgb(cpu, 3, R_MAC3 >> 4);
- R_CD2 = R_CODE;
-}
-
-static inline void psx_gte_i_ncdt(psx_cpu_t* cpu) {
- R_FLAG = 0;
- NCDS(0);
- NCDS(1);
- NCDS(2);
-}
-
-static inline void psx_gte_i_nccs(psx_cpu_t* cpu) {
- R_FLAG = 0;
- NCCS(0);
-}
-
-static inline void psx_gte_i_cc(psx_cpu_t* cpu) {
- R_FLAG = 0;
- R_MAC1 = gte_clamp_mac(cpu, 1, gte_check_mac(cpu, 1, gte_check_mac(cpu, 1, (I64(R_RBK) << 12) + (I64(R_LR1) * I64(R_IR1))) + (I64(R_LR2) * I64(R_IR2))) + (I64(R_LR3) * I64(R_IR3)));
- R_MAC2 = gte_clamp_mac(cpu, 2, gte_check_mac(cpu, 2, gte_check_mac(cpu, 2, (I64(R_GBK) << 12) + (I64(R_LG1) * I64(R_IR1))) + (I64(R_LG2) * I64(R_IR2))) + (I64(R_LG3) * I64(R_IR3)));
- R_MAC3 = gte_clamp_mac(cpu, 3, gte_check_mac(cpu, 3, gte_check_mac(cpu, 3, (I64(R_BBK) << 12) + (I64(R_LB1) * I64(R_IR1))) + (I64(R_LB2) * I64(R_IR2))) + (I64(R_LB3) * I64(R_IR3)));
- R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm);
- R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm);
- R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm);
- R_MAC1 = gte_clamp_mac(cpu, 1, (I64(R_RC) * I64(R_IR1)) << 4);
- R_MAC2 = gte_clamp_mac(cpu, 2, (I64(R_GC) * I64(R_IR2)) << 4);
- R_MAC3 = gte_clamp_mac(cpu, 3, (I64(R_BC) * I64(R_IR3)) << 4);
- R_RGB0 = R_RGB1;
- R_RGB1 = R_RGB2;
- R_CD2 = R_CODE;
- R_RC2 = gte_clamp_rgb(cpu, 1, R_MAC1 >> 4);
- R_GC2 = gte_clamp_rgb(cpu, 2, R_MAC2 >> 4);
- R_BC2 = gte_clamp_rgb(cpu, 3, R_MAC3 >> 4);
- R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm);
- R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm);
- R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm);
-}
-
-static inline void psx_gte_i_ncs(psx_cpu_t* cpu) {
- R_FLAG = 0;
- NCS(0);
-}
-
-static inline void psx_gte_i_nct(psx_cpu_t* cpu) {
- R_FLAG = 0;
- NCS(0);
- NCS(1);
- NCS(2);
-}
-
-static inline void psx_gte_i_sqr(psx_cpu_t* cpu) {
- R_FLAG = 0;
-
- R_MAC1 = gte_clamp_mac(cpu, 1, I64(R_IR1) * I64(R_IR1));
- R_MAC2 = gte_clamp_mac(cpu, 2, I64(R_IR2) * I64(R_IR2));
- R_MAC3 = gte_clamp_mac(cpu, 3, I64(R_IR3) * I64(R_IR3));
-
- R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm);
- R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm);
- R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm);
-}
-
-static inline void psx_gte_i_dcpl(psx_cpu_t* cpu) {
- R_FLAG = 0;
-
- R_MAC1 = gte_clamp_mac(cpu, 1, I64(R_RC) * I64(R_IR1)) << 4;
- R_MAC2 = gte_clamp_mac(cpu, 2, I64(R_GC) * I64(R_IR2)) << 4;
- R_MAC3 = gte_clamp_mac(cpu, 3, I64(R_BC) * I64(R_IR3)) << 4;
- int64_t ir1 = gte_clamp_ir(cpu, 1, gte_clamp_mac(cpu, 1, ((I64(R_RFC) << 12) - ((I64(R_RC << 4)) * I64(R_IR1)))), 0);
- int64_t ir2 = gte_clamp_ir(cpu, 2, gte_clamp_mac(cpu, 2, ((I64(R_GFC) << 12) - ((I64(R_GC << 4)) * I64(R_IR2)))), 0);
- int64_t ir3 = gte_clamp_ir(cpu, 3, gte_clamp_mac(cpu, 3, ((I64(R_BFC) << 12) - ((I64(R_BC << 4)) * I64(R_IR3)))), 0);
- R_MAC1 = gte_clamp_mac(cpu, 1, ((I64(R_RC << 4)) * I64(R_IR1)) + (I64(R_IR0) * ir1));
- R_MAC2 = gte_clamp_mac(cpu, 2, ((I64(R_GC << 4)) * I64(R_IR2)) + (I64(R_IR0) * ir2));
- R_MAC3 = gte_clamp_mac(cpu, 3, ((I64(R_BC << 4)) * I64(R_IR3)) + (I64(R_IR0) * ir3));
- R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm);
- R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm);
- R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm);
- R_RGB0 = R_RGB1;
- R_RGB1 = R_RGB2;
- R_CD2 = R_CODE;
- R_RC2 = gte_clamp_rgb(cpu, 1, R_MAC1 >> 4);
- R_GC2 = gte_clamp_rgb(cpu, 2, R_MAC2 >> 4);
- R_BC2 = gte_clamp_rgb(cpu, 3, R_MAC3 >> 4);
-}
-
-static inline void psx_gte_i_dpct(psx_cpu_t* cpu) {
- R_FLAG = 0;
- DPCT1;
- DPCT1;
- DPCT1;
-}
-
-static inline void psx_gte_i_avsz3(psx_cpu_t* cpu) {
- R_FLAG = 0;
-
- int64_t avg = I64(R_ZSF3) * (R_SZ1 + R_SZ2 + R_SZ3);
-
- R_MAC0 = (int)gte_clamp_mac0(cpu, avg);
- R_OTZ = gte_clamp_sz3(cpu, avg >> 12);
-}
-
-static inline void psx_gte_i_avsz4(psx_cpu_t* cpu) {
- R_FLAG = 0;
-
- int64_t avg = I64(R_ZSF4) * (R_SZ0 + R_SZ1 + R_SZ2 + R_SZ3);
-
- R_MAC0 = (int)gte_clamp_mac0(cpu, avg);
- R_OTZ = gte_clamp_sz3(cpu, avg >> 12);
-}
-
-static inline void psx_gte_i_rtpt(psx_cpu_t* cpu) {
- R_FLAG = 0;
- GTE_RTP(0);
- GTE_RTP(1);
- GTE_RTP_DQ(2);
-}
-
-static inline void psx_gte_i_gpf(psx_cpu_t* cpu) {
- R_FLAG = 0;
-
- R_MAC1 = gte_clamp_mac(cpu, 1, R_IR0 * R_IR1);
- R_MAC2 = gte_clamp_mac(cpu, 2, R_IR0 * R_IR2);
- R_MAC3 = gte_clamp_mac(cpu, 3, R_IR0 * R_IR3);
- R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm);
- R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm);
- R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm);
- R_RGB0 = R_RGB1;
- R_RGB1 = R_RGB2;
- R_CD2 = R_CODE;
- R_RC2 = gte_clamp_rgb(cpu, 1, R_MAC1 >> 4);
- R_GC2 = gte_clamp_rgb(cpu, 2, R_MAC2 >> 4);
- R_BC2 = gte_clamp_rgb(cpu, 3, R_MAC3 >> 4);
-}
-
-static inline void psx_gte_i_gpl(psx_cpu_t* cpu) {
- R_FLAG = 0;
-
- R_MAC1 = gte_clamp_mac(cpu, 1, (I64(R_MAC1) << cpu->gte_sf) + (R_IR0 * R_IR1));
- R_MAC2 = gte_clamp_mac(cpu, 2, (I64(R_MAC2) << cpu->gte_sf) + (R_IR0 * R_IR2));
- R_MAC3 = gte_clamp_mac(cpu, 3, (I64(R_MAC3) << cpu->gte_sf) + (R_IR0 * R_IR3));
- R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm);
- R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm);
- R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm);
- R_RGB0 = R_RGB1;
- R_RGB1 = R_RGB2;
- R_CD2 = R_CODE;
- R_RC2 = gte_clamp_rgb(cpu, 1, R_MAC1 >> 4);
- R_GC2 = gte_clamp_rgb(cpu, 2, R_MAC2 >> 4);
- R_BC2 = gte_clamp_rgb(cpu, 3, R_MAC3 >> 4);
-}
-
-static inline void psx_gte_i_ncct(psx_cpu_t* cpu) {
- R_FLAG = 0;
- NCCS(0);
- NCCS(1);
- NCCS(2);
-}
-
-int psx_cpu_execute(psx_cpu_t* cpu) {
- switch ((cpu->opcode & 0xfc000000) >> 26) {
- case 0x00000000 >> 26: {
- switch (cpu->opcode & 0x0000003f) {
- case 0x00000000: psx_cpu_i_sll(cpu); return 2;
- case 0x00000002: psx_cpu_i_srl(cpu); return 2;
- case 0x00000003: psx_cpu_i_sra(cpu); return 2;
- case 0x00000004: psx_cpu_i_sllv(cpu); return 2;
- case 0x00000006: psx_cpu_i_srlv(cpu); return 2;
- case 0x00000007: psx_cpu_i_srav(cpu); return 2;
- case 0x00000008: psx_cpu_i_jr(cpu); return 2;
- case 0x00000009: psx_cpu_i_jalr(cpu); return 2;
- case 0x0000000c: psx_cpu_i_syscall(cpu); return 2;
- case 0x0000000d: psx_cpu_i_break(cpu); return 2;
- case 0x00000010: psx_cpu_i_mfhi(cpu); return 2;
- case 0x00000011: psx_cpu_i_mthi(cpu); return 2;
- case 0x00000012: psx_cpu_i_mflo(cpu); return 2;
- case 0x00000013: psx_cpu_i_mtlo(cpu); return 2;
- case 0x00000018: psx_cpu_i_mult(cpu); return 2;
- case 0x00000019: psx_cpu_i_multu(cpu); return 2;
- case 0x0000001a: psx_cpu_i_div(cpu); return 2;
- case 0x0000001b: psx_cpu_i_divu(cpu); return 2;
- case 0x00000020: psx_cpu_i_add(cpu); return 2;
- case 0x00000021: psx_cpu_i_addu(cpu); return 2;
- case 0x00000022: psx_cpu_i_sub(cpu); return 2;
- case 0x00000023: psx_cpu_i_subu(cpu); return 2;
- case 0x00000024: psx_cpu_i_and(cpu); return 2;
- case 0x00000025: psx_cpu_i_or(cpu); return 2;
- case 0x00000026: psx_cpu_i_xor(cpu); return 2;
- case 0x00000027: psx_cpu_i_nor(cpu); return 2;
- case 0x0000002a: psx_cpu_i_slt(cpu); return 2;
- case 0x0000002b: psx_cpu_i_sltu(cpu); return 2;
- } break;
- } break;
- case 0x04000000 >> 26: {
- cpu->branch = 1;
- cpu->branch_taken = 0;
-
- switch ((cpu->opcode & 0x001f0000) >> 16) {
- case 0x00000000 >> 16: psx_cpu_i_bltz(cpu); return 2;
- case 0x00010000 >> 16: psx_cpu_i_bgez(cpu); return 2;
- case 0x00100000 >> 16: psx_cpu_i_bltzal(cpu); return 2;
- case 0x00110000 >> 16: psx_cpu_i_bgezal(cpu); return 2;
- // bltz/bgez dupes
- default: {
- if (cpu->opcode & 0x00010000) {
- psx_cpu_i_bgez(cpu);
- } else {
- psx_cpu_i_bltz(cpu);
- }
- } return 2;
- } break;
- } break;
- case 0x08000000 >> 26: psx_cpu_i_j(cpu); return 2;
- case 0x0c000000 >> 26: psx_cpu_i_jal(cpu); return 2;
- case 0x10000000 >> 26: psx_cpu_i_beq(cpu); return 2;
- case 0x14000000 >> 26: psx_cpu_i_bne(cpu); return 2;
- case 0x18000000 >> 26: psx_cpu_i_blez(cpu); return 2;
- case 0x1c000000 >> 26: psx_cpu_i_bgtz(cpu); return 2;
- case 0x20000000 >> 26: psx_cpu_i_addi(cpu); return 2;
- case 0x24000000 >> 26: psx_cpu_i_addiu(cpu); return 2;
- case 0x28000000 >> 26: psx_cpu_i_slti(cpu); return 2;
- case 0x2c000000 >> 26: psx_cpu_i_sltiu(cpu); return 2;
- case 0x30000000 >> 26: psx_cpu_i_andi(cpu); return 2;
- case 0x34000000 >> 26: psx_cpu_i_ori(cpu); return 2;
- case 0x38000000 >> 26: psx_cpu_i_xori(cpu); return 2;
- case 0x3c000000 >> 26: psx_cpu_i_lui(cpu); return 2;
- case 0x40000000 >> 26: {
- switch ((cpu->opcode & 0x03e00000) >> 21) {
- case 0x00000000 >> 21: psx_cpu_i_mfc0(cpu); return 2;
- case 0x00800000 >> 21: psx_cpu_i_mtc0(cpu); return 2;
- case 0x02000000 >> 21: psx_cpu_i_rfe(cpu); return 2;
- }
- } break;
- case 0x48000000 >> 26: {
- switch ((cpu->opcode & 0x03e00000) >> 21) {
- case 0x00000000 >> 21: psx_cpu_i_mfc2(cpu); return 2;
- case 0x00400000 >> 21: psx_cpu_i_cfc2(cpu); return 2;
- case 0x00800000 >> 21: psx_cpu_i_mtc2(cpu); return 2;
- case 0x00c00000 >> 21: psx_cpu_i_ctc2(cpu); return 2;
- default: {
- DO_PENDING_LOAD;
-
- cpu->gte_sf = ((cpu->opcode & 0x80000) != 0) * 12;
- cpu->gte_lm = (cpu->opcode & 0x400) != 0;
- cpu->gte_cv = (cpu->opcode >> 13) & 3;
- cpu->gte_v = (cpu->opcode >> 15) & 3;
- cpu->gte_mx = (cpu->opcode >> 17) & 3;
-
- switch (cpu->opcode & 0x3f) {
- case 0x01: psx_gte_i_rtps(cpu); return 15;
- case 0x06: psx_gte_i_nclip(cpu); return 8;
- case 0x0c: psx_gte_i_op(cpu); return 6;
- case 0x10: psx_gte_i_dpcs(cpu); return 8;
- case 0x11: psx_gte_i_intpl(cpu); return 8;
- case 0x12: psx_gte_i_mvmva(cpu); return 8;
- case 0x13: psx_gte_i_ncds(cpu); return 19;
- case 0x14: psx_gte_i_cdp(cpu); return 13;
- case 0x16: psx_gte_i_ncdt(cpu); return 44;
- case 0x1b: psx_gte_i_nccs(cpu); return 17;
- case 0x1c: psx_gte_i_cc(cpu); return 11;
- case 0x1e: psx_gte_i_ncs(cpu); return 14;
- case 0x20: psx_gte_i_nct(cpu); return 30;
- case 0x28: psx_gte_i_sqr(cpu); return 5;
- case 0x29: psx_gte_i_dcpl(cpu); return 8;
- case 0x2a: psx_gte_i_dpct(cpu); return 17;
- case 0x2d: psx_gte_i_avsz3(cpu); return 5;
- case 0x2e: psx_gte_i_avsz4(cpu); return 6;
- case 0x30: psx_gte_i_rtpt(cpu); return 23;
- case 0x3d: psx_gte_i_gpf(cpu); return 5;
- case 0x3e: psx_gte_i_gpl(cpu); return 5;
- case 0x3f: psx_gte_i_ncct(cpu); return 39;
- default: psx_gte_i_invalid(cpu); return 0;
- }
- } break;
- }
- } break;
- case 0x80000000 >> 26: psx_cpu_i_lb(cpu); return 2;
- case 0x84000000 >> 26: psx_cpu_i_lh(cpu); return 2;
- case 0x88000000 >> 26: psx_cpu_i_lwl(cpu); return 2;
- case 0x8c000000 >> 26: psx_cpu_i_lw(cpu); return 2;
- case 0x90000000 >> 26: psx_cpu_i_lbu(cpu); return 2;
- case 0x94000000 >> 26: psx_cpu_i_lhu(cpu); return 2;
- case 0x98000000 >> 26: psx_cpu_i_lwr(cpu); return 2;
- case 0xa0000000 >> 26: psx_cpu_i_sb(cpu); return 2;
- case 0xa4000000 >> 26: psx_cpu_i_sh(cpu); return 2;
- case 0xa8000000 >> 26: psx_cpu_i_swl(cpu); return 2;
- case 0xac000000 >> 26: psx_cpu_i_sw(cpu); return 2;
- case 0xb8000000 >> 26: psx_cpu_i_swr(cpu); return 2;
- case 0xc0000000 >> 26: psx_cpu_i_lwc0(cpu); return 2;
- case 0xc4000000 >> 26: psx_cpu_i_lwc1(cpu); return 2;
- case 0xc8000000 >> 26: psx_cpu_i_lwc2(cpu); return 2;
- case 0xcc000000 >> 26: psx_cpu_i_lwc3(cpu); return 2;
- case 0xe0000000 >> 26: psx_cpu_i_swc0(cpu); return 2;
- case 0xe4000000 >> 26: psx_cpu_i_swc1(cpu); return 2;
- case 0xe8000000 >> 26: psx_cpu_i_swc2(cpu); return 2;
- case 0xec000000 >> 26: psx_cpu_i_swc3(cpu); return 2;
- }
-
- return 0;
-}
-
-#undef R_R0
-#undef R_A0
-#undef R_RA
-
-#undef OP
-#undef S
-#undef T
-#undef D
-#undef IMM5
-#undef CMT
-#undef SOP
-#undef IMM26
-#undef IMM16
-#undef IMM16S
-
-#undef TRACE_M
-#undef TRACE_I16S
-#undef TRACE_I16D
-#undef TRACE_I5D
-#undef TRACE_I26
-#undef TRACE_RT
-#undef TRACE_C0M
-#undef TRACE_C2M
-#undef TRACE_C2MC
-#undef TRACE_B
-#undef TRACE_RS
-#undef TRACE_MTF
-#undef TRACE_RD
-#undef TRACE_MD
-#undef TRACE_I20
-#undef TRACE_N
-
-#undef DO_PENDING_LOAD
-
-#undef DEBUG_ALL
-
-#undef SE8
+#define R_RT12 cpu->cop2_cr.rt.m[0].c[1]
+#define R_RT13 cpu->cop2_cr.rt.m[1].c[0]
+#define R_RT21 cpu->cop2_cr.rt.m[1].c[1]
+#define R_RT22 cpu->cop2_cr.rt.m[2].c[0]
+#define R_RT23 cpu->cop2_cr.rt.m[2].c[1]
+#define R_RT31 cpu->cop2_cr.rt.m[3].c[0]
+#define R_RT32 cpu->cop2_cr.rt.m[3].c[1]
+#define R_RT33 cpu->cop2_cr.rt.m33
+#define R_MAC0 cpu->cop2_dr.mac[0]
+#define R_MAC1 cpu->cop2_dr.mac[1]
+#define R_MAC2 cpu->cop2_dr.mac[2]
+#define R_MAC3 cpu->cop2_dr.mac[3]
+#define R_OFX cpu->cop2_cr.ofx
+#define R_OFY cpu->cop2_cr.ofy
+#define R_IR0 cpu->cop2_dr.ir[0]
+#define R_IR1 cpu->cop2_dr.ir[1]
+#define R_IR2 cpu->cop2_dr.ir[2]
+#define R_IR3 cpu->cop2_dr.ir[3]
+#define R_SXY0 cpu->cop2_dr.sxy[0].xy
+#define R_SX0 cpu->cop2_dr.sxy[0].p[0]
+#define R_SY0 cpu->cop2_dr.sxy[0].p[1]
+#define R_SZ0 cpu->cop2_dr.sz[0]
+#define R_SXY1 cpu->cop2_dr.sxy[1].xy
+#define R_SX1 cpu->cop2_dr.sxy[1].p[0]
+#define R_SY1 cpu->cop2_dr.sxy[1].p[1]
+#define R_SZ1 cpu->cop2_dr.sz[1]
+#define R_SXY2 cpu->cop2_dr.sxy[2].xy
+#define R_SX2 cpu->cop2_dr.sxy[2].p[0]
+#define R_SY2 cpu->cop2_dr.sxy[2].p[1]
+#define R_SZ2 cpu->cop2_dr.sz[2]
+#define R_SZ3 cpu->cop2_dr.sz[3]
+#define R_DQA cpu->cop2_cr.dqa
+#define R_DQB cpu->cop2_cr.dqb
+#define R_ZSF3 cpu->cop2_cr.zsf3
+#define R_ZSF4 cpu->cop2_cr.zsf4
+#define R_OTZ cpu->cop2_dr.otz
+#define R_H cpu->cop2_cr.h
+#define R_RC cpu->cop2_dr.rgbc.c[0]
+#define R_GC cpu->cop2_dr.rgbc.c[1]
+#define R_BC cpu->cop2_dr.rgbc.c[2]
+#define R_CODE cpu->cop2_dr.rgbc.c[3]
+#define R_RGBC cpu->cop2_dr.rgbc.rgbc
+#define R_RFC cpu->cop2_cr.fc.x
+#define R_GFC cpu->cop2_cr.fc.y
+#define R_BFC cpu->cop2_cr.fc.z
+#define R_RGB0 cpu->cop2_dr.rgb[0].rgbc
+#define R_RGB1 cpu->cop2_dr.rgb[1].rgbc
+#define R_RGB2 cpu->cop2_dr.rgb[2].rgbc
+#define R_RC0 cpu->cop2_dr.rgb[0].c[0]
+#define R_GC0 cpu->cop2_dr.rgb[0].c[1]
+#define R_BC0 cpu->cop2_dr.rgb[0].c[2]
+#define R_CD0 cpu->cop2_dr.rgb[0].c[3]
+#define R_RC1 cpu->cop2_dr.rgb[1].c[0]
+#define R_GC1 cpu->cop2_dr.rgb[1].c[1]
+#define R_BC1 cpu->cop2_dr.rgb[1].c[2]
+#define R_CD1 cpu->cop2_dr.rgb[1].c[3]
+#define R_RC2 cpu->cop2_dr.rgb[2].c[0]
+#define R_GC2 cpu->cop2_dr.rgb[2].c[1]
+#define R_BC2 cpu->cop2_dr.rgb[2].c[2]
+#define R_CD2 cpu->cop2_dr.rgb[2].c[3]
+#define R_L11 cpu->cop2_cr.l.m[0].c[0]
+#define R_L12 cpu->cop2_cr.l.m[0].c[1]
+#define R_L13 cpu->cop2_cr.l.m[1].c[0]
+#define R_L21 cpu->cop2_cr.l.m[1].c[1]
+#define R_L22 cpu->cop2_cr.l.m[2].c[0]
+#define R_L23 cpu->cop2_cr.l.m[2].c[1]
+#define R_L31 cpu->cop2_cr.l.m[3].c[0]
+#define R_L32 cpu->cop2_cr.l.m[3].c[1]
+#define R_L33 cpu->cop2_cr.l.m33
+#define R_RBK cpu->cop2_cr.bk.x
+#define R_GBK cpu->cop2_cr.bk.y
+#define R_BBK cpu->cop2_cr.bk.z
+#define R_LR1 cpu->cop2_cr.lr.m[0].c[0]
+#define R_LR2 cpu->cop2_cr.lr.m[0].c[1]
+#define R_LR3 cpu->cop2_cr.lr.m[1].c[0]
+#define R_LG1 cpu->cop2_cr.lr.m[1].c[1]
+#define R_LG2 cpu->cop2_cr.lr.m[2].c[0]
+#define R_LG3 cpu->cop2_cr.lr.m[2].c[1]
+#define R_LB1 cpu->cop2_cr.lr.m[3].c[0]
+#define R_LB2 cpu->cop2_cr.lr.m[3].c[1]
+#define R_LB3 cpu->cop2_cr.lr.m33
+
+#define GTE_RTP_DQ(i) { \+ int64_t vx = (int64_t)((int16_t)cpu->cop2_dr.v[i].p[0]); \
+ int64_t vy = (int64_t)((int16_t)cpu->cop2_dr.v[i].p[1]); \
+ int64_t vz = (int64_t)cpu->cop2_dr.v[i].z; \
+ R_MAC1 = gte_clamp_mac(cpu, 1, gte_check_mac(cpu, 1, gte_check_mac(cpu, 1, (((int64_t)R_TRX) << 12) + (I64((int16_t)R_RT11) * vx)) + (I64((int16_t)R_RT12) * vy)) + (I64((int16_t)R_RT13) * vz)); \
+ R_MAC2 = gte_clamp_mac(cpu, 2, gte_check_mac(cpu, 2, gte_check_mac(cpu, 2, (((int64_t)R_TRY) << 12) + (I64((int16_t)R_RT21) * vx)) + (I64((int16_t)R_RT22) * vy)) + (I64((int16_t)R_RT23) * vz)); \
+ R_MAC3 = gte_clamp_mac(cpu, 3, gte_check_mac(cpu, 3, gte_check_mac(cpu, 3, (((int64_t)R_TRZ) << 12) + (I64((int16_t)R_RT31) * vx)) + (I64((int16_t)R_RT32) * vy)) + (I64((int16_t)R_RT33) * vz)); \
+ R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm); \
+ R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm); \
+ R_IR3 = gte_clamp_ir_z(cpu, cpu->s_mac3, cpu->gte_sf, cpu->gte_lm); \
+ R_SZ0 = R_SZ1; \
+ R_SZ1 = R_SZ2; \
+ R_SZ2 = R_SZ3; \
+ R_SZ3 = gte_clamp_sz3(cpu, cpu->s_mac3 >> 12); \
+ int32_t div = gte_divide(cpu, R_H, R_SZ3); \
+ R_SXY0 = R_SXY1; \
+ R_SXY1 = R_SXY2; \
+ R_SX2 = gte_clamp_sxy(cpu, 1, (gte_clamp_mac0(cpu, (int64_t)((int32_t)R_OFX) + ((int64_t)R_IR1 * div)) >> 16)); \
+ R_SY2 = gte_clamp_sxy(cpu, 2, (gte_clamp_mac0(cpu, (int64_t)((int32_t)R_OFY) + ((int64_t)R_IR2 * div)) >> 16)); \
+ R_MAC0 = gte_clamp_mac0(cpu, ((int64_t)R_DQB) + (((int64_t)R_DQA) * div)); \
+ R_IR0 = gte_clamp_ir0(cpu, cpu->s_mac0 >> 12); }
+
+#define GTE_RTP(i) { \+ int64_t vx = (int64_t)((int16_t)cpu->cop2_dr.v[i].p[0]); \
+ int64_t vy = (int64_t)((int16_t)cpu->cop2_dr.v[i].p[1]); \
+ int64_t vz = (int64_t)cpu->cop2_dr.v[i].z; \
+ R_MAC1 = gte_clamp_mac(cpu, 1, gte_check_mac(cpu, 1, gte_check_mac(cpu, 1, (((int64_t)R_TRX) << 12) + (I64((int16_t)R_RT11) * vx)) + (I64((int16_t)R_RT12) * vy)) + (I64((int16_t)R_RT13) * vz)); \
+ R_MAC2 = gte_clamp_mac(cpu, 2, gte_check_mac(cpu, 2, gte_check_mac(cpu, 2, (((int64_t)R_TRY) << 12) + (I64((int16_t)R_RT21) * vx)) + (I64((int16_t)R_RT22) * vy)) + (I64((int16_t)R_RT23) * vz)); \
+ R_MAC3 = gte_clamp_mac(cpu, 3, gte_check_mac(cpu, 3, gte_check_mac(cpu, 3, (((int64_t)R_TRZ) << 12) + (I64((int16_t)R_RT31) * vx)) + (I64((int16_t)R_RT32) * vy)) + (I64((int16_t)R_RT33) * vz)); \
+ R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm); \
+ R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm); \
+ R_IR3 = gte_clamp_ir_z(cpu, cpu->s_mac3, cpu->gte_sf, cpu->gte_lm); \
+ R_SZ0 = R_SZ1; \
+ R_SZ1 = R_SZ2; \
+ R_SZ2 = R_SZ3; \
+ R_SZ3 = gte_clamp_sz3(cpu, cpu->s_mac3 >> 12); \
+ int32_t div = gte_divide(cpu, R_H, R_SZ3); \
+ R_SXY0 = R_SXY1; \
+ R_SXY1 = R_SXY2; \
+ R_SX2 = gte_clamp_sxy(cpu, 1, (gte_clamp_mac0(cpu, (int64_t)((int32_t)R_OFX) + ((int64_t)R_IR1 * div)) >> 16)); \
+ R_SY2 = gte_clamp_sxy(cpu, 2, (gte_clamp_mac0(cpu, (int64_t)((int32_t)R_OFY) + ((int64_t)R_IR2 * div)) >> 16)); }
+
+#define DPCT1 { \+ int64_t mac1 = gte_clamp_mac(cpu, 1, (((int64_t)R_RFC) << 12) - (((int64_t)cpu->cop2_dr.rgb[0].c[0]) << 16)); \
+ int64_t mac2 = gte_clamp_mac(cpu, 2, (((int64_t)R_GFC) << 12) - (((int64_t)cpu->cop2_dr.rgb[0].c[1]) << 16)); \
+ int64_t mac3 = gte_clamp_mac(cpu, 3, (((int64_t)R_BFC) << 12) - (((int64_t)cpu->cop2_dr.rgb[0].c[2]) << 16)); \
+ int64_t ir1 = gte_clamp_ir(cpu, 1, mac1, 0); \
+ int64_t ir2 = gte_clamp_ir(cpu, 2, mac2, 0); \
+ int64_t ir3 = gte_clamp_ir(cpu, 3, mac3, 0); \
+ R_MAC1 = gte_clamp_mac(cpu, 1, (((int64_t)cpu->cop2_dr.rgb[0].c[0]) << 16) + (R_IR0 * ir1)); \
+ R_MAC2 = gte_clamp_mac(cpu, 2, (((int64_t)cpu->cop2_dr.rgb[0].c[1]) << 16) + (R_IR0 * ir2)); \
+ R_MAC3 = gte_clamp_mac(cpu, 3, (((int64_t)cpu->cop2_dr.rgb[0].c[2]) << 16) + (R_IR0 * ir3)); \
+ R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm); \
+ R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm); \
+ R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm); \
+ R_RGB0 = R_RGB1; \
+ R_RGB1 = R_RGB2; \
+ R_CD2 = R_CODE; \
+ R_RC2 = gte_clamp_rgb(cpu, 1, R_MAC1 >> 4); \
+ R_GC2 = gte_clamp_rgb(cpu, 2, R_MAC2 >> 4); \
+ R_BC2 = gte_clamp_rgb(cpu, 3, R_MAC3 >> 4); }
+
+#define NCCS(i) { \+ int64_t vx = (int64_t)((int16_t)cpu->cop2_dr.v[i].p[0]); \
+ int64_t vy = (int64_t)((int16_t)cpu->cop2_dr.v[i].p[1]); \
+ int64_t vz = (int64_t)cpu->cop2_dr.v[i].z; \
+ R_MAC1 = gte_clamp_mac(cpu, 1, (I64(R_L11) * vx) + (I64(R_L12) * vy) + (I64(R_L13) * vz)); \
+ R_MAC2 = gte_clamp_mac(cpu, 2, (I64(R_L21) * vx) + (I64(R_L22) * vy) + (I64(R_L23) * vz)); \
+ R_MAC3 = gte_clamp_mac(cpu, 3, (I64(R_L31) * vx) + (I64(R_L32) * vy) + (I64(R_L33) * vz)); \
+ R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm); \
+ R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm); \
+ R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm); \
+ R_MAC1 = gte_clamp_mac(cpu, 1, gte_check_mac(cpu, 1, gte_check_mac(cpu, 1, (I64(R_RBK) << 12) + (I64(R_LR1) * I64(R_IR1))) + (I64(R_LR2) * I64(R_IR2))) + (I64(R_LR3) * I64(R_IR3))); \
+ R_MAC2 = gte_clamp_mac(cpu, 2, gte_check_mac(cpu, 2, gte_check_mac(cpu, 2, (I64(R_GBK) << 12) + (I64(R_LG1) * I64(R_IR1))) + (I64(R_LG2) * I64(R_IR2))) + (I64(R_LG3) * I64(R_IR3))); \
+ R_MAC3 = gte_clamp_mac(cpu, 3, gte_check_mac(cpu, 3, gte_check_mac(cpu, 3, (I64(R_BBK) << 12) + (I64(R_LB1) * I64(R_IR1))) + (I64(R_LB2) * I64(R_IR2))) + (I64(R_LB3) * I64(R_IR3))); \
+ R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm); \
+ R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm); \
+ R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm); \
+ R_MAC1 = gte_clamp_mac(cpu, 1, (I64(R_RC) * I64(R_IR1)) << 4); \
+ R_MAC2 = gte_clamp_mac(cpu, 2, (I64(R_GC) * I64(R_IR2)) << 4); \
+ R_MAC3 = gte_clamp_mac(cpu, 3, (I64(R_BC) * I64(R_IR3)) << 4); \
+ R_RGB0 = R_RGB1; \
+ R_RGB1 = R_RGB2; \
+ R_CD2 = R_CODE; \
+ R_RC2 = gte_clamp_rgb(cpu, 1, R_MAC1 >> 4); \
+ R_GC2 = gte_clamp_rgb(cpu, 2, R_MAC2 >> 4); \
+ R_BC2 = gte_clamp_rgb(cpu, 3, R_MAC3 >> 4); \
+ R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm); \
+ R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm); \
+ R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm); }
+
+#define NCS(i) { \+ int64_t vx = (int64_t)((int16_t)cpu->cop2_dr.v[i].p[0]); \
+ int64_t vy = (int64_t)((int16_t)cpu->cop2_dr.v[i].p[1]); \
+ int64_t vz = (int64_t)cpu->cop2_dr.v[i].z; \
+ R_MAC1 = gte_clamp_mac(cpu, 1, (I64(R_L11) * vx) + (I64(R_L12) * vy) + (I64(R_L13) * vz)); \
+ R_MAC2 = gte_clamp_mac(cpu, 2, (I64(R_L21) * vx) + (I64(R_L22) * vy) + (I64(R_L23) * vz)); \
+ R_MAC3 = gte_clamp_mac(cpu, 3, (I64(R_L31) * vx) + (I64(R_L32) * vy) + (I64(R_L33) * vz)); \
+ R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm); \
+ R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm); \
+ R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm); \
+ R_MAC1 = gte_clamp_mac(cpu, 1, gte_check_mac(cpu, 1, gte_check_mac(cpu, 1, (I64(R_RBK) << 12) + (I64(R_LR1) * I64(R_IR1))) + (I64(R_LR2) * I64(R_IR2))) + (I64(R_LR3) * I64(R_IR3))); \
+ R_MAC2 = gte_clamp_mac(cpu, 2, gte_check_mac(cpu, 2, gte_check_mac(cpu, 2, (I64(R_GBK) << 12) + (I64(R_LG1) * I64(R_IR1))) + (I64(R_LG2) * I64(R_IR2))) + (I64(R_LG3) * I64(R_IR3))); \
+ R_MAC3 = gte_clamp_mac(cpu, 3, gte_check_mac(cpu, 3, gte_check_mac(cpu, 3, (I64(R_BBK) << 12) + (I64(R_LB1) * I64(R_IR1))) + (I64(R_LB2) * I64(R_IR2))) + (I64(R_LB3) * I64(R_IR3))); \
+ R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm); \
+ R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm); \
+ R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm); \
+ R_RGB0 = R_RGB1; \
+ R_RGB1 = R_RGB2; \
+ R_CD2 = R_CODE; \
+ R_RC2 = gte_clamp_rgb(cpu, 1, R_MAC1 >> 4); \
+ R_GC2 = gte_clamp_rgb(cpu, 2, R_MAC2 >> 4); \
+ R_BC2 = gte_clamp_rgb(cpu, 3, R_MAC3 >> 4); \
+ R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm); \
+ R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm); \
+ R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm); }
+
+#define NCDS(i) { \+ int64_t vx = (int64_t)((int16_t)cpu->cop2_dr.v[i].p[0]); \
+ int64_t vy = (int64_t)((int16_t)cpu->cop2_dr.v[i].p[1]); \
+ int64_t vz = (int64_t)cpu->cop2_dr.v[i].z; \
+ R_MAC1 = gte_clamp_mac(cpu, 1, (I64(R_L11) * vx) + (I64(R_L12) * vy) + (I64(R_L13) * vz)); \
+ R_MAC2 = gte_clamp_mac(cpu, 2, (I64(R_L21) * vx) + (I64(R_L22) * vy) + (I64(R_L23) * vz)); \
+ R_MAC3 = gte_clamp_mac(cpu, 3, (I64(R_L31) * vx) + (I64(R_L32) * vy) + (I64(R_L33) * vz)); \
+ R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm); \
+ R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm); \
+ R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm); \
+ R_MAC1 = gte_clamp_mac(cpu, 1, gte_check_mac(cpu, 1, gte_check_mac(cpu, 1, (I64(R_RBK) << 12) + (I64(R_LR1) * I64(R_IR1))) + (I64(R_LR2) * I64(R_IR2))) + (I64(R_LR3) * I64(R_IR3))); \
+ R_MAC2 = gte_clamp_mac(cpu, 2, gte_check_mac(cpu, 2, gte_check_mac(cpu, 2, (I64(R_GBK) << 12) + (I64(R_LG1) * I64(R_IR1))) + (I64(R_LG2) * I64(R_IR2))) + (I64(R_LG3) * I64(R_IR3))); \
+ R_MAC3 = gte_clamp_mac(cpu, 3, gte_check_mac(cpu, 3, gte_check_mac(cpu, 3, (I64(R_BBK) << 12) + (I64(R_LB1) * I64(R_IR1))) + (I64(R_LB2) * I64(R_IR2))) + (I64(R_LB3) * I64(R_IR3))); \
+ R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm); \
+ R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm); \
+ R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm); \
+ int64_t ir1 = gte_clamp_ir(cpu, 1, gte_clamp_mac(cpu, 1, ((I64(R_RFC) << 12) - ((I64(R_RC << 4)) * I64(R_IR1)))), 0); \
+ int64_t ir2 = gte_clamp_ir(cpu, 2, gte_clamp_mac(cpu, 2, ((I64(R_GFC) << 12) - ((I64(R_GC << 4)) * I64(R_IR2)))), 0); \
+ int64_t ir3 = gte_clamp_ir(cpu, 3, gte_clamp_mac(cpu, 3, ((I64(R_BFC) << 12) - ((I64(R_BC << 4)) * I64(R_IR3)))), 0); \
+ R_MAC1 = gte_clamp_mac(cpu, 1, ((I64(R_RC << 4)) * I64(R_IR1)) + (I64(R_IR0) * ir1)); \
+ R_MAC2 = gte_clamp_mac(cpu, 2, ((I64(R_GC << 4)) * I64(R_IR2)) + (I64(R_IR0) * ir2)); \
+ R_MAC3 = gte_clamp_mac(cpu, 3, ((I64(R_BC << 4)) * I64(R_IR3)) + (I64(R_IR0) * ir3)); \
+ R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm); \
+ R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm); \
+ R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm); \
+ R_RGB0 = R_RGB1; \
+ R_RGB1 = R_RGB2; \
+ R_CD2 = R_CODE; \
+ R_RC2 = gte_clamp_rgb(cpu, 1, R_MAC1 >> 4); \
+ R_GC2 = gte_clamp_rgb(cpu, 2, R_MAC2 >> 4); \
+ R_BC2 = gte_clamp_rgb(cpu, 3, R_MAC3 >> 4); }
+
+static inline void psx_gte_i_rtps(psx_cpu_t* cpu) {+ R_FLAG = 0;
+ GTE_RTP_DQ(0);
+}
+
+static inline void psx_gte_i_nclip(psx_cpu_t* cpu) {+ R_FLAG = 0;
+
+ int64_t value = I64((int16_t)R_SX0) * (I64((int16_t)R_SY1) - I64((int16_t)R_SY2));
+ value += I64((int16_t)R_SX1) * (I64((int16_t)R_SY2) - I64((int16_t)R_SY0));
+ value += I64((int16_t)R_SX2) * (I64((int16_t)R_SY0) - I64((int16_t)R_SY1));
+
+ R_MAC0 = (int)gte_clamp_mac0(cpu, value);
+}
+
+static inline void psx_gte_i_op(psx_cpu_t* cpu) {+ R_FLAG = 0;
+
+ R_MAC1 = gte_clamp_mac(cpu, 1, I64(I64((int16_t)R_RT22) * I64(R_IR3)) - I64((I64((int16_t)R_RT33) * I64(R_IR2))));
+ R_MAC2 = gte_clamp_mac(cpu, 2, I64(I64((int16_t)R_RT33) * I64(R_IR1)) - I64((I64((int16_t)R_RT11) * I64(R_IR3))));
+ R_MAC3 = gte_clamp_mac(cpu, 3, I64(I64((int16_t)R_RT11) * I64(R_IR2)) - I64((I64((int16_t)R_RT22) * I64(R_IR1))));
+
+ R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm);
+ R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm);
+ R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm);
+}
+
+static inline void psx_gte_i_dpcs(psx_cpu_t* cpu) {+ R_FLAG = 0;
+
+ int64_t mac1 = gte_clamp_mac(cpu, 1, (((int64_t)R_RFC) << 12) - (((int64_t)R_RC) << 16));
+ int64_t mac2 = gte_clamp_mac(cpu, 2, (((int64_t)R_GFC) << 12) - (((int64_t)R_GC) << 16));
+ int64_t mac3 = gte_clamp_mac(cpu, 3, (((int64_t)R_BFC) << 12) - (((int64_t)R_BC) << 16));
+
+ int64_t ir1 = gte_clamp_ir(cpu, 1, mac1, 0);
+ int64_t ir2 = gte_clamp_ir(cpu, 2, mac2, 0);
+ int64_t ir3 = gte_clamp_ir(cpu, 3, mac3, 0);
+
+ R_MAC1 = gte_clamp_mac(cpu, 1, (I64(R_RC) << 16) + (R_IR0 * ir1));
+ R_MAC2 = gte_clamp_mac(cpu, 2, (I64(R_GC) << 16) + (R_IR0 * ir2));
+ R_MAC3 = gte_clamp_mac(cpu, 3, (I64(R_BC) << 16) + (R_IR0 * ir3));
+
+ R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm);
+ R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm);
+ R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm);
+
+ R_RGB0 = R_RGB1;
+ R_RGB1 = R_RGB2;
+ R_CD2 = R_CODE;
+
+ R_RC2 = gte_clamp_rgb(cpu, 1, R_MAC1 >> 4);
+ R_GC2 = gte_clamp_rgb(cpu, 2, R_MAC2 >> 4);
+ R_BC2 = gte_clamp_rgb(cpu, 3, R_MAC3 >> 4);
+}
+
+static inline void psx_gte_i_intpl(psx_cpu_t* cpu) {+ R_FLAG = 0;
+
+ int64_t mac1 = gte_clamp_mac(cpu, 1, (((int64_t)R_RFC) << 12) - (I64(R_IR1) << 12));
+ int64_t mac2 = gte_clamp_mac(cpu, 2, (((int64_t)R_GFC) << 12) - (I64(R_IR2) << 12));
+ int64_t mac3 = gte_clamp_mac(cpu, 3, (((int64_t)R_BFC) << 12) - (I64(R_IR3) << 12));
+
+ int64_t ir1 = gte_clamp_ir(cpu, 1, mac1, 0);
+ int64_t ir2 = gte_clamp_ir(cpu, 2, mac2, 0);
+ int64_t ir3 = gte_clamp_ir(cpu, 3, mac3, 0);
+
+ R_MAC1 = gte_clamp_mac(cpu, 1, (I64(R_IR1) << 12) + (I64(R_IR0) * ir1));
+ R_MAC2 = gte_clamp_mac(cpu, 2, (I64(R_IR2) << 12) + (I64(R_IR0) * ir2));
+ R_MAC3 = gte_clamp_mac(cpu, 3, (I64(R_IR3) << 12) + (I64(R_IR0) * ir3));
+
+ R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm);
+ R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm);
+ R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm);
+
+ R_RGB0 = R_RGB1;
+ R_RGB1 = R_RGB2;
+ R_CD2 = R_CODE;
+
+ R_RC2 = gte_clamp_rgb(cpu, 1, R_MAC1 >> 4);
+ R_GC2 = gte_clamp_rgb(cpu, 2, R_MAC2 >> 4);
+ R_BC2 = gte_clamp_rgb(cpu, 3, R_MAC3 >> 4);
+}
+
+#define R_VX v.p[0]
+#define R_VY v.p[1]
+#define R_VZ v.z
+#define R_MX11 mx.m[0].c[0]
+#define R_MX12 mx.m[0].c[1]
+#define R_MX13 mx.m[1].c[0]
+#define R_MX21 mx.m[1].c[1]
+#define R_MX22 mx.m[2].c[0]
+#define R_MX23 mx.m[2].c[1]
+#define R_MX31 mx.m[3].c[0]
+#define R_MX32 mx.m[3].c[1]
+#define R_MX33 mx.m33
+#define R_CV1 cv.x
+#define R_CV2 cv.y
+#define R_CV3 cv.z
+
+static inline void psx_gte_i_mvmva(psx_cpu_t* cpu) {+ R_FLAG = 0;
+
+ gte_matrix_t mx = { 0 };+ gte_vertex_t v = { 0 };+ gte_vec3_t cv = { 0 };+
+ switch (cpu->gte_mx) {+ case 0: mx = cpu->cop2_cr.rt; break;
+ case 1: mx = cpu->cop2_cr.l; break;
+ case 2: mx = cpu->cop2_cr.lr; break;
+ case 3: {+ R_MX11 = -(R_RC << 4);
+ R_MX12 = R_RC << 4;
+ R_MX13 = R_IR0;
+ R_MX21 = R_RT13;
+ R_MX22 = R_RT13;
+ R_MX23 = R_RT13;
+ R_MX31 = R_RT22;
+ R_MX32 = R_RT22;
+ R_MX33 = R_RT22;
+ } break;
+ }
+
+ switch (cpu->gte_v) {+ case 0: case 1: case 2:
+ v = cpu->cop2_dr.v[cpu->gte_v];
+ break;
+
+ case 3: {+ v.p[0] = R_IR1;
+ v.p[1] = R_IR2;
+ v.z = R_IR3;
+ } break;
+ }
+
+ switch (cpu->gte_cv) {+ case 0: cv = cpu->cop2_cr.tr; break;
+ case 1: cv = cpu->cop2_cr.bk; break;
+ case 2: cv = cpu->cop2_cr.fc; break;
+ case 3: {+ cv.x = 0;
+ cv.y = 0;
+ cv.z = 0;
+ } break;
+ }
+
+ // Bugged case (CV=FC)
+ if (cpu->gte_cv == 2) {+ R_MAC1 = gte_clamp_mac(cpu, 1, gte_check_mac(cpu, 1, I64(R_MX12) * I64(R_VY)) + (I64(R_MX13) * I64(R_VZ)));
+ R_MAC2 = gte_clamp_mac(cpu, 2, gte_check_mac(cpu, 2, I64(R_MX22) * I64(R_VY)) + (I64(R_MX23) * I64(R_VZ)));
+ R_MAC3 = gte_clamp_mac(cpu, 3, gte_check_mac(cpu, 3, I64(R_MX32) * I64(R_VY)) + (I64(R_MX33) * I64(R_VZ)));
+
+ int64_t mac1 = gte_clamp_mac(cpu, 1, (I64(R_CV1) << 12) + (I64(R_MX11) * I64(R_VX)));
+ int64_t mac2 = gte_clamp_mac(cpu, 2, (I64(R_CV2) << 12) + (I64(R_MX21) * I64(R_VX)));
+ int64_t mac3 = gte_clamp_mac(cpu, 3, (I64(R_CV3) << 12) + (I64(R_MX31) * I64(R_VX)));
+
+ gte_clamp_ir(cpu, 1, mac1, 0);
+ gte_clamp_ir(cpu, 2, mac2, 0);
+ gte_clamp_ir(cpu, 3, mac3, 0);
+ } else {+ R_MAC1 = gte_clamp_mac(cpu, 1, gte_check_mac(cpu, 1, gte_check_mac(cpu, 1, (I64(R_CV1) << 12) + (I64(R_MX11) * I64(R_VX))) + (I64(R_MX12) * I64(R_VY))) + (I64(R_MX13) * I64(R_VZ)));
+ R_MAC2 = gte_clamp_mac(cpu, 2, gte_check_mac(cpu, 2, gte_check_mac(cpu, 2, (I64(R_CV2) << 12) + (I64(R_MX21) * I64(R_VX))) + (I64(R_MX22) * I64(R_VY))) + (I64(R_MX23) * I64(R_VZ)));
+ R_MAC3 = gte_clamp_mac(cpu, 3, gte_check_mac(cpu, 3, gte_check_mac(cpu, 3, (I64(R_CV3) << 12) + (I64(R_MX31) * I64(R_VX))) + (I64(R_MX32) * I64(R_VY))) + (I64(R_MX33) * I64(R_VZ)));
+ }
+
+ R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm);
+ R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm);
+ R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm);
+}
+
+#undef R_VX
+#undef R_VY
+#undef R_VZ
+#undef R_MX11
+#undef R_MX12
+#undef R_MX13
+#undef R_MX21
+#undef R_MX22
+#undef R_MX23
+#undef R_MX31
+#undef R_MX32
+#undef R_MX33
+#undef R_CV1
+#undef R_CV2
+#undef R_CV3
+
+// To-do: Fix flags
+static inline void psx_gte_i_ncds(psx_cpu_t* cpu) {+ R_FLAG = 0;
+
+ NCDS(0);
+}
+
+static inline void psx_gte_i_cdp(psx_cpu_t* cpu) {+ R_FLAG = 0;
+ R_MAC1 = gte_clamp_mac(cpu, 1, gte_check_mac(cpu, 1, gte_check_mac(cpu, 1, (I64(R_RBK) << 12) + (I64(R_LR1) * I64(R_IR1))) + (I64(R_LR2) * I64(R_IR2))) + (I64(R_LR3) * I64(R_IR3)));
+ R_MAC2 = gte_clamp_mac(cpu, 2, gte_check_mac(cpu, 2, gte_check_mac(cpu, 2, (I64(R_GBK) << 12) + (I64(R_LG1) * I64(R_IR1))) + (I64(R_LG2) * I64(R_IR2))) + (I64(R_LG3) * I64(R_IR3)));
+ R_MAC3 = gte_clamp_mac(cpu, 3, gte_check_mac(cpu, 3, gte_check_mac(cpu, 3, (I64(R_BBK) << 12) + (I64(R_LB1) * I64(R_IR1))) + (I64(R_LB2) * I64(R_IR2))) + (I64(R_LB3) * I64(R_IR3)));
+ R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm);
+ R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm);
+ R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm);
+ int64_t ir1 = gte_clamp_ir(cpu, 1, gte_clamp_mac(cpu, 1, ((I64(R_RFC) << 12) - ((I64(R_RC << 4)) * I64(R_IR1)))), 0);
+ int64_t ir2 = gte_clamp_ir(cpu, 2, gte_clamp_mac(cpu, 2, ((I64(R_GFC) << 12) - ((I64(R_GC << 4)) * I64(R_IR2)))), 0);
+ int64_t ir3 = gte_clamp_ir(cpu, 3, gte_clamp_mac(cpu, 3, ((I64(R_BFC) << 12) - ((I64(R_BC << 4)) * I64(R_IR3)))), 0);
+ R_MAC1 = gte_clamp_mac(cpu, 1, (I64(R_RC << 4) * I64(R_IR1)) + (I64(R_IR0) * ir1));
+ R_MAC2 = gte_clamp_mac(cpu, 2, (I64(R_GC << 4) * I64(R_IR2)) + (I64(R_IR0) * ir2));
+ R_MAC3 = gte_clamp_mac(cpu, 3, (I64(R_BC << 4) * I64(R_IR3)) + (I64(R_IR0) * ir3));
+ R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm);
+ R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm);
+ R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm);
+ R_RGB0 = R_RGB1;
+ R_RGB1 = R_RGB2;
+ R_RC2 = gte_clamp_rgb(cpu, 1, R_MAC1 >> 4);
+ R_GC2 = gte_clamp_rgb(cpu, 2, R_MAC2 >> 4);
+ R_BC2 = gte_clamp_rgb(cpu, 3, R_MAC3 >> 4);
+ R_CD2 = R_CODE;
+}
+
+static inline void psx_gte_i_ncdt(psx_cpu_t* cpu) {+ R_FLAG = 0;
+ NCDS(0);
+ NCDS(1);
+ NCDS(2);
+}
+
+static inline void psx_gte_i_nccs(psx_cpu_t* cpu) {+ R_FLAG = 0;
+ NCCS(0);
+}
+
+static inline void psx_gte_i_cc(psx_cpu_t* cpu) {+ R_FLAG = 0;
+ R_MAC1 = gte_clamp_mac(cpu, 1, gte_check_mac(cpu, 1, gte_check_mac(cpu, 1, (I64(R_RBK) << 12) + (I64(R_LR1) * I64(R_IR1))) + (I64(R_LR2) * I64(R_IR2))) + (I64(R_LR3) * I64(R_IR3)));
+ R_MAC2 = gte_clamp_mac(cpu, 2, gte_check_mac(cpu, 2, gte_check_mac(cpu, 2, (I64(R_GBK) << 12) + (I64(R_LG1) * I64(R_IR1))) + (I64(R_LG2) * I64(R_IR2))) + (I64(R_LG3) * I64(R_IR3)));
+ R_MAC3 = gte_clamp_mac(cpu, 3, gte_check_mac(cpu, 3, gte_check_mac(cpu, 3, (I64(R_BBK) << 12) + (I64(R_LB1) * I64(R_IR1))) + (I64(R_LB2) * I64(R_IR2))) + (I64(R_LB3) * I64(R_IR3)));
+ R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm);
+ R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm);
+ R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm);
+ R_MAC1 = gte_clamp_mac(cpu, 1, (I64(R_RC) * I64(R_IR1)) << 4);
+ R_MAC2 = gte_clamp_mac(cpu, 2, (I64(R_GC) * I64(R_IR2)) << 4);
+ R_MAC3 = gte_clamp_mac(cpu, 3, (I64(R_BC) * I64(R_IR3)) << 4);
+ R_RGB0 = R_RGB1;
+ R_RGB1 = R_RGB2;
+ R_CD2 = R_CODE;
+ R_RC2 = gte_clamp_rgb(cpu, 1, R_MAC1 >> 4);
+ R_GC2 = gte_clamp_rgb(cpu, 2, R_MAC2 >> 4);
+ R_BC2 = gte_clamp_rgb(cpu, 3, R_MAC3 >> 4);
+ R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm);
+ R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm);
+ R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm);
+}
+
+static inline void psx_gte_i_ncs(psx_cpu_t* cpu) {+ R_FLAG = 0;
+ NCS(0);
+}
+
+static inline void psx_gte_i_nct(psx_cpu_t* cpu) {+ R_FLAG = 0;
+ NCS(0);
+ NCS(1);
+ NCS(2);
+}
+
+static inline void psx_gte_i_sqr(psx_cpu_t* cpu) {+ R_FLAG = 0;
+
+ R_MAC1 = gte_clamp_mac(cpu, 1, I64(R_IR1) * I64(R_IR1));
+ R_MAC2 = gte_clamp_mac(cpu, 2, I64(R_IR2) * I64(R_IR2));
+ R_MAC3 = gte_clamp_mac(cpu, 3, I64(R_IR3) * I64(R_IR3));
+
+ R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm);
+ R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm);
+ R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm);
+}
+
+static inline void psx_gte_i_dcpl(psx_cpu_t* cpu) {+ R_FLAG = 0;
+
+ R_MAC1 = gte_clamp_mac(cpu, 1, I64(R_RC) * I64(R_IR1)) << 4;
+ R_MAC2 = gte_clamp_mac(cpu, 2, I64(R_GC) * I64(R_IR2)) << 4;
+ R_MAC3 = gte_clamp_mac(cpu, 3, I64(R_BC) * I64(R_IR3)) << 4;
+ int64_t ir1 = gte_clamp_ir(cpu, 1, gte_clamp_mac(cpu, 1, ((I64(R_RFC) << 12) - ((I64(R_RC << 4)) * I64(R_IR1)))), 0);
+ int64_t ir2 = gte_clamp_ir(cpu, 2, gte_clamp_mac(cpu, 2, ((I64(R_GFC) << 12) - ((I64(R_GC << 4)) * I64(R_IR2)))), 0);
+ int64_t ir3 = gte_clamp_ir(cpu, 3, gte_clamp_mac(cpu, 3, ((I64(R_BFC) << 12) - ((I64(R_BC << 4)) * I64(R_IR3)))), 0);
+ R_MAC1 = gte_clamp_mac(cpu, 1, ((I64(R_RC << 4)) * I64(R_IR1)) + (I64(R_IR0) * ir1));
+ R_MAC2 = gte_clamp_mac(cpu, 2, ((I64(R_GC << 4)) * I64(R_IR2)) + (I64(R_IR0) * ir2));
+ R_MAC3 = gte_clamp_mac(cpu, 3, ((I64(R_BC << 4)) * I64(R_IR3)) + (I64(R_IR0) * ir3));
+ R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm);
+ R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm);
+ R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm);
+ R_RGB0 = R_RGB1;
+ R_RGB1 = R_RGB2;
+ R_CD2 = R_CODE;
+ R_RC2 = gte_clamp_rgb(cpu, 1, R_MAC1 >> 4);
+ R_GC2 = gte_clamp_rgb(cpu, 2, R_MAC2 >> 4);
+ R_BC2 = gte_clamp_rgb(cpu, 3, R_MAC3 >> 4);
+}
+
+static inline void psx_gte_i_dpct(psx_cpu_t* cpu) {+ R_FLAG = 0;
+ DPCT1;
+ DPCT1;
+ DPCT1;
+}
+
+static inline void psx_gte_i_avsz3(psx_cpu_t* cpu) {+ R_FLAG = 0;
+
+ int64_t avg = I64(R_ZSF3) * (R_SZ1 + R_SZ2 + R_SZ3);
+
+ R_MAC0 = (int)gte_clamp_mac0(cpu, avg);
+ R_OTZ = gte_clamp_sz3(cpu, avg >> 12);
+}
+
+static inline void psx_gte_i_avsz4(psx_cpu_t* cpu) {+ R_FLAG = 0;
+
+ int64_t avg = I64(R_ZSF4) * (R_SZ0 + R_SZ1 + R_SZ2 + R_SZ3);
+
+ R_MAC0 = (int)gte_clamp_mac0(cpu, avg);
+ R_OTZ = gte_clamp_sz3(cpu, avg >> 12);
+}
+
+static inline void psx_gte_i_rtpt(psx_cpu_t* cpu) {+ R_FLAG = 0;
+ GTE_RTP(0);
+ GTE_RTP(1);
+ GTE_RTP_DQ(2);
+}
+
+static inline void psx_gte_i_gpf(psx_cpu_t* cpu) {+ R_FLAG = 0;
+
+ R_MAC1 = gte_clamp_mac(cpu, 1, R_IR0 * R_IR1);
+ R_MAC2 = gte_clamp_mac(cpu, 2, R_IR0 * R_IR2);
+ R_MAC3 = gte_clamp_mac(cpu, 3, R_IR0 * R_IR3);
+ R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm);
+ R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm);
+ R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm);
+ R_RGB0 = R_RGB1;
+ R_RGB1 = R_RGB2;
+ R_CD2 = R_CODE;
+ R_RC2 = gte_clamp_rgb(cpu, 1, R_MAC1 >> 4);
+ R_GC2 = gte_clamp_rgb(cpu, 2, R_MAC2 >> 4);
+ R_BC2 = gte_clamp_rgb(cpu, 3, R_MAC3 >> 4);
+}
+
+static inline void psx_gte_i_gpl(psx_cpu_t* cpu) {+ R_FLAG = 0;
+
+ R_MAC1 = gte_clamp_mac(cpu, 1, (I64(R_MAC1) << cpu->gte_sf) + (R_IR0 * R_IR1));
+ R_MAC2 = gte_clamp_mac(cpu, 2, (I64(R_MAC2) << cpu->gte_sf) + (R_IR0 * R_IR2));
+ R_MAC3 = gte_clamp_mac(cpu, 3, (I64(R_MAC3) << cpu->gte_sf) + (R_IR0 * R_IR3));
+ R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm);
+ R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm);
+ R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm);
+ R_RGB0 = R_RGB1;
+ R_RGB1 = R_RGB2;
+ R_CD2 = R_CODE;
+ R_RC2 = gte_clamp_rgb(cpu, 1, R_MAC1 >> 4);
+ R_GC2 = gte_clamp_rgb(cpu, 2, R_MAC2 >> 4);
+ R_BC2 = gte_clamp_rgb(cpu, 3, R_MAC3 >> 4);
+}
+
+static inline void psx_gte_i_ncct(psx_cpu_t* cpu) {+ R_FLAG = 0;
+ NCCS(0);
+ NCCS(1);
+ NCCS(2);
+}
+
+int psx_cpu_execute(psx_cpu_t* cpu) {+ switch ((cpu->opcode & 0xfc000000) >> 26) {+ case 0x00000000 >> 26: {+ switch (cpu->opcode & 0x0000003f) {+ case 0x00000000: psx_cpu_i_sll(cpu); return 2;
+ case 0x00000002: psx_cpu_i_srl(cpu); return 2;
+ case 0x00000003: psx_cpu_i_sra(cpu); return 2;
+ case 0x00000004: psx_cpu_i_sllv(cpu); return 2;
+ case 0x00000006: psx_cpu_i_srlv(cpu); return 2;
+ case 0x00000007: psx_cpu_i_srav(cpu); return 2;
+ case 0x00000008: psx_cpu_i_jr(cpu); return 2;
+ case 0x00000009: psx_cpu_i_jalr(cpu); return 2;
+ case 0x0000000c: psx_cpu_i_syscall(cpu); return 2;
+ case 0x0000000d: psx_cpu_i_break(cpu); return 2;
+ case 0x00000010: psx_cpu_i_mfhi(cpu); return 2;
+ case 0x00000011: psx_cpu_i_mthi(cpu); return 2;
+ case 0x00000012: psx_cpu_i_mflo(cpu); return 2;
+ case 0x00000013: psx_cpu_i_mtlo(cpu); return 2;
+ case 0x00000018: psx_cpu_i_mult(cpu); return 2;
+ case 0x00000019: psx_cpu_i_multu(cpu); return 2;
+ case 0x0000001a: psx_cpu_i_div(cpu); return 2;
+ case 0x0000001b: psx_cpu_i_divu(cpu); return 2;
+ case 0x00000020: psx_cpu_i_add(cpu); return 2;
+ case 0x00000021: psx_cpu_i_addu(cpu); return 2;
+ case 0x00000022: psx_cpu_i_sub(cpu); return 2;
+ case 0x00000023: psx_cpu_i_subu(cpu); return 2;
+ case 0x00000024: psx_cpu_i_and(cpu); return 2;
+ case 0x00000025: psx_cpu_i_or(cpu); return 2;
+ case 0x00000026: psx_cpu_i_xor(cpu); return 2;
+ case 0x00000027: psx_cpu_i_nor(cpu); return 2;
+ case 0x0000002a: psx_cpu_i_slt(cpu); return 2;
+ case 0x0000002b: psx_cpu_i_sltu(cpu); return 2;
+ } break;
+ } break;
+ case 0x04000000 >> 26: {+ cpu->branch = 1;
+ cpu->branch_taken = 0;
+
+ switch ((cpu->opcode & 0x001f0000) >> 16) {+ case 0x00000000 >> 16: psx_cpu_i_bltz(cpu); return 2;
+ case 0x00010000 >> 16: psx_cpu_i_bgez(cpu); return 2;
+ case 0x00100000 >> 16: psx_cpu_i_bltzal(cpu); return 2;
+ case 0x00110000 >> 16: psx_cpu_i_bgezal(cpu); return 2;
+ // bltz/bgez dupes
+ default: {+ if (cpu->opcode & 0x00010000) {+ psx_cpu_i_bgez(cpu);
+ } else {+ psx_cpu_i_bltz(cpu);
+ }
+ } return 2;
+ } break;
+ } break;
+ case 0x08000000 >> 26: psx_cpu_i_j(cpu); return 2;
+ case 0x0c000000 >> 26: psx_cpu_i_jal(cpu); return 2;
+ case 0x10000000 >> 26: psx_cpu_i_beq(cpu); return 2;
+ case 0x14000000 >> 26: psx_cpu_i_bne(cpu); return 2;
+ case 0x18000000 >> 26: psx_cpu_i_blez(cpu); return 2;
+ case 0x1c000000 >> 26: psx_cpu_i_bgtz(cpu); return 2;
+ case 0x20000000 >> 26: psx_cpu_i_addi(cpu); return 2;
+ case 0x24000000 >> 26: psx_cpu_i_addiu(cpu); return 2;
+ case 0x28000000 >> 26: psx_cpu_i_slti(cpu); return 2;
+ case 0x2c000000 >> 26: psx_cpu_i_sltiu(cpu); return 2;
+ case 0x30000000 >> 26: psx_cpu_i_andi(cpu); return 2;
+ case 0x34000000 >> 26: psx_cpu_i_ori(cpu); return 2;
+ case 0x38000000 >> 26: psx_cpu_i_xori(cpu); return 2;
+ case 0x3c000000 >> 26: psx_cpu_i_lui(cpu); return 2;
+ case 0x40000000 >> 26: {+ switch ((cpu->opcode & 0x03e00000) >> 21) {+ case 0x00000000 >> 21: psx_cpu_i_mfc0(cpu); return 2;
+ case 0x00800000 >> 21: psx_cpu_i_mtc0(cpu); return 2;
+ case 0x02000000 >> 21: psx_cpu_i_rfe(cpu); return 2;
+ }
+ } break;
+ case 0x48000000 >> 26: {+ switch ((cpu->opcode & 0x03e00000) >> 21) {+ case 0x00000000 >> 21: psx_cpu_i_mfc2(cpu); return 2;
+ case 0x00400000 >> 21: psx_cpu_i_cfc2(cpu); return 2;
+ case 0x00800000 >> 21: psx_cpu_i_mtc2(cpu); return 2;
+ case 0x00c00000 >> 21: psx_cpu_i_ctc2(cpu); return 2;
+ default: {+ DO_PENDING_LOAD;
+
+ cpu->gte_sf = ((cpu->opcode & 0x80000) != 0) * 12;
+ cpu->gte_lm = (cpu->opcode & 0x400) != 0;
+ cpu->gte_cv = (cpu->opcode >> 13) & 3;
+ cpu->gte_v = (cpu->opcode >> 15) & 3;
+ cpu->gte_mx = (cpu->opcode >> 17) & 3;
+
+ switch (cpu->opcode & 0x3f) {+ case 0x01: psx_gte_i_rtps(cpu); return 15;
+ case 0x06: psx_gte_i_nclip(cpu); return 8;
+ case 0x0c: psx_gte_i_op(cpu); return 6;
+ case 0x10: psx_gte_i_dpcs(cpu); return 8;
+ case 0x11: psx_gte_i_intpl(cpu); return 8;
+ case 0x12: psx_gte_i_mvmva(cpu); return 8;
+ case 0x13: psx_gte_i_ncds(cpu); return 19;
+ case 0x14: psx_gte_i_cdp(cpu); return 13;
+ case 0x16: psx_gte_i_ncdt(cpu); return 44;
+ case 0x1b: psx_gte_i_nccs(cpu); return 17;
+ case 0x1c: psx_gte_i_cc(cpu); return 11;
+ case 0x1e: psx_gte_i_ncs(cpu); return 14;
+ case 0x20: psx_gte_i_nct(cpu); return 30;
+ case 0x28: psx_gte_i_sqr(cpu); return 5;
+ case 0x29: psx_gte_i_dcpl(cpu); return 8;
+ case 0x2a: psx_gte_i_dpct(cpu); return 17;
+ case 0x2d: psx_gte_i_avsz3(cpu); return 5;
+ case 0x2e: psx_gte_i_avsz4(cpu); return 6;
+ case 0x30: psx_gte_i_rtpt(cpu); return 23;
+ case 0x3d: psx_gte_i_gpf(cpu); return 5;
+ case 0x3e: psx_gte_i_gpl(cpu); return 5;
+ case 0x3f: psx_gte_i_ncct(cpu); return 39;
+ default: psx_gte_i_invalid(cpu); return 0;
+ }
+ } break;
+ }
+ } break;
+ case 0x80000000 >> 26: psx_cpu_i_lb(cpu); return 2;
+ case 0x84000000 >> 26: psx_cpu_i_lh(cpu); return 2;
+ case 0x88000000 >> 26: psx_cpu_i_lwl(cpu); return 2;
+ case 0x8c000000 >> 26: psx_cpu_i_lw(cpu); return 2;
+ case 0x90000000 >> 26: psx_cpu_i_lbu(cpu); return 2;
+ case 0x94000000 >> 26: psx_cpu_i_lhu(cpu); return 2;
+ case 0x98000000 >> 26: psx_cpu_i_lwr(cpu); return 2;
+ case 0xa0000000 >> 26: psx_cpu_i_sb(cpu); return 2;
+ case 0xa4000000 >> 26: psx_cpu_i_sh(cpu); return 2;
+ case 0xa8000000 >> 26: psx_cpu_i_swl(cpu); return 2;
+ case 0xac000000 >> 26: psx_cpu_i_sw(cpu); return 2;
+ case 0xb8000000 >> 26: psx_cpu_i_swr(cpu); return 2;
+ case 0xc0000000 >> 26: psx_cpu_i_lwc0(cpu); return 2;
+ case 0xc4000000 >> 26: psx_cpu_i_lwc1(cpu); return 2;
+ case 0xc8000000 >> 26: psx_cpu_i_lwc2(cpu); return 2;
+ case 0xcc000000 >> 26: psx_cpu_i_lwc3(cpu); return 2;
+ case 0xe0000000 >> 26: psx_cpu_i_swc0(cpu); return 2;
+ case 0xe4000000 >> 26: psx_cpu_i_swc1(cpu); return 2;
+ case 0xe8000000 >> 26: psx_cpu_i_swc2(cpu); return 2;
+ case 0xec000000 >> 26: psx_cpu_i_swc3(cpu); return 2;
+ }
+
+ return 0;
+}
+
+#undef R_R0
+#undef R_A0
+#undef R_RA
+
+#undef OP
+#undef S
+#undef T
+#undef D
+#undef IMM5
+#undef CMT
+#undef SOP
+#undef IMM26
+#undef IMM16
+#undef IMM16S
+
+#undef TRACE_M
+#undef TRACE_I16S
+#undef TRACE_I16D
+#undef TRACE_I5D
+#undef TRACE_I26
+#undef TRACE_RT
+#undef TRACE_C0M
+#undef TRACE_C2M
+#undef TRACE_C2MC
+#undef TRACE_B
+#undef TRACE_RS
+#undef TRACE_MTF
+#undef TRACE_RD
+#undef TRACE_MD
+#undef TRACE_I20
+#undef TRACE_N
+
+#undef DO_PENDING_LOAD
+
+#undef DEBUG_ALL
+
+#undef SE8
#undef SE16
--- a/psx/cpu.h
+++ b/psx/cpu.h
@@ -1,312 +1,312 @@
#ifndef PSX_CPU_H
#define PSX_CPU_H
-
-#include "p9.h"
-
-#include "bus.h"
-
-#define PSX_CPU_CPS 33868800 // 33868800 Clocks/s
-#define PSX_CPU_FREQ 33.868800f // 33.868800 MHz
-
-struct psx_cpu_t;
-
-typedef struct psx_cpu_t psx_cpu_t;
-
-typedef void (*psx_cpu_kcall_hook_t)(psx_cpu_t*);
-
-/*
- cop0r0 - N/A
- cop0r1 - N/A
- cop0r2 - N/A
- cop0r3 - BPC - Breakpoint on execute (R/W)
- cop0r4 - N/A
- cop0r5 - BDA - Breakpoint on data access (R/W)
- cop0r6 - JUMPDEST - Randomly memorized jump address (R)
- cop0r7 - DCIC - Breakpoint control (R/W)
- cop0r8 - BadVaddr - Bad Virtual Address (R)
- cop0r9 - BDAM - Data Access breakpoint mask (R/W)
- cop0r10 - N/A
- cop0r11 - BPCM - Execute breakpoint mask (R/W)
- cop0r12 - SR - System status register (R/W)
- cop0r13 - CAUSE - Describes the most recently recognised exception (R)
- cop0r14 - EPC - Return Address from Trap (R)
- cop0r15 - PRID - Processor ID (R)
-*/
-
-#define COP0_BPC 3
-#define COP0_BDA 5
-#define COP0_JUMPDEST 6
-#define COP0_DCIC 7
-#define COP0_BADVADDR 8
-#define COP0_BDAM 9
-#define COP0_BPCM 11
-#define COP0_SR 12
-#define COP0_CAUSE 13
-#define COP0_EPC 14
-#define COP0_PRID 15
-
-/*
- Name Alias Common Usage
- R0 zero Constant (always 0)
- R1 at Assembler temporary (destroyed by some assembler pseudoinstructions!)
- R2-R3 v0-v1 Subroutine return values, may be changed by subroutines
- R4-R7 a0-a3 Subroutine arguments, may be changed by subroutines
- R8-R15 t0-t7 Temporaries, may be changed by subroutines
- R16-R23 s0-s7 Static variables, must be saved by subs
- R24-R25 t8-t9 Temporaries, may be changed by subroutines
- R26-R27 k0-k1 Reserved for kernel (destroyed by some IRQ handlers!)
- R28 gp Global pointer (rarely used)
- R29 sp Stack pointer
- R30 fp(s8) Frame Pointer, or 9th Static variable, must be saved
- R31 ra Return address (used so by JAL,BLTZAL,BGEZAL opcodes)
- - pc Program counter
- - hi,lo Multiply/divide results, may be changed by subroutines
-*/
-
-typedef struct __attribute__((__packed__)) {
- union {
- uint32_t xy;
- int16_t p[2];
- };
-
- int16_t z;
-} gte_vertex_t;
-
-typedef struct __attribute__((__packed__)) {
- union {
- uint32_t xy;
- int16_t p[2];
- };
-} gte_vec2_t;
-
-typedef struct __attribute__((__packed__)) {
- int32_t x, y, z;
-} gte_vec3_t;
-
-typedef struct __attribute__((__packed__)) {
- union {
- uint32_t rgbc;
- uint8_t c[4];
- };
-} gte_color_t;
-
-typedef struct __attribute__((__packed__)) {
- union {
- uint32_t u32;
- int16_t c[2];
- } m[4];
-
- int16_t m33;
-} gte_matrix_t;
-
-struct __attribute__((__packed__)) psx_cpu_t {
- uint32_t r[32];
- uint32_t opcode;
- uint32_t pc, next_pc, saved_pc;
- uint32_t hi, lo;
- uint32_t load_d, load_v;
- uint32_t last_cycles;
- uint32_t total_cycles;
- int branch, delay_slot, branch_taken;
-
- uint32_t cop0_r[16];
-
- struct {
- gte_vertex_t v[3];
- gte_color_t rgbc;
- uint16_t otz;
- int16_t ir[4];
- gte_vec2_t sxy[4];
- uint16_t sz[4];
- gte_color_t rgb[3];
- uint32_t res1;
- int32_t mac[4];
- uint16_t irgb, orgb;
- int32_t lzcs, lzcr;
- } cop2_dr;
-
- struct {
- gte_matrix_t rt;
- gte_vec3_t tr;
- gte_matrix_t l;
- gte_vec3_t bk;
- gte_matrix_t lr;
- gte_vec3_t fc;
- uint32_t ofx, ofy;
- uint32_t h;
- int16_t dqa;
- int32_t dqb;
- int16_t zsf3, zsf4;
- uint32_t flag;
- } cop2_cr;
-
- int gte_lm;
- int gte_sf;
- int gte_mx;
- int gte_v;
- int gte_cv;
- int64_t s_mac0;
- int64_t s_mac3;
-
- psx_bus_t* bus;
-
- psx_cpu_kcall_hook_t a_function_hook;
- psx_cpu_kcall_hook_t b_function_hook;
-};
-
-/*
- 0 IEc Current Interrupt Enable (0=Disable, 1=Enable) ;rfe pops IUp here
- 1 KUc Current Kernel/User Mode (0=Kernel, 1=User) ;rfe pops KUp here
- 2 IEp Previous Interrupt Disable ;rfe pops IUo here
- 3 KUp Previous Kernel/User Mode ;rfe pops KUo here
- 4 IEo Old Interrupt Disable ;left unchanged by rfe
- 5 KUo Old Kernel/User Mode ;left unchanged by rfe
- 6-7 - Not used (zero)
- 8-15 Im 8 bit interrupt mask fields. When set the corresponding
- interrupts are allowed to cause an exception.
- 16 Isc Isolate Cache (0=No, 1=Isolate)
- When isolated, all load and store operations are targetted
- to the Data cache, and never the main memory.
- (Used by PSX Kernel, in combination with Port FFFE0130h)
- 17 Swc Swapped cache mode (0=Normal, 1=Swapped)
- Instruction cache will act as Data cache and vice versa.
- Use only with Isc to access & invalidate Instr. cache entries.
- (Not used by PSX Kernel)
- 18 PZ When set cache parity bits are written as 0.
- 19 CM Shows the result of the last load operation with the D-cache
- isolated. It gets set if the cache really contained data
- for the addressed memory location.
- 20 PE Cache parity error (Does not cause exception)
- 21 TS TLB shutdown. Gets set if a programm address simultaneously
- matches 2 TLB entries.
- (initial value on reset allows to detect extended CPU version?)
- 22 BEV Boot exception vectors in RAM/ROM (0=RAM/KSEG0, 1=ROM/KSEG1)
- 23-24 - Not used (zero)
- 25 RE Reverse endianness (0=Normal endianness, 1=Reverse endianness)
- Reverses the byte order in which data is stored in
- memory. (lo-hi -> hi-lo)
- (Affects only user mode, not kernel mode) (?)
- (The bit doesn't exist in PSX ?)
- 26-27 - Not used (zero)
- 28 CU0 COP0 Enable (0=Enable only in Kernel Mode, 1=Kernel and User Mode)
- 29 CU1 COP1 Enable (0=Disable, 1=Enable) (none in PSX)
- 30 CU2 COP2 Enable (0=Disable, 1=Enable) (GTE in PSX)
- 31 CU3 COP3 Enable (0=Disable, 1=Enable) (none in PSX)
-*/
-
-#define SR_IEC 0x00000001
-#define SR_KUC 0x00000002
-#define SR_IEP 0x00000004
-#define SR_KUP 0x00000008
-#define SR_IEO 0x00000010
-#define SR_KUO 0x00000020
-#define SR_IM 0x0000ff00
-#define SR_IM0 0x00000100
-#define SR_IM1 0x00000200
-#define SR_IM2 0x00000400
-#define SR_IM3 0x00000800
-#define SR_IM4 0x00001000
-#define SR_IM5 0x00002000
-#define SR_IM6 0x00004000
-#define SR_IM7 0x00008000
-#define SR_ISC 0x00010000
-#define SR_SWC 0x00020000
-#define SR_PZ 0x00040000
-#define SR_CM 0x00080000
-#define SR_PE 0x00100000
-#define SR_TS 0x00200000
-#define SR_BEV 0x00400000
-#define SR_RE 0x02000000
-#define SR_CU0 0x10000000
-#define SR_CU1 0x20000000
-#define SR_CU2 0x40000000
-#define SR_CU3 0x80000000
-
-psx_cpu_t* psx_cpu_create(void);
-void psx_cpu_init(psx_cpu_t*, psx_bus_t*);
-void psx_cpu_destroy(psx_cpu_t*);
-void psx_cpu_cycle(psx_cpu_t*);
-void psx_cpu_set_irq_pending(psx_cpu_t*);
+
+#include "p9.h"
+
+#include "bus.h"
+
+#define PSX_CPU_CPS 33868800 // 33868800 Clocks/s
+#define PSX_CPU_FREQ 33.868800f // 33.868800 MHz
+
+struct psx_cpu_t;
+
+typedef struct psx_cpu_t psx_cpu_t;
+
+typedef void (*psx_cpu_kcall_hook_t)(psx_cpu_t*);
+
+/*
+ cop0r0 - N/A
+ cop0r1 - N/A
+ cop0r2 - N/A
+ cop0r3 - BPC - Breakpoint on execute (R/W)
+ cop0r4 - N/A
+ cop0r5 - BDA - Breakpoint on data access (R/W)
+ cop0r6 - JUMPDEST - Randomly memorized jump address (R)
+ cop0r7 - DCIC - Breakpoint control (R/W)
+ cop0r8 - BadVaddr - Bad Virtual Address (R)
+ cop0r9 - BDAM - Data Access breakpoint mask (R/W)
+ cop0r10 - N/A
+ cop0r11 - BPCM - Execute breakpoint mask (R/W)
+ cop0r12 - SR - System status register (R/W)
+ cop0r13 - CAUSE - Describes the most recently recognised exception (R)
+ cop0r14 - EPC - Return Address from Trap (R)
+ cop0r15 - PRID - Processor ID (R)
+*/
+
+#define COP0_BPC 3
+#define COP0_BDA 5
+#define COP0_JUMPDEST 6
+#define COP0_DCIC 7
+#define COP0_BADVADDR 8
+#define COP0_BDAM 9
+#define COP0_BPCM 11
+#define COP0_SR 12
+#define COP0_CAUSE 13
+#define COP0_EPC 14
+#define COP0_PRID 15
+
+/*
+ Name Alias Common Usage
+ R0 zero Constant (always 0)
+ R1 at Assembler temporary (destroyed by some assembler pseudoinstructions!)
+ R2-R3 v0-v1 Subroutine return values, may be changed by subroutines
+ R4-R7 a0-a3 Subroutine arguments, may be changed by subroutines
+ R8-R15 t0-t7 Temporaries, may be changed by subroutines
+ R16-R23 s0-s7 Static variables, must be saved by subs
+ R24-R25 t8-t9 Temporaries, may be changed by subroutines
+ R26-R27 k0-k1 Reserved for kernel (destroyed by some IRQ handlers!)
+ R28 gp Global pointer (rarely used)
+ R29 sp Stack pointer
+ R30 fp(s8) Frame Pointer, or 9th Static variable, must be saved
+ R31 ra Return address (used so by JAL,BLTZAL,BGEZAL opcodes)
+ - pc Program counter
+ - hi,lo Multiply/divide results, may be changed by subroutines
+*/
+
+typedef struct __attribute__((__packed__)) {+ union {+ uint32_t xy;
+ int16_t p[2];
+ };
+
+ int16_t z;
+} gte_vertex_t;
+
+typedef struct __attribute__((__packed__)) {+ union {+ uint32_t xy;
+ int16_t p[2];
+ };
+} gte_vec2_t;
+
+typedef struct __attribute__((__packed__)) {+ int32_t x, y, z;
+} gte_vec3_t;
+
+typedef struct __attribute__((__packed__)) {+ union {+ uint32_t rgbc;
+ uint8_t c[4];
+ };
+} gte_color_t;
+
+typedef struct __attribute__((__packed__)) {+ union {+ uint32_t u32;
+ int16_t c[2];
+ } m[4];
+
+ int16_t m33;
+} gte_matrix_t;
+
+struct __attribute__((__packed__)) psx_cpu_t {+ uint32_t r[32];
+ uint32_t opcode;
+ uint32_t pc, next_pc, saved_pc;
+ uint32_t hi, lo;
+ uint32_t load_d, load_v;
+ uint32_t last_cycles;
+ uint32_t total_cycles;
+ int branch, delay_slot, branch_taken;
+
+ uint32_t cop0_r[16];
+
+ struct {+ gte_vertex_t v[3];
+ gte_color_t rgbc;
+ uint16_t otz;
+ int16_t ir[4];
+ gte_vec2_t sxy[4];
+ uint16_t sz[4];
+ gte_color_t rgb[3];
+ uint32_t res1;
+ int32_t mac[4];
+ uint16_t irgb, orgb;
+ int32_t lzcs, lzcr;
+ } cop2_dr;
+
+ struct {+ gte_matrix_t rt;
+ gte_vec3_t tr;
+ gte_matrix_t l;
+ gte_vec3_t bk;
+ gte_matrix_t lr;
+ gte_vec3_t fc;
+ uint32_t ofx, ofy;
+ uint32_t h;
+ int16_t dqa;
+ int32_t dqb;
+ int16_t zsf3, zsf4;
+ uint32_t flag;
+ } cop2_cr;
+
+ int gte_lm;
+ int gte_sf;
+ int gte_mx;
+ int gte_v;
+ int gte_cv;
+ int64_t s_mac0;
+ int64_t s_mac3;
+
+ psx_bus_t* bus;
+
+ psx_cpu_kcall_hook_t a_function_hook;
+ psx_cpu_kcall_hook_t b_function_hook;
+};
+
+/*
+ 0 IEc Current Interrupt Enable (0=Disable, 1=Enable) ;rfe pops IUp here
+ 1 KUc Current Kernel/User Mode (0=Kernel, 1=User) ;rfe pops KUp here
+ 2 IEp Previous Interrupt Disable ;rfe pops IUo here
+ 3 KUp Previous Kernel/User Mode ;rfe pops KUo here
+ 4 IEo Old Interrupt Disable ;left unchanged by rfe
+ 5 KUo Old Kernel/User Mode ;left unchanged by rfe
+ 6-7 - Not used (zero)
+ 8-15 Im 8 bit interrupt mask fields. When set the corresponding
+ interrupts are allowed to cause an exception.
+ 16 Isc Isolate Cache (0=No, 1=Isolate)
+ When isolated, all load and store operations are targetted
+ to the Data cache, and never the main memory.
+ (Used by PSX Kernel, in combination with Port FFFE0130h)
+ 17 Swc Swapped cache mode (0=Normal, 1=Swapped)
+ Instruction cache will act as Data cache and vice versa.
+ Use only with Isc to access & invalidate Instr. cache entries.
+ (Not used by PSX Kernel)
+ 18 PZ When set cache parity bits are written as 0.
+ 19 CM Shows the result of the last load operation with the D-cache
+ isolated. It gets set if the cache really contained data
+ for the addressed memory location.
+ 20 PE Cache parity error (Does not cause exception)
+ 21 TS TLB shutdown. Gets set if a programm address simultaneously
+ matches 2 TLB entries.
+ (initial value on reset allows to detect extended CPU version?)
+ 22 BEV Boot exception vectors in RAM/ROM (0=RAM/KSEG0, 1=ROM/KSEG1)
+ 23-24 - Not used (zero)
+ 25 RE Reverse endianness (0=Normal endianness, 1=Reverse endianness)
+ Reverses the byte order in which data is stored in
+ memory. (lo-hi -> hi-lo)
+ (Affects only user mode, not kernel mode) (?)
+ (The bit doesn't exist in PSX ?)
+ 26-27 - Not used (zero)
+ 28 CU0 COP0 Enable (0=Enable only in Kernel Mode, 1=Kernel and User Mode)
+ 29 CU1 COP1 Enable (0=Disable, 1=Enable) (none in PSX)
+ 30 CU2 COP2 Enable (0=Disable, 1=Enable) (GTE in PSX)
+ 31 CU3 COP3 Enable (0=Disable, 1=Enable) (none in PSX)
+*/
+
+#define SR_IEC 0x00000001
+#define SR_KUC 0x00000002
+#define SR_IEP 0x00000004
+#define SR_KUP 0x00000008
+#define SR_IEO 0x00000010
+#define SR_KUO 0x00000020
+#define SR_IM 0x0000ff00
+#define SR_IM0 0x00000100
+#define SR_IM1 0x00000200
+#define SR_IM2 0x00000400
+#define SR_IM3 0x00000800
+#define SR_IM4 0x00001000
+#define SR_IM5 0x00002000
+#define SR_IM6 0x00004000
+#define SR_IM7 0x00008000
+#define SR_ISC 0x00010000
+#define SR_SWC 0x00020000
+#define SR_PZ 0x00040000
+#define SR_CM 0x00080000
+#define SR_PE 0x00100000
+#define SR_TS 0x00200000
+#define SR_BEV 0x00400000
+#define SR_RE 0x02000000
+#define SR_CU0 0x10000000
+#define SR_CU1 0x20000000
+#define SR_CU2 0x40000000
+#define SR_CU3 0x80000000
+
+psx_cpu_t* psx_cpu_create(void);
+void psx_cpu_init(psx_cpu_t*, psx_bus_t*);
+void psx_cpu_destroy(psx_cpu_t*);
+void psx_cpu_cycle(psx_cpu_t*);
+void psx_cpu_set_irq_pending(psx_cpu_t*);
void psx_cpu_load_state(psx_cpu_t*, void*);
void psx_cpu_save_state(psx_cpu_t*, void*);
-void psx_cpu_fetch(psx_cpu_t*);
-void psx_cpu_set_a_kcall_hook(psx_cpu_t*, psx_cpu_kcall_hook_t);
-void psx_cpu_set_b_kcall_hook(psx_cpu_t*, psx_cpu_kcall_hook_t);
-int psx_cpu_execute(psx_cpu_t*);
-
-/*
- 00h INT Interrupt
- 01h MOD TLB modification (none such in PSX)
- 02h TLBL TLB load (none such in PSX)
- 03h TLBS TLB store (none such in PSX)
- 04h AdEL Address error, Data load or Instruction fetch
- 05h AdES Address error, Data store
- The address errors occur when attempting to read
- outside of KUseg in user mode and when the address
- is misaligned. (See also: BadVaddr register)
- 06h IBE Bus error on Instruction fetch
- 07h DBE Bus error on Data load/store
- 08h Syscall Generated unconditionally by syscall instruction
- 09h BP Breakpoint - break instruction
- 0Ah RI Reserved instruction
- 0Bh CpU Coprocessor unusable
- 0Ch Ov Arithmetic overflow
-*/
-
-#define CAUSE_INT (0x00 << 2)
-#define CAUSE_MOD (0x01 << 2)
-#define CAUSE_TLBL (0x02 << 2)
-#define CAUSE_TLBS (0x03 << 2)
-#define CAUSE_ADEL (0x04 << 2)
-#define CAUSE_ADES (0x05 << 2)
-#define CAUSE_IBE (0x06 << 2)
-#define CAUSE_DBE (0x07 << 2)
-#define CAUSE_SYSCALL (0x08 << 2)
-#define CAUSE_BP (0x09 << 2)
-#define CAUSE_RI (0x0a << 2)
-#define CAUSE_CPU (0x0b << 2)
-#define CAUSE_OV (0x0c << 2)
-
-/*
- 31 Error Flag (Bit30..23, and 18..13 ORed together) (Read only)
- 30 MAC1 Result positive 44bit overflow (max +7FFFFFFFFFFh) ;\triggered
- 29 MAC2 Result positive 44bit overflow (max +7FFFFFFFFFFh) ; during
- 28 MAC3 Result positive 44bit overflow (max +7FFFFFFFFFFh) ; calculations
- 27 MAC1 Result negative 44bit overflow (min -80000000000h) ;
- 26 MAC2 Result negative 44bit overflow (min -80000000000h) ;
- 25 MAC3 Result negative 44bit overflow (min -80000000000h) ;/
- 24 IR1 saturated to +0000h..+7FFFh (lm=1) or to -8000h..+7FFFh (lm=0)
- 23 IR2 saturated to +0000h..+7FFFh (lm=1) or to -8000h..+7FFFh (lm=0)
- 22 IR3 saturated to +0000h..+7FFFh (lm=1) or to -8000h..+7FFFh (lm=0)
- 21 Color-FIFO-R saturated to +00h..+FFh
- 20 Color-FIFO-G saturated to +00h..+FFh
- 19 Color-FIFO-B saturated to +00h..+FFh
- 18 SZ3 or OTZ saturated to +0000h..+FFFFh
- 17 Divide overflow. RTPS/RTPT division result saturated to max=1FFFFh
- 16 MAC0 Result positive 32bit overflow (max +7FFFFFFFh) ;\triggered on
- 15 MAC0 Result negative 32bit overflow (min -80000000h) ;/final result
- 14 SX2 saturated to -0400h..+03FFh
- 13 SY2 saturated to -0400h..+03FFh
-*/
-
-#define GTEF_SY2SAT 0x00002000
-#define GTEF_SX2SAT 0x00004000
-#define GTEF_M0POVF 0x00008000
-#define GTEF_M0NOVF 0x00010000
-#define GTEF_DIVOVF 0x00020000
-#define GTEF_SZ3SAT 0x00040000
-#define GTEF_CFRSAT 0x00080000
-#define GTEF_CFGSAT 0x00100000
-#define GTEF_CFBSAT 0x00200000
-#define GTEF_IR3SAT 0x00400000
-#define GTEF_IR2SAT 0x00800000
-#define GTEF_IR1SAT 0x01000000
-#define GTEF_M3NOVF 0x02000000
-#define GTEF_M2NOVF 0x04000000
-#define GTEF_M1NOVF 0x08000000
-#define GTEF_M3POVF 0x10000000
-#define GTEF_M2POVF 0x20000000
-#define GTEF_M1POVF 0x40000000
-#define GTEF_ERRORF 0x80000000
-
+void psx_cpu_fetch(psx_cpu_t*);
+void psx_cpu_set_a_kcall_hook(psx_cpu_t*, psx_cpu_kcall_hook_t);
+void psx_cpu_set_b_kcall_hook(psx_cpu_t*, psx_cpu_kcall_hook_t);
+int psx_cpu_execute(psx_cpu_t*);
+
+/*
+ 00h INT Interrupt
+ 01h MOD TLB modification (none such in PSX)
+ 02h TLBL TLB load (none such in PSX)
+ 03h TLBS TLB store (none such in PSX)
+ 04h AdEL Address error, Data load or Instruction fetch
+ 05h AdES Address error, Data store
+ The address errors occur when attempting to read
+ outside of KUseg in user mode and when the address
+ is misaligned. (See also: BadVaddr register)
+ 06h IBE Bus error on Instruction fetch
+ 07h DBE Bus error on Data load/store
+ 08h Syscall Generated unconditionally by syscall instruction
+ 09h BP Breakpoint - break instruction
+ 0Ah RI Reserved instruction
+ 0Bh CpU Coprocessor unusable
+ 0Ch Ov Arithmetic overflow
+*/
+
+#define CAUSE_INT (0x00 << 2)
+#define CAUSE_MOD (0x01 << 2)
+#define CAUSE_TLBL (0x02 << 2)
+#define CAUSE_TLBS (0x03 << 2)
+#define CAUSE_ADEL (0x04 << 2)
+#define CAUSE_ADES (0x05 << 2)
+#define CAUSE_IBE (0x06 << 2)
+#define CAUSE_DBE (0x07 << 2)
+#define CAUSE_SYSCALL (0x08 << 2)
+#define CAUSE_BP (0x09 << 2)
+#define CAUSE_RI (0x0a << 2)
+#define CAUSE_CPU (0x0b << 2)
+#define CAUSE_OV (0x0c << 2)
+
+/*
+ 31 Error Flag (Bit30..23, and 18..13 ORed together) (Read only)
+ 30 MAC1 Result positive 44bit overflow (max +7FFFFFFFFFFh) ;\triggered
+ 29 MAC2 Result positive 44bit overflow (max +7FFFFFFFFFFh) ; during
+ 28 MAC3 Result positive 44bit overflow (max +7FFFFFFFFFFh) ; calculations
+ 27 MAC1 Result negative 44bit overflow (min -80000000000h) ;
+ 26 MAC2 Result negative 44bit overflow (min -80000000000h) ;
+ 25 MAC3 Result negative 44bit overflow (min -80000000000h) ;/
+ 24 IR1 saturated to +0000h..+7FFFh (lm=1) or to -8000h..+7FFFh (lm=0)
+ 23 IR2 saturated to +0000h..+7FFFh (lm=1) or to -8000h..+7FFFh (lm=0)
+ 22 IR3 saturated to +0000h..+7FFFh (lm=1) or to -8000h..+7FFFh (lm=0)
+ 21 Color-FIFO-R saturated to +00h..+FFh
+ 20 Color-FIFO-G saturated to +00h..+FFh
+ 19 Color-FIFO-B saturated to +00h..+FFh
+ 18 SZ3 or OTZ saturated to +0000h..+FFFFh
+ 17 Divide overflow. RTPS/RTPT division result saturated to max=1FFFFh
+ 16 MAC0 Result positive 32bit overflow (max +7FFFFFFFh) ;\triggered on
+ 15 MAC0 Result negative 32bit overflow (min -80000000h) ;/final result
+ 14 SX2 saturated to -0400h..+03FFh
+ 13 SY2 saturated to -0400h..+03FFh
+*/
+
+#define GTEF_SY2SAT 0x00002000
+#define GTEF_SX2SAT 0x00004000
+#define GTEF_M0POVF 0x00008000
+#define GTEF_M0NOVF 0x00010000
+#define GTEF_DIVOVF 0x00020000
+#define GTEF_SZ3SAT 0x00040000
+#define GTEF_CFRSAT 0x00080000
+#define GTEF_CFGSAT 0x00100000
+#define GTEF_CFBSAT 0x00200000
+#define GTEF_IR3SAT 0x00400000
+#define GTEF_IR2SAT 0x00800000
+#define GTEF_IR1SAT 0x01000000
+#define GTEF_M3NOVF 0x02000000
+#define GTEF_M2NOVF 0x04000000
+#define GTEF_M1NOVF 0x08000000
+#define GTEF_M3POVF 0x10000000
+#define GTEF_M2POVF 0x20000000
+#define GTEF_M1POVF 0x40000000
+#define GTEF_ERRORF 0x80000000
+
#endif
--- a/psx/cpu_debug.h
+++ b/psx/cpu_debug.h
@@ -1,428 +1,428 @@
-#ifdef CPU_TRACE
-
-static const char* g_psx_cpu_a_kcall_symtable[] = {
- "open(filename=%08x,accessmode=%08x)",
- "lseek(fd=%08x,offset=%08x,seektype=%08x)",
- "read(fd=%08x,dst=%08x,length=%08x)",
- "write(fd=%08x,src=%08x,length=%08x)",
- "close(fd=%08x)",
- "ioctl(fd=%08x,cmd=%08x,arg=%08x)",
- "exit(exitcode=%08x)",
- "isatty(fd=%08x)",
- "getc(fd=%08x)",
- "putc(char=%08x,fd=%08x)",
- "todigit(char=%08x)",
- "atof(src=%08x)",
- "strtoul(src=%08x,src_end=%08x,base=%08x)",
- "strtol(src=%08x,src_end=%08x,base=%08x)",
- "abs(val=%08x)",
- "labs(val=%08x)",
- "atoi(src=%08x)",
- "atol(src=%08x)",
- "atob(src=%08x,num_dst=%08x)",
- "setjmp(buf=%08x)",
- "longjmp(buf=%08x,param=%08x)",
- "strcat(dst=%08x,src=%08x)",
- "strncat(dst=%08x,src=%08x,maxlen=%08x)",
- "strcmp(str1=%08x,str2=%08x)",
- "strncmp(str1=%08x,str2=%08x,maxlen=%08x)",
- "strcpy(dst=%08x,src=%08x)",
- "strncpy(dst=%08x,src=%08x,maxlen=%08x)",
- "strlen(src=%08x)",
- "index(src=%08x,char=%08x)",
- "rindex(src=%08x,char=%08x)",
- "strchr(src=%08x,char=%08x)",
- "strrchr(src=%08x,char=%08x)",
- "strpbrk(src=%08x,list=%08x)",
- "strspn(src=%08x,list=%08x)",
- "strcspn(src=%08x,list=%08x)",
- "strtok(src=%08x,list=%08x)",
- "strstr(str=%08x,substr=%08x)",
- "toupper(char=%08x)",
- "tolower(char=%08x)",
- "bcopy(src=%08x,dst=%08x,len=%08x)",
- "bzero(dst=%08x,len=%08x)",
- "bcmp(ptr1=%08x,ptr2=%08x,len=%08x)",
- "memcpy(dst=%08x,src=%08x,len=%08x)",
- "memset(dst=%08x,fillbyte=%08x,len=%08x)",
- "memmove(dst=%08x,src=%08x,len=%08x)",
- "memcmp(src1=%08x,src2=%08x,len=%08x)",
- "memchr(src=%08x,scanbyte=%08x,len=%08x)",
- "rand()",
- "srand(seed=%08x)",
- "qsort(base=%08x,nel=%08x,width=%08x,callback=%08x)",
- "strtod(src=%08x,src_end=%08x)",
- "malloc(size=%08x)",
- "free(buf=%08x)",
- "lsearch(key=%08x,base=%08x,nel=%08x,width=%08x,callback=%08x)",
- "bsearch(key=%08x,base=%08x,nel=%08x,width=%08x,callback=%08x)",
- "calloc(sizx=%08x,sizy=%08x)",
- "realloc(old_buf=%08x,new_siz=%08x)",
- "InitHeap(addr=%08x,size=%08x)",
- "_exit(exitcode=%08x)",
- "getchar()",
- "putchar(char=%08x)",
- "gets(dst=%08x)",
- "puts(src=%08x)",
- "printf(txt=%08x,param1=%08x,param2=%08x,etc.=%08x)",
- "SystemErrorUnresolvedException()",
- "LoadTest(filename=%08x,headerbuf=%08x)",
- "Load(filename=%08x,headerbuf=%08x)",
- "Exec(headerbuf=%08x,param1=%08x,param2=%08x)",
- "FlushCache()",
- "init_a0_b0_c0_vectors()",
- "GPU_dw(Xdst=%08x,Ydst=%08x,Xsiz=%08x,Ysiz=%08x,src=%08x)",
- "gpu_send_dma(Xdst=%08x,Ydst=%08x,Xsiz=%08x,Ysiz=%08x,src=%08x)",
- "SendGP1Command(gp1cmd=%08x)",
- "GPU_cw(gp0cmd=%08x)",
- "GPU_cwp(src=%08x,num=%08x)",
- "send_gpu_linked_list(src=%08x)",
- "gpu_abort_dma()",
- "GetGPUStatus()",
- "gpu_sync()",
- "SystemError()",
- "SystemError()",
- "LoadExec(filename=%08x,stackbase=%08x,stackoffset=%08x)",
- "GetSysSp()",
- "SystemError()",
- "_96_init()",
- "_bu_init()",
- "_96_remove()",
- "return 0",
- "return 0",
- "return 0",
- "return 0",
- "dev_tty_init()",
- "dev_tty_open(fcb=%08x, (unused)path=%08x,accessmode=%08x)",
- "dev_tty_in_out(fcb=%08x,cmd=%08x)",
- "dev_tty_ioctl(fcb=%08x,cmd=%08x,arg=%08x)",
- "dev_cd_open(fcb=%08x,path=%08x,accessmode=%08x)",
- "dev_cd_read(fcb=%08x,dst=%08x,len=%08x)",
- "dev_cd_close(fcb=%08x)",
- "dev_cd_firstfile(fcb=%08x,path=%08x,direntry=%08x)",
- "dev_cd_nextfile(fcb=%08x,direntry=%08x)",
- "dev_cd_chdir(fcb=%08x,path=%08x)",
- "dev_card_open(fcb=%08x,path=%08x,accessmode=%08x)",
- "dev_card_read(fcb=%08x,dst=%08x,len=%08x)",
- "dev_card_write(fcb=%08x,src=%08x,len=%08x)",
- "dev_card_close(fcb=%08x)",
- "dev_card_firstfile(fcb=%08x,path=%08x,direntry=%08x)",
- "dev_card_nextfile(fcb=%08x,direntry=%08x)",
- "dev_card_erase(fcb=%08x,path=%08x)",
- "dev_card_undelete(fcb=%08x,path=%08x)",
- "dev_card_format(fcb=%08x)",
- "dev_card_rename(fcb1=%08x,path=%08x)",
- "card_clear_error(fcb=%08x) (?)",
- "_bu_init()",
- "_96_init()",
- "_96_remove()",
- "return 0",
- "return 0",
- "return 0",
- "return 0",
- "return 0",
- "CdAsyncSeekL(src=%08x)",
- "return 0",
- "return 0",
- "return 0",
- "CdAsyncGetStatus(dst=%08x)",
- "return 0",
- "CdAsyncReadSector(count=%08x,dst=%08x,mode=%08x)",
- "return 0",
- "return 0",
- "CdAsyncSetMode(mode=%08x)",
- "return 0",
- "return 0",
- "return 0",
- "return 0",
- "return 0",
- "return 0",
- "return 0",
- "return 0",
- "return 0",
- "return 0",
- "return 0",
- "return 0",
- "return 0",
- "return 0",
- "CdromIoIrqFunc1()",
- "CdromDmaIrqFunc1()",
- "CdromIoIrqFunc2()",
- "CdromDmaIrqFunc2()",
- "CdromGetInt5errCode(dst1=%08x,dst2=%08x)",
- "CdInitSubFunc()",
- "AddCDROMDevice()",
- "AddMemCardDevice()",
- "AddDuartTtyDevice()",
- "add_nullcon_driver()",
- "SystemError()",
- "SystemError()",
- "SetConf(num_EvCB=%08x,num_TCB=%08x,stacktop=%08x)",
- "GetConf(num_EvCB_dst=%08x,num_TCB_dst=%08x,stacktop_dst=%08x)",
- "SetCdromIrqAutoAbort(type=%08x,flag=%08x)",
- "SetMem(megabytes=%08x)",
- "_boot()",
- "SystemError(type=%08x,errorcode=%08x)",
- "EnqueueCdIntr()",
- "DequeueCdIntr()",
- "CdGetLbn(filename=%08x)",
- "CdReadSector(count=%08x,sector=%08x,buffer=%08x)",
- "CdGetStatus()",
- "bufs_cb_0()",
- "bufs_cb_1()",
- "bufs_cb_2()",
- "bufs_cb_3()",
- "_card_info(port=%08x)",
- "_card_load(port=%08x)",
- "_card_auto(flag=%08x)",
- "bufs_cb_4()",
- "card_write_test(port=%08x)",
- "return 0",
- "return 0",
- "ioabort_raw(param=%08x)",
- "return 0",
- "GetSystemInfo(index=%08x)"
-};
-
-static const char* g_psx_cpu_b_kcall_symtable[] = {
- "alloc_kernel_memory(size=%08x)",
- "free_kernel_memory(buf=%08x)",
- "init_timer(t=%08x,reload=%08x,flags=%08x)",
- "get_timer(t=%08x)",
- "enable_timer_irq(t=%08x)",
- "disable_timer_irq(t=%08x)",
- "restart_timer(t=%08x)",
- "DeliverEvent(class=%08x, spec=%08x)",
- "OpenEvent(class=%08x,spec=%08x,mode=%08x,func=%08x)",
- "CloseEvent(event=%08x)",
- "WaitEvent(event=%08x)",
- "TestEvent(event=%08x)",
- "EnableEvent(event=%08x)",
- "DisableEvent(event=%08x)",
- "OpenTh(reg_PC=%08x,reg_SP_FP=%08x,reg_GP=%08x)",
- "CloseTh(handle=%08x)",
- "ChangeTh(handle=%08x)",
- "jump_to_00000000h()",
- "InitPAD2(buf1=%08x,siz1=%08x,buf2=%08x,siz2=%08x)",
- "StartPAD2()",
- "StopPAD2()",
- "PAD_init2(type=%08x,button_dest=%08x,unused=%08x,unused=%08x)",
- "PAD_dr()",
- "ReturnFromException()",
- "ResetEntryInt()",
- "HookEntryInt(addr=%08x)",
- "SystemError()",
- "SystemError()",
- "SystemError()",
- "SystemError()",
- "SystemError()",
- "SystemError()",
- "UnDeliverEvent(class=%08x,spec=%08x)",
- "SystemError()",
- "SystemError()",
- "SystemError()",
- "jump_to_00000000h()",
- "jump_to_00000000h()",
- "jump_to_00000000h()",
- "jump_to_00000000h()",
- "jump_to_00000000h()",
- "jump_to_00000000h()",
- "SystemError()",
- "SystemError()",
- "jump_to_00000000h()",
- "jump_to_00000000h()",
- "jump_to_00000000h()",
- "jump_to_00000000h()",
- "jump_to_00000000h()",
- "jump_to_00000000h()",
- "open(filename=%08x,accessmode=%08x)",
- "lseek(fd=%08x,offset=%08x,seektype=%08x)",
- "read(fd=%08x,dst=%08x,length=%08x)",
- "write(fd=%08x,src=%08x,length=%08x)",
- "close(fd=%08x)",
- "ioctl(fd=%08x,cmd=%08x,arg=%08x)",
- "exit(exitcode=%08x)",
- "isatty(fd=%08x)",
- "getc(fd=%08x)",
- "putc(char=%08x,fd=%08x)",
- "getchar()",
- "putchar(char=%08x)",
- "gets(dst=%08x)",
- "puts(src=%08x)",
- "cd(name=%08x)",
- "format(devicename=%08x)",
- "firstfile2(filename=%08x,direntry=%08x)",
- "nextfile(direntry=%08x)",
- "rename(old_filename=%08x,new_filename=%08x)",
- "erase(filename=%08x)",
- "undelete(filename=%08x)",
- "AddDrv(device_info=%08x)",
- "DelDrv(device_name_lowercase=%08x)",
- "PrintInstalledDevices()",
- "InitCARD2(pad_enable=%08x)",
- "StartCARD2()",
- "StopCARD2()",
- "_card_info_subfunc(port=%08x)",
- "_card_write(port=%08x,sector=%08x,src=%08x)",
- "_card_read(port=%08x,sector=%08x,dst=%08x)",
- "_new_card()",
- "Krom2RawAdd(shiftjis_code=%08x)",
- "SystemError()",
- "Krom2Offset(shiftjis_code=%08x)",
- "_get_errno()",
- "_get_error(fd=%08x)",
- "GetC0Table()",
- "GetB0Table()",
- "_card_chan()",
- "testdevice(devicename=%08x)",
- "SystemError()",
- "ChangeClearPAD(int=%08x)",
- "_card_status(slot=%08x)",
- "_card_wait(slot=%08x)"
-};
-
-static const char* g_psx_cpu_c_kcall_symtable[] = {
- "EnqueueTimerAndVblankIrqs(priority=%08x)",
- "EnqueueSyscallHandler(priority=%08x)",
- "SysEnqIntRP(priority=%08x,struc=%08x)",
- "SysDeqIntRP(priority=%08x,struc=%08x)",
- "get_free_EvCB_slot()",
- "get_free_TCB_slot()",
- "ExceptionHandler()",
- "InstallExceptionHandlers()",
- "SysInitMemory(addr=%08x,size=%08x)",
- "SysInitKernelVariables()",
- "ChangeClearRCnt(t=%08x,flag=%08x)",
- "SystemError()",
- "InitDefInt(priority=%08x)",
- "SetIrqAutoAck(irq=%08x,flag=%08x)",
- "return 0",
- "return 0",
- "return 0",
- "return 0",
- "InstallDevices(ttyflag=%08x)",
- "FlushStdInOutPut()",
- "return 0",
- "_cdevinput(circ=%08x,char=%08x)",
- "_cdevscan()",
- "_circgetc(circ=%08x)",
- "_circputc(char=%08x,circ=%08x)",
- "_ioabort(txt1=%08x,txt2=%08x)",
- "set_card_find_mode(mode=%08x)",
- "KernelRedirect(ttyflag=%08x)",
- "AdjustA0Table()",
- "get_card_find_mode()"
-};
-
-#define TRACE_M(m) \
- log_trace("%08x: %-7s $%s, %+i($%s)", cpu->pc-8, m, g_mips_cc_register_names[T], IMM16S, g_mips_cc_register_names[S])
-
-#define TRACE_I16S(m) \
- log_trace("%08x: %-7s $%s, 0x%04x", cpu->pc-8, m, g_mips_cc_register_names[T], IMM16)
-
-#define TRACE_I16D(m) \
- log_trace("%08x: %-7s $%s, $%s, 0x%04x", cpu->pc-8, m, g_mips_cc_register_names[T], g_mips_cc_register_names[S], IMM16)
-
-#define TRACE_I5D(m) \
- log_trace("%08x: %-7s $%s, $%s, %u", cpu->pc-8, m, g_mips_cc_register_names[D], g_mips_cc_register_names[T], IMM5)
-
-#define TRACE_I26(m) \
- log_trace("%08x: %-7s 0x%07x", cpu->pc-8, m, ((cpu->pc & 0xf0000000) | (IMM26 << 2)))
-
-#define TRACE_RT(m) \
- log_trace("%08x: %-7s $%s, $%s, $%s", cpu->pc-8, m, g_mips_cc_register_names[D], g_mips_cc_register_names[S], g_mips_cc_register_names[T])
-
-#define TRACE_C0M(m) \
- log_trace("%08x: %-7s $%s, $%s", cpu->pc-8, m, g_mips_cc_register_names[T], g_mips_cop0_register_names[D])
-
-#define TRACE_C2M(m) \
- log_trace("%08x: %-7s $%s, $cop2_r%u", cpu->pc-8, m, g_mips_cc_register_names[T], D)
-
-#define TRACE_C2MC(m) \
- log_trace("%08x: %-7s $%s, $cop2_r%u", cpu->pc-8, m, g_mips_cc_register_names[T], D + 32)
-
-#define TRACE_B(m) \
- log_trace("%08x: %-7s $%s, $%s, %-i", cpu->pc-8, m, g_mips_cc_register_names[S], g_mips_cc_register_names[T], IMM16S << 2)
-
-#define TRACE_RS(m) \
- log_trace("%08x: %-7s $%s", cpu->pc-8, m, g_mips_cc_register_names[S])
-
-#define TRACE_MTF(m) \
- log_trace("%08x: %-7s $%s", cpu->pc-8, m, g_mips_cc_register_names[D])
-
-#define TRACE_RD(m) \
- log_trace("%08x: %-7s $%s, $%s", cpu->pc-8, m, g_mips_cc_register_names[D], g_mips_cc_register_names[S])
-
-#define TRACE_MD(m) \
- log_trace("%08x: %-7s $%s, $%s", cpu->pc-8, m, g_mips_cc_register_names[S], g_mips_cc_register_names[T]);
-
-#define TRACE_I20(m) \
- log_trace("%08x: %-7s 0x%05x", cpu->pc-8, m, CMT);
-
-#define TRACE_N(m) \
- log_trace("%08x: %-7s", cpu->pc-8, m);
-
-#define DEBUG_ALL \
- log_fatal("r0=%08x at=%08x v0=%08x v1=%08x", cpu->r[0] , cpu->r[1] , cpu->r[2] , cpu->r[3] ); \
- log_fatal("a0=%08x a1=%08x a2=%08x a3=%08x", cpu->r[4] , cpu->r[5] , cpu->r[6] , cpu->r[7] ); \
- log_fatal("t0=%08x t1=%08x t2=%08x t3=%08x", cpu->r[8] , cpu->r[9] , cpu->r[10], cpu->r[11]); \
- log_fatal("t4=%08x t5=%08x t6=%08x t7=%08x", cpu->r[12], cpu->r[13], cpu->r[14], cpu->r[15]); \
- log_fatal("s0=%08x s1=%08x s2=%08x s3=%08x", cpu->r[16], cpu->r[17], cpu->r[18], cpu->r[19]); \
- log_fatal("s4=%08x s5=%08x s6=%08x s7=%08x", cpu->r[20], cpu->r[21], cpu->r[22], cpu->r[23]); \
- log_fatal("t8=%08x t9=%08x k0=%08x k1=%08x", cpu->r[24], cpu->r[25], cpu->r[26], cpu->r[27]); \
- log_fatal("gp=%08x sp=%08x fp=%08x ra=%08x", cpu->r[28], cpu->r[29], cpu->r[30], cpu->r[31]); \
- log_fatal("pc=%08x hi=%08x lo=%08x l:%s=%08x", cpu->pc, cpu->hi, cpu->lo, g_mips_cc_register_names[cpu->load_d], cpu->load_v); \
- exit(1)
-
-const char* g_mips_cop0_register_names[] = {
- "cop0_r0",
- "cop0_r1",
- "cop0_r2",
- "cop0_bpc",
- "cop0_r4",
- "cop0_bda",
- "cop0_jumpdest",
- "cop0_dcic",
- "cop0_badvaddr",
- "cop0_bdam",
- "cop0_r10",
- "cop0_bpcm",
- "cop0_sr",
- "cop0_cause",
- "cop0_epc",
- "cop0_prid"
-};
-
-static const char* g_mips_cc_register_names[] = {
- "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
- "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
- "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
- "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"
-};
-
-static const char* g_psx_cpu_syscall_function_symbol_table[] = {
- "NoFunction",
- "EnterCriticalSection",
- "ExitCriticalSection",
- "ChangeThreadSubFunction"
- // DeliverEvent (invalid)
-};
-
-#else
-#define TRACE_M(m)
-#define TRACE_I16S(m)
-#define TRACE_I16D(m)
-#define TRACE_I5D(m)
-#define TRACE_I26(m)
-#define TRACE_RT(m)
-#define TRACE_C0M(m)
-#define TRACE_C2M(m)
-#define TRACE_C2MC(m)
-#define TRACE_B(m)
-#define TRACE_RS(m)
-#define TRACE_MTF(m)
-#define TRACE_RD(m)
-#define TRACE_MD(m)
-#define TRACE_I20(m)
-#define TRACE_N(m)
+#ifdef CPU_TRACE
+
+static const char* g_psx_cpu_a_kcall_symtable[] = {+ "open(filename=%08x,accessmode=%08x)",
+ "lseek(fd=%08x,offset=%08x,seektype=%08x)",
+ "read(fd=%08x,dst=%08x,length=%08x)",
+ "write(fd=%08x,src=%08x,length=%08x)",
+ "close(fd=%08x)",
+ "ioctl(fd=%08x,cmd=%08x,arg=%08x)",
+ "exit(exitcode=%08x)",
+ "isatty(fd=%08x)",
+ "getc(fd=%08x)",
+ "putc(char=%08x,fd=%08x)",
+ "todigit(char=%08x)",
+ "atof(src=%08x)",
+ "strtoul(src=%08x,src_end=%08x,base=%08x)",
+ "strtol(src=%08x,src_end=%08x,base=%08x)",
+ "abs(val=%08x)",
+ "labs(val=%08x)",
+ "atoi(src=%08x)",
+ "atol(src=%08x)",
+ "atob(src=%08x,num_dst=%08x)",
+ "setjmp(buf=%08x)",
+ "longjmp(buf=%08x,param=%08x)",
+ "strcat(dst=%08x,src=%08x)",
+ "strncat(dst=%08x,src=%08x,maxlen=%08x)",
+ "strcmp(str1=%08x,str2=%08x)",
+ "strncmp(str1=%08x,str2=%08x,maxlen=%08x)",
+ "strcpy(dst=%08x,src=%08x)",
+ "strncpy(dst=%08x,src=%08x,maxlen=%08x)",
+ "strlen(src=%08x)",
+ "index(src=%08x,char=%08x)",
+ "rindex(src=%08x,char=%08x)",
+ "strchr(src=%08x,char=%08x)",
+ "strrchr(src=%08x,char=%08x)",
+ "strpbrk(src=%08x,list=%08x)",
+ "strspn(src=%08x,list=%08x)",
+ "strcspn(src=%08x,list=%08x)",
+ "strtok(src=%08x,list=%08x)",
+ "strstr(str=%08x,substr=%08x)",
+ "toupper(char=%08x)",
+ "tolower(char=%08x)",
+ "bcopy(src=%08x,dst=%08x,len=%08x)",
+ "bzero(dst=%08x,len=%08x)",
+ "bcmp(ptr1=%08x,ptr2=%08x,len=%08x)",
+ "memcpy(dst=%08x,src=%08x,len=%08x)",
+ "memset(dst=%08x,fillbyte=%08x,len=%08x)",
+ "memmove(dst=%08x,src=%08x,len=%08x)",
+ "memcmp(src1=%08x,src2=%08x,len=%08x)",
+ "memchr(src=%08x,scanbyte=%08x,len=%08x)",
+ "rand()",
+ "srand(seed=%08x)",
+ "qsort(base=%08x,nel=%08x,width=%08x,callback=%08x)",
+ "strtod(src=%08x,src_end=%08x)",
+ "malloc(size=%08x)",
+ "free(buf=%08x)",
+ "lsearch(key=%08x,base=%08x,nel=%08x,width=%08x,callback=%08x)",
+ "bsearch(key=%08x,base=%08x,nel=%08x,width=%08x,callback=%08x)",
+ "calloc(sizx=%08x,sizy=%08x)",
+ "realloc(old_buf=%08x,new_siz=%08x)",
+ "InitHeap(addr=%08x,size=%08x)",
+ "_exit(exitcode=%08x)",
+ "getchar()",
+ "putchar(char=%08x)",
+ "gets(dst=%08x)",
+ "puts(src=%08x)",
+ "printf(txt=%08x,param1=%08x,param2=%08x,etc.=%08x)",
+ "SystemErrorUnresolvedException()",
+ "LoadTest(filename=%08x,headerbuf=%08x)",
+ "Load(filename=%08x,headerbuf=%08x)",
+ "Exec(headerbuf=%08x,param1=%08x,param2=%08x)",
+ "FlushCache()",
+ "init_a0_b0_c0_vectors()",
+ "GPU_dw(Xdst=%08x,Ydst=%08x,Xsiz=%08x,Ysiz=%08x,src=%08x)",
+ "gpu_send_dma(Xdst=%08x,Ydst=%08x,Xsiz=%08x,Ysiz=%08x,src=%08x)",
+ "SendGP1Command(gp1cmd=%08x)",
+ "GPU_cw(gp0cmd=%08x)",
+ "GPU_cwp(src=%08x,num=%08x)",
+ "send_gpu_linked_list(src=%08x)",
+ "gpu_abort_dma()",
+ "GetGPUStatus()",
+ "gpu_sync()",
+ "SystemError()",
+ "SystemError()",
+ "LoadExec(filename=%08x,stackbase=%08x,stackoffset=%08x)",
+ "GetSysSp()",
+ "SystemError()",
+ "_96_init()",
+ "_bu_init()",
+ "_96_remove()",
+ "return 0",
+ "return 0",
+ "return 0",
+ "return 0",
+ "dev_tty_init()",
+ "dev_tty_open(fcb=%08x, (unused)path=%08x,accessmode=%08x)",
+ "dev_tty_in_out(fcb=%08x,cmd=%08x)",
+ "dev_tty_ioctl(fcb=%08x,cmd=%08x,arg=%08x)",
+ "dev_cd_open(fcb=%08x,path=%08x,accessmode=%08x)",
+ "dev_cd_read(fcb=%08x,dst=%08x,len=%08x)",
+ "dev_cd_close(fcb=%08x)",
+ "dev_cd_firstfile(fcb=%08x,path=%08x,direntry=%08x)",
+ "dev_cd_nextfile(fcb=%08x,direntry=%08x)",
+ "dev_cd_chdir(fcb=%08x,path=%08x)",
+ "dev_card_open(fcb=%08x,path=%08x,accessmode=%08x)",
+ "dev_card_read(fcb=%08x,dst=%08x,len=%08x)",
+ "dev_card_write(fcb=%08x,src=%08x,len=%08x)",
+ "dev_card_close(fcb=%08x)",
+ "dev_card_firstfile(fcb=%08x,path=%08x,direntry=%08x)",
+ "dev_card_nextfile(fcb=%08x,direntry=%08x)",
+ "dev_card_erase(fcb=%08x,path=%08x)",
+ "dev_card_undelete(fcb=%08x,path=%08x)",
+ "dev_card_format(fcb=%08x)",
+ "dev_card_rename(fcb1=%08x,path=%08x)",
+ "card_clear_error(fcb=%08x) (?)",
+ "_bu_init()",
+ "_96_init()",
+ "_96_remove()",
+ "return 0",
+ "return 0",
+ "return 0",
+ "return 0",
+ "return 0",
+ "CdAsyncSeekL(src=%08x)",
+ "return 0",
+ "return 0",
+ "return 0",
+ "CdAsyncGetStatus(dst=%08x)",
+ "return 0",
+ "CdAsyncReadSector(count=%08x,dst=%08x,mode=%08x)",
+ "return 0",
+ "return 0",
+ "CdAsyncSetMode(mode=%08x)",
+ "return 0",
+ "return 0",
+ "return 0",
+ "return 0",
+ "return 0",
+ "return 0",
+ "return 0",
+ "return 0",
+ "return 0",
+ "return 0",
+ "return 0",
+ "return 0",
+ "return 0",
+ "return 0",
+ "CdromIoIrqFunc1()",
+ "CdromDmaIrqFunc1()",
+ "CdromIoIrqFunc2()",
+ "CdromDmaIrqFunc2()",
+ "CdromGetInt5errCode(dst1=%08x,dst2=%08x)",
+ "CdInitSubFunc()",
+ "AddCDROMDevice()",
+ "AddMemCardDevice()",
+ "AddDuartTtyDevice()",
+ "add_nullcon_driver()",
+ "SystemError()",
+ "SystemError()",
+ "SetConf(num_EvCB=%08x,num_TCB=%08x,stacktop=%08x)",
+ "GetConf(num_EvCB_dst=%08x,num_TCB_dst=%08x,stacktop_dst=%08x)",
+ "SetCdromIrqAutoAbort(type=%08x,flag=%08x)",
+ "SetMem(megabytes=%08x)",
+ "_boot()",
+ "SystemError(type=%08x,errorcode=%08x)",
+ "EnqueueCdIntr()",
+ "DequeueCdIntr()",
+ "CdGetLbn(filename=%08x)",
+ "CdReadSector(count=%08x,sector=%08x,buffer=%08x)",
+ "CdGetStatus()",
+ "bufs_cb_0()",
+ "bufs_cb_1()",
+ "bufs_cb_2()",
+ "bufs_cb_3()",
+ "_card_info(port=%08x)",
+ "_card_load(port=%08x)",
+ "_card_auto(flag=%08x)",
+ "bufs_cb_4()",
+ "card_write_test(port=%08x)",
+ "return 0",
+ "return 0",
+ "ioabort_raw(param=%08x)",
+ "return 0",
+ "GetSystemInfo(index=%08x)"
+};
+
+static const char* g_psx_cpu_b_kcall_symtable[] = {+ "alloc_kernel_memory(size=%08x)",
+ "free_kernel_memory(buf=%08x)",
+ "init_timer(t=%08x,reload=%08x,flags=%08x)",
+ "get_timer(t=%08x)",
+ "enable_timer_irq(t=%08x)",
+ "disable_timer_irq(t=%08x)",
+ "restart_timer(t=%08x)",
+ "DeliverEvent(class=%08x, spec=%08x)",
+ "OpenEvent(class=%08x,spec=%08x,mode=%08x,func=%08x)",
+ "CloseEvent(event=%08x)",
+ "WaitEvent(event=%08x)",
+ "TestEvent(event=%08x)",
+ "EnableEvent(event=%08x)",
+ "DisableEvent(event=%08x)",
+ "OpenTh(reg_PC=%08x,reg_SP_FP=%08x,reg_GP=%08x)",
+ "CloseTh(handle=%08x)",
+ "ChangeTh(handle=%08x)",
+ "jump_to_00000000h()",
+ "InitPAD2(buf1=%08x,siz1=%08x,buf2=%08x,siz2=%08x)",
+ "StartPAD2()",
+ "StopPAD2()",
+ "PAD_init2(type=%08x,button_dest=%08x,unused=%08x,unused=%08x)",
+ "PAD_dr()",
+ "ReturnFromException()",
+ "ResetEntryInt()",
+ "HookEntryInt(addr=%08x)",
+ "SystemError()",
+ "SystemError()",
+ "SystemError()",
+ "SystemError()",
+ "SystemError()",
+ "SystemError()",
+ "UnDeliverEvent(class=%08x,spec=%08x)",
+ "SystemError()",
+ "SystemError()",
+ "SystemError()",
+ "jump_to_00000000h()",
+ "jump_to_00000000h()",
+ "jump_to_00000000h()",
+ "jump_to_00000000h()",
+ "jump_to_00000000h()",
+ "jump_to_00000000h()",
+ "SystemError()",
+ "SystemError()",
+ "jump_to_00000000h()",
+ "jump_to_00000000h()",
+ "jump_to_00000000h()",
+ "jump_to_00000000h()",
+ "jump_to_00000000h()",
+ "jump_to_00000000h()",
+ "open(filename=%08x,accessmode=%08x)",
+ "lseek(fd=%08x,offset=%08x,seektype=%08x)",
+ "read(fd=%08x,dst=%08x,length=%08x)",
+ "write(fd=%08x,src=%08x,length=%08x)",
+ "close(fd=%08x)",
+ "ioctl(fd=%08x,cmd=%08x,arg=%08x)",
+ "exit(exitcode=%08x)",
+ "isatty(fd=%08x)",
+ "getc(fd=%08x)",
+ "putc(char=%08x,fd=%08x)",
+ "getchar()",
+ "putchar(char=%08x)",
+ "gets(dst=%08x)",
+ "puts(src=%08x)",
+ "cd(name=%08x)",
+ "format(devicename=%08x)",
+ "firstfile2(filename=%08x,direntry=%08x)",
+ "nextfile(direntry=%08x)",
+ "rename(old_filename=%08x,new_filename=%08x)",
+ "erase(filename=%08x)",
+ "undelete(filename=%08x)",
+ "AddDrv(device_info=%08x)",
+ "DelDrv(device_name_lowercase=%08x)",
+ "PrintInstalledDevices()",
+ "InitCARD2(pad_enable=%08x)",
+ "StartCARD2()",
+ "StopCARD2()",
+ "_card_info_subfunc(port=%08x)",
+ "_card_write(port=%08x,sector=%08x,src=%08x)",
+ "_card_read(port=%08x,sector=%08x,dst=%08x)",
+ "_new_card()",
+ "Krom2RawAdd(shiftjis_code=%08x)",
+ "SystemError()",
+ "Krom2Offset(shiftjis_code=%08x)",
+ "_get_errno()",
+ "_get_error(fd=%08x)",
+ "GetC0Table()",
+ "GetB0Table()",
+ "_card_chan()",
+ "testdevice(devicename=%08x)",
+ "SystemError()",
+ "ChangeClearPAD(int=%08x)",
+ "_card_status(slot=%08x)",
+ "_card_wait(slot=%08x)"
+};
+
+static const char* g_psx_cpu_c_kcall_symtable[] = {+ "EnqueueTimerAndVblankIrqs(priority=%08x)",
+ "EnqueueSyscallHandler(priority=%08x)",
+ "SysEnqIntRP(priority=%08x,struc=%08x)",
+ "SysDeqIntRP(priority=%08x,struc=%08x)",
+ "get_free_EvCB_slot()",
+ "get_free_TCB_slot()",
+ "ExceptionHandler()",
+ "InstallExceptionHandlers()",
+ "SysInitMemory(addr=%08x,size=%08x)",
+ "SysInitKernelVariables()",
+ "ChangeClearRCnt(t=%08x,flag=%08x)",
+ "SystemError()",
+ "InitDefInt(priority=%08x)",
+ "SetIrqAutoAck(irq=%08x,flag=%08x)",
+ "return 0",
+ "return 0",
+ "return 0",
+ "return 0",
+ "InstallDevices(ttyflag=%08x)",
+ "FlushStdInOutPut()",
+ "return 0",
+ "_cdevinput(circ=%08x,char=%08x)",
+ "_cdevscan()",
+ "_circgetc(circ=%08x)",
+ "_circputc(char=%08x,circ=%08x)",
+ "_ioabort(txt1=%08x,txt2=%08x)",
+ "set_card_find_mode(mode=%08x)",
+ "KernelRedirect(ttyflag=%08x)",
+ "AdjustA0Table()",
+ "get_card_find_mode()"
+};
+
+#define TRACE_M(m) \
+ log_trace("%08x: %-7s $%s, %+i($%s)", cpu->pc-8, m, g_mips_cc_register_names[T], IMM16S, g_mips_cc_register_names[S])+
+#define TRACE_I16S(m) \
+ log_trace("%08x: %-7s $%s, 0x%04x", cpu->pc-8, m, g_mips_cc_register_names[T], IMM16)+
+#define TRACE_I16D(m) \
+ log_trace("%08x: %-7s $%s, $%s, 0x%04x", cpu->pc-8, m, g_mips_cc_register_names[T], g_mips_cc_register_names[S], IMM16)+
+#define TRACE_I5D(m) \
+ log_trace("%08x: %-7s $%s, $%s, %u", cpu->pc-8, m, g_mips_cc_register_names[D], g_mips_cc_register_names[T], IMM5)+
+#define TRACE_I26(m) \
+ log_trace("%08x: %-7s 0x%07x", cpu->pc-8, m, ((cpu->pc & 0xf0000000) | (IMM26 << 2)))+
+#define TRACE_RT(m) \
+ log_trace("%08x: %-7s $%s, $%s, $%s", cpu->pc-8, m, g_mips_cc_register_names[D], g_mips_cc_register_names[S], g_mips_cc_register_names[T])+
+#define TRACE_C0M(m) \
+ log_trace("%08x: %-7s $%s, $%s", cpu->pc-8, m, g_mips_cc_register_names[T], g_mips_cop0_register_names[D])+
+#define TRACE_C2M(m) \
+ log_trace("%08x: %-7s $%s, $cop2_r%u", cpu->pc-8, m, g_mips_cc_register_names[T], D)+
+#define TRACE_C2MC(m) \
+ log_trace("%08x: %-7s $%s, $cop2_r%u", cpu->pc-8, m, g_mips_cc_register_names[T], D + 32)+
+#define TRACE_B(m) \
+ log_trace("%08x: %-7s $%s, $%s, %-i", cpu->pc-8, m, g_mips_cc_register_names[S], g_mips_cc_register_names[T], IMM16S << 2)+
+#define TRACE_RS(m) \
+ log_trace("%08x: %-7s $%s", cpu->pc-8, m, g_mips_cc_register_names[S])+
+#define TRACE_MTF(m) \
+ log_trace("%08x: %-7s $%s", cpu->pc-8, m, g_mips_cc_register_names[D])+
+#define TRACE_RD(m) \
+ log_trace("%08x: %-7s $%s, $%s", cpu->pc-8, m, g_mips_cc_register_names[D], g_mips_cc_register_names[S])+
+#define TRACE_MD(m) \
+ log_trace("%08x: %-7s $%s, $%s", cpu->pc-8, m, g_mips_cc_register_names[S], g_mips_cc_register_names[T]);+
+#define TRACE_I20(m) \
+ log_trace("%08x: %-7s 0x%05x", cpu->pc-8, m, CMT);+
+#define TRACE_N(m) \
+ log_trace("%08x: %-7s", cpu->pc-8, m);+
+#define DEBUG_ALL \
+ log_fatal("r0=%08x at=%08x v0=%08x v1=%08x", cpu->r[0] , cpu->r[1] , cpu->r[2] , cpu->r[3] ); \+ log_fatal("a0=%08x a1=%08x a2=%08x a3=%08x", cpu->r[4] , cpu->r[5] , cpu->r[6] , cpu->r[7] ); \+ log_fatal("t0=%08x t1=%08x t2=%08x t3=%08x", cpu->r[8] , cpu->r[9] , cpu->r[10], cpu->r[11]); \+ log_fatal("t4=%08x t5=%08x t6=%08x t7=%08x", cpu->r[12], cpu->r[13], cpu->r[14], cpu->r[15]); \+ log_fatal("s0=%08x s1=%08x s2=%08x s3=%08x", cpu->r[16], cpu->r[17], cpu->r[18], cpu->r[19]); \+ log_fatal("s4=%08x s5=%08x s6=%08x s7=%08x", cpu->r[20], cpu->r[21], cpu->r[22], cpu->r[23]); \+ log_fatal("t8=%08x t9=%08x k0=%08x k1=%08x", cpu->r[24], cpu->r[25], cpu->r[26], cpu->r[27]); \+ log_fatal("gp=%08x sp=%08x fp=%08x ra=%08x", cpu->r[28], cpu->r[29], cpu->r[30], cpu->r[31]); \+ log_fatal("pc=%08x hi=%08x lo=%08x l:%s=%08x", cpu->pc, cpu->hi, cpu->lo, g_mips_cc_register_names[cpu->load_d], cpu->load_v); \+ exit(1)
+
+const char* g_mips_cop0_register_names[] = {+ "cop0_r0",
+ "cop0_r1",
+ "cop0_r2",
+ "cop0_bpc",
+ "cop0_r4",
+ "cop0_bda",
+ "cop0_jumpdest",
+ "cop0_dcic",
+ "cop0_badvaddr",
+ "cop0_bdam",
+ "cop0_r10",
+ "cop0_bpcm",
+ "cop0_sr",
+ "cop0_cause",
+ "cop0_epc",
+ "cop0_prid"
+};
+
+static const char* g_mips_cc_register_names[] = {+ "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
+ "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
+ "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
+ "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"
+};
+
+static const char* g_psx_cpu_syscall_function_symbol_table[] = {+ "NoFunction",
+ "EnterCriticalSection",
+ "ExitCriticalSection",
+ "ChangeThreadSubFunction"
+ // DeliverEvent (invalid)
+};
+
+#else
+#define TRACE_M(m)
+#define TRACE_I16S(m)
+#define TRACE_I16D(m)
+#define TRACE_I5D(m)
+#define TRACE_I26(m)
+#define TRACE_RT(m)
+#define TRACE_C0M(m)
+#define TRACE_C2M(m)
+#define TRACE_C2MC(m)
+#define TRACE_B(m)
+#define TRACE_RS(m)
+#define TRACE_MTF(m)
+#define TRACE_RD(m)
+#define TRACE_MD(m)
+#define TRACE_I20(m)
+#define TRACE_N(m)
#endif
\ No newline at end of file
--- a/psx/dev/bios.c
+++ b/psx/dev/bios.c
@@ -25,15 +25,15 @@
psx_bios_t* psx_bios_create(void) {return (psx_bios_t*)malloc(sizeof(psx_bios_t));
}
-
-void psx_bios_init(psx_bios_t* bios) {
- memset(bios, 0, sizeof(psx_bios_t));
-
- bios->io_base = PSX_BIOS_BEGIN;
- bios->io_size = PSX_BIOS_SIZE;
- bios->bus_delay = 18;
-}
-
+
+void psx_bios_init(psx_bios_t* bios) {+ memset(bios, 0, sizeof(psx_bios_t));
+
+ bios->io_base = PSX_BIOS_BEGIN;
+ bios->io_size = PSX_BIOS_SIZE;
+ bios->bus_delay = 18;
+}
+
int psx_bios_load(psx_bios_t* bios, const char* path) {if (!path)
return 0;
@@ -43,12 +43,12 @@
if (fd < 0)
return 1;
-
- // Almost all PS1 BIOS ROMs are 512 KiB in size.
- // There's (at least) one exception, and that is SCPH-5903.
- // This is a special asian model PS1 that had built-in support
- // for Video CD (VCD) playback. Its BIOS is double the normal
- // size
+
+ // Almost all PS1 BIOS ROMs are 512 KiB in size.
+ // There's (at least) one exception, and that is SCPH-5903.
+ // This is a special asian model PS1 that had built-in support
+ // for Video CD (VCD) playback. Its BIOS is double the normal
+ // size
size = seek(fd, 0, 2);
if (size <= 0) {close(fd);
@@ -76,19 +76,19 @@
return 0;
}
-
-uint32_t psx_bios_read32(psx_bios_t* bios, uint32_t offset) {
- return *((uint32_t*)(bios->buf + offset));
-}
-
-uint16_t psx_bios_read16(psx_bios_t* bios, uint32_t offset) {
- return *((uint16_t*)(bios->buf + offset));
-}
-
-uint8_t psx_bios_read8(psx_bios_t* bios, uint32_t offset) {
- return bios->buf[offset];
-}
-
+
+uint32_t psx_bios_read32(psx_bios_t* bios, uint32_t offset) {+ return *((uint32_t*)(bios->buf + offset));
+}
+
+uint16_t psx_bios_read16(psx_bios_t* bios, uint32_t offset) {+ return *((uint16_t*)(bios->buf + offset));
+}
+
+uint8_t psx_bios_read8(psx_bios_t* bios, uint32_t offset) {+ return bios->buf[offset];
+}
+
void psx_bios_write32(psx_bios_t* bios, uint32_t offset, uint32_t value) {USED(bios);
log_warn("Unhandled 32-bit BIOS write at offset %08x (%08x)", offset, value);@@ -103,8 +103,8 @@
USED(bios);
log_warn("Unhandled 8-bit BIOS write at offset %08x (%02x)", offset, value);}
-
-void psx_bios_destroy(psx_bios_t* bios) {
- free(bios->buf);
- free(bios);
+
+void psx_bios_destroy(psx_bios_t* bios) {+ free(bios->buf);
+ free(bios);
}
--- a/psx/dev/bios.h
+++ b/psx/dev/bios.h
@@ -1,14 +1,14 @@
#ifndef PSX_DEV_BIOS_H
-#define PSX_DEV_BIOS_H
-
-#include "p9.h"
-
-#include "log.h"
-
-#define PSX_BIOS_SIZE 0x80000
-#define PSX_BIOS_BEGIN 0x1fc00000
-#define PSX_BIOS_END 0x1fc7ffff
-
+#define PSX_DEV_BIOS_H
+
+#include "p9.h"
+
+#include "log.h"
+
+#define PSX_BIOS_SIZE 0x80000
+#define PSX_BIOS_BEGIN 0x1fc00000
+#define PSX_BIOS_END 0x1fc7ffff
+
struct psx_bios_t {uint32_t bus_delay;
uint32_t io_base, io_size;
@@ -17,16 +17,16 @@
};
typedef struct psx_bios_t psx_bios_t;
-
-psx_bios_t* psx_bios_create(void);
-void psx_bios_init(psx_bios_t*);
-int psx_bios_load(psx_bios_t*, const char*);
-uint32_t psx_bios_read32(psx_bios_t*, uint32_t);
-uint16_t psx_bios_read16(psx_bios_t*, uint32_t);
-uint8_t psx_bios_read8(psx_bios_t*, uint32_t);
-void psx_bios_write32(psx_bios_t*, uint32_t, uint32_t);
-void psx_bios_write16(psx_bios_t*, uint32_t, uint16_t);
-void psx_bios_write8(psx_bios_t*, uint32_t, uint8_t);
-void psx_bios_destroy(psx_bios_t*);
-
+
+psx_bios_t* psx_bios_create(void);
+void psx_bios_init(psx_bios_t*);
+int psx_bios_load(psx_bios_t*, const char*);
+uint32_t psx_bios_read32(psx_bios_t*, uint32_t);
+uint16_t psx_bios_read16(psx_bios_t*, uint32_t);
+uint8_t psx_bios_read8(psx_bios_t*, uint32_t);
+void psx_bios_write32(psx_bios_t*, uint32_t, uint32_t);
+void psx_bios_write16(psx_bios_t*, uint32_t, uint16_t);
+void psx_bios_write8(psx_bios_t*, uint32_t, uint8_t);
+void psx_bios_destroy(psx_bios_t*);
+
#endif
--- a/psx/dev/cdrom/cue.c
+++ b/psx/dev/cdrom/cue.c
@@ -139,30 +139,28 @@
}
uint32_t cue_parse_msf(cue_t* cue) {- uint32_t frames = 0;
+ int mm, ss, ff;
if (!isdigit(cue->c))
return 0;
- frames = cue_parse_number(cue) * 4500;
+ mm = cue_parse_number(cue);
if (cue->c != ':')
return 0;
cue->c = fgetc(cue->file);
+ ss = cue_parse_number(cue);
- frames += cue_parse_number(cue) * 75;
-
if (cue->c != ':')
return 0;
cue->c = fgetc(cue->file);
+ ff = cue_parse_number(cue);
- frames += cue_parse_number(cue);
-
// 1 second = 75 frames (sectors)
// 1 minute = 60 seconds = 4500 frames
- return frames;
+ return (mm * 60 + ss) * 75 + ff;
}
void cue_parse_index(cue_t* cue) {--- a/psx/dev/cdrom/impl.c
+++ b/psx/dev/cdrom/impl.c
@@ -179,7 +179,7 @@
int ss = (cdrom->lba % (60 * 75)) / 75;
int ff = (cdrom->lba % (60 * 75)) % 75;
- printf("play song at lba=%08x %02u:%02u:%02u track=%d\n", cdrom->lba, mm, ss, ff, track);+ printf("play song at lba=%08x %02d:%02d:%02d track=%d\n", cdrom->lba, mm, ss, ff, track);cdrom->prev_state = CD_STATE_PLAY;
cdrom->state = CD_STATE_PLAY;
@@ -706,11 +706,12 @@
}
void cdrom_cmd_reset(psx_cdrom_t* cdrom) {+ USED(cdrom);
printf("reset\n");}
void cdrom_cmd_getq(psx_cdrom_t* cdrom) {-
+ USED(cdrom);
}
void cdrom_cmd_readtoc(psx_cdrom_t* cdrom) {@@ -731,5 +732,5 @@
}
void cdrom_cmd_videocd(psx_cdrom_t* cdrom) {-
+ USED(cdrom);
}
--- a/psx/dev/dma.c
+++ b/psx/dev/dma.c
@@ -1,292 +1,292 @@
-#include "dev/dma.h"
-#include "log.h"
-
-#include "p9.h"
-
-psx_dma_t* psx_dma_create(void) {
- return (psx_dma_t*)malloc(sizeof(psx_dma_t));
-}
-
-const uint32_t g_psx_dma_ctrl_hw_1_table[] = {
- 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000,
- 0x00000002
-};
-
-const uint32_t g_psx_dma_ctrl_hw_0_table[] = {
- 0x71770703, 0x71770703, 0x71770703,
- 0x71770703, 0x71770703, 0x71770703,
- 0x50000002
-};
-
-const psx_dma_do_fn_t g_psx_dma_do_table[] = {
- psx_dma_do_mdec_in,
- psx_dma_do_mdec_out,
- psx_dma_do_gpu,
- psx_dma_do_cdrom,
- psx_dma_do_spu,
- psx_dma_do_pio,
- psx_dma_do_otc
-};
-
-#define CR(c, r) *((&dma->mdec_in.madr) + (c * 3) + r)
-
-void psx_dma_init(psx_dma_t* dma, psx_bus_t* bus, psx_ic_t* ic) {
- memset(dma, 0, sizeof(psx_dma_t));
-
- dma->io_base = PSX_DMAR_BEGIN;
- dma->io_size = PSX_DMAR_SIZE;
-
- dma->bus = bus;
- dma->ic = ic;
-
- dma->dpcr = 0x07654321;
-}
-
-uint32_t psx_dma_read32(psx_dma_t* dma, uint32_t offset) {
- if (offset < 0x70) {
- int channel = (offset >> 4) & 0x7;
- int reg = (offset >> 2) & 0x3;
- uint32_t cr = CR(channel, reg);
-
- if (reg == 2) {
- cr |= g_psx_dma_ctrl_hw_1_table[channel];
- cr &= g_psx_dma_ctrl_hw_0_table[channel];
- }
-
- log_error("DMA channel %u register %u (%08x) read %08x", channel, reg, PSX_DMAR_BEGIN + offset, cr);
-
- return cr;
- } else {
- switch (offset) {
- case 0x70: log_error("DMA control read %08x", dma->dpcr); return dma->dpcr;
- case 0x74: log_error("DMA irqc read %08x", dma->dicr); return dma->dicr;
-
- default: {
- log_error("Unhandled 32-bit DMA read at offset %08x", offset);
-
- return 0x0;
- }
- }
- }
-}
-
-uint16_t psx_dma_read16(psx_dma_t* dma, uint32_t offset) {
- switch (offset) {
- case 0x70: return dma->dpcr;
- case 0x74: return dma->dicr & 0xffff;
- case 0x76: return dma->dicr >> 16;
-
- default: {
- printf("Unhandled 16-bit DMA read at offset %08x\n", offset);
-
- return 0x0;
- }
- }
-}
-
-uint8_t psx_dma_read8(psx_dma_t* dma, uint32_t offset) {
- switch (offset) {
- case 0x70: return dma->dpcr;
- case 0x74: return (dma->dicr >> 0) & 0xff;
- case 0x75: return (dma->dicr >> 8) & 0xff;
- case 0x76: return (dma->dicr >> 16) & 0xff;
- case 0x77: return (dma->dicr >> 24) & 0xff;
-
- default: {
- printf("Unhandled 8-bit DMA read at offset %08x\n", offset);
-
- return 0x0;
- }
- }
-}
-
-void dma_write_dicr(psx_dma_t* dma, uint32_t value) {
- uint32_t ack = value & DICR_FLAGS;
- uint32_t flags = dma->dicr & DICR_FLAGS;
-
- flags &= (~ack);
- flags &= DICR_FLAGS;
-
- dma->dicr &= 0x80000000;
- dma->dicr |= flags;
- dma->dicr |= value & 0xffffff;
-}
-
-void psx_dma_write32(psx_dma_t* dma, uint32_t offset, uint32_t value) {
- if (offset < 0x70) {
- int channel = (offset >> 4) & 0x7;
- int reg = (offset >> 2) & 0x3;
-
- CR(channel, reg) = value;
-
- log_error("DMA channel %u register %u write (%08x) %08x", channel, reg, PSX_DMAR_BEGIN + offset, value);
-
- if (reg == 2)
- g_psx_dma_do_table[channel](dma);
- } else {
- switch (offset) {
- case 0x70: log_error("DMA control write %08x", value); dma->dpcr = value; break;
- case 0x74: {
- dma_write_dicr(dma, value);
- } break;
-
- default: {
- log_error("Unhandled 32-bit DMA write at offset %08x (%08x)", offset, value);
- } break;
- }
- }
-}
-
-void psx_dma_write16(psx_dma_t* dma, uint32_t offset, uint16_t value) {
- switch (offset) {
- case 0x74: dma_write_dicr(dma, ((uint32_t)value) << 0);
- case 0x76: dma_write_dicr(dma, ((uint32_t)value) << 16);
- default: {
- log_fatal("Unhandled 16-bit DMA write at offset %08x (%04x)", offset, value);
-
- //exit(1);
- } break;
- }
-}
-
-void psx_dma_write8(psx_dma_t* dma, uint32_t offset, uint8_t value) {
- switch (offset) {
- // DICR 8-bit???
- case 0x74: dma_write_dicr(dma, ((uint32_t)value) << 0); break;
- case 0x75: dma_write_dicr(dma, ((uint32_t)value) << 8); break;
- case 0x76: dma_write_dicr(dma, ((uint32_t)value) << 16); break;
- case 0x77: dma_write_dicr(dma, ((uint32_t)value) << 24); break;
- default: {
- log_fatal("Unhandled 8-bit DMA write at offset %08x (%02x)", offset, value);
-
- //exit(1);
- } break;
- }
-}
-
-const char* g_psx_dma_sync_type_name_table[] = {
- "burst",
- "request",
- "linked",
- "reserved"
-};
-
-void psx_dma_do_mdec_in(psx_dma_t* dma) {
- if (!CHCR_BUSY(mdec_in))
- return;
-
- // printf("dma mdec in size=%04x bcnt=%04x step=%u madr=%08x\n",
- // BCR_SIZE(mdec_in),
- // BCR_BCNT(mdec_in),
- // CHCR_STEP(mdec_in),
- // dma->mdec_in.madr
- // );
-
- size_t size = BCR_SIZE(mdec_in) * BCR_BCNT(mdec_in);
-
- int step = CHCR_STEP(mdec_in) ? -4 : 4;
-
- for (int i = 0; i < size; i++) {
- uint32_t data = psx_bus_read32(dma->bus, dma->mdec_in.madr);
-
- psx_bus_write32(dma->bus, 0x1f801820, data);
-
- dma->mdec_in.madr += step;
- }
-
- dma->mdec_in_irq_delay = size;
-
- dma->mdec_in.chcr = 0;
- dma->mdec_in.bcr = 0;
-}
-
-void psx_dma_do_mdec_out(psx_dma_t* dma) {
- if (!CHCR_BUSY(mdec_out))
- return;
-
- // printf("dma mdec out size=%04x bcnt=%04x step=%u madr=%08x\n",
- // BCR_SIZE(mdec_out),
- // BCR_BCNT(mdec_out),
- // CHCR_STEP(mdec_out),
- // dma->mdec_out.madr
- // );
-
- // printf("mdec out transfer\n");
-
- size_t size = BCR_SIZE(mdec_out) * BCR_BCNT(mdec_out);
-
- for (int i = 0; i < size; i++) {
- uint32_t data = psx_bus_read32(dma->bus, 0x1f801820);
-
- psx_bus_write32(dma->bus, dma->mdec_out.madr, data);
-
- dma->mdec_out.madr += CHCR_STEP(mdec_out) ? -4 : 4;
- }
-
- dma->mdec_out_irq_delay = size;
-
- dma->mdec_out.chcr = 0;
- dma->mdec_out.bcr = 0;
-}
-
-void psx_dma_do_gpu_linked(psx_dma_t* dma) {
- uint32_t hdr = psx_bus_read32(dma->bus, dma->gpu.madr);
- uint32_t size = hdr >> 24;
- uint32_t addr = dma->gpu.madr;
-
- int timeout = 16384;
-
- while (timeout--) {
- while (size--) {
- addr = (addr + (CHCR_STEP(gpu) ? -4 : 4)) & 0x1ffffc;
-
- // Get command from linked list
- uint32_t cmd = psx_bus_read32(dma->bus, addr);
-
- // Write to GP0
- psx_bus_write32(dma->bus, 0x1f801810, cmd);
-
- dma->gpu_irq_delay++;
- }
-
- addr = hdr & 0xffffff;
-
- if (addr == 0xffffff)
- break;
-
- hdr = psx_bus_read32(dma->bus, addr);
- size = hdr >> 24;
- }
-}
-
-void psx_dma_do_gpu_request(psx_dma_t* dma) {
- if (!CHCR_BUSY(gpu))
- return;
-
- uint32_t size = BCR_SIZE(gpu) * BCR_BCNT(gpu);
-
- if (CHCR_TDIR(gpu)) {
- for (int i = 0; i < size; i++) {
- uint32_t data = psx_bus_read32(dma->bus, dma->gpu.madr);
-
- psx_bus_write32(dma->bus, 0x1f801810, data);
-
- dma->gpu.madr += CHCR_STEP(gpu) ? -4 : 4;
- }
- } else {
- for (int i = 0; i < size; i++) {
- uint32_t data = psx_bus_read32(dma->bus, 0x1f801810);
-
- psx_bus_write32(dma->bus, dma->gpu.madr, data);
-
- dma->gpu.madr += CHCR_STEP(gpu) ? -4 : 4;
- }
- }
-
- dma->gpu_irq_delay = size;
-}
-
+#include "dev/dma.h"
+#include "log.h"
+
+#include "p9.h"
+
+psx_dma_t* psx_dma_create(void) {+ return (psx_dma_t*)malloc(sizeof(psx_dma_t));
+}
+
+const uint32_t g_psx_dma_ctrl_hw_1_table[] = {+ 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000,
+ 0x00000002
+};
+
+const uint32_t g_psx_dma_ctrl_hw_0_table[] = {+ 0x71770703, 0x71770703, 0x71770703,
+ 0x71770703, 0x71770703, 0x71770703,
+ 0x50000002
+};
+
+const psx_dma_do_fn_t g_psx_dma_do_table[] = {+ psx_dma_do_mdec_in,
+ psx_dma_do_mdec_out,
+ psx_dma_do_gpu,
+ psx_dma_do_cdrom,
+ psx_dma_do_spu,
+ psx_dma_do_pio,
+ psx_dma_do_otc
+};
+
+#define CR(c, r) *((&dma->mdec_in.madr) + (c * 3) + r)
+
+void psx_dma_init(psx_dma_t* dma, psx_bus_t* bus, psx_ic_t* ic) {+ memset(dma, 0, sizeof(psx_dma_t));
+
+ dma->io_base = PSX_DMAR_BEGIN;
+ dma->io_size = PSX_DMAR_SIZE;
+
+ dma->bus = bus;
+ dma->ic = ic;
+
+ dma->dpcr = 0x07654321;
+}
+
+uint32_t psx_dma_read32(psx_dma_t* dma, uint32_t offset) {+ if (offset < 0x70) {+ int channel = (offset >> 4) & 0x7;
+ int reg = (offset >> 2) & 0x3;
+ uint32_t cr = CR(channel, reg);
+
+ if (reg == 2) {+ cr |= g_psx_dma_ctrl_hw_1_table[channel];
+ cr &= g_psx_dma_ctrl_hw_0_table[channel];
+ }
+
+ log_error("DMA channel %u register %u (%08x) read %08x", channel, reg, PSX_DMAR_BEGIN + offset, cr);+
+ return cr;
+ } else {+ switch (offset) {+ case 0x70: log_error("DMA control read %08x", dma->dpcr); return dma->dpcr;+ case 0x74: log_error("DMA irqc read %08x", dma->dicr); return dma->dicr;+
+ default: {+ log_error("Unhandled 32-bit DMA read at offset %08x", offset);+
+ return 0x0;
+ }
+ }
+ }
+}
+
+uint16_t psx_dma_read16(psx_dma_t* dma, uint32_t offset) {+ switch (offset) {+ case 0x70: return dma->dpcr;
+ case 0x74: return dma->dicr & 0xffff;
+ case 0x76: return dma->dicr >> 16;
+
+ default: {+ printf("Unhandled 16-bit DMA read at offset %08x\n", offset);+
+ return 0x0;
+ }
+ }
+}
+
+uint8_t psx_dma_read8(psx_dma_t* dma, uint32_t offset) {+ switch (offset) {+ case 0x70: return dma->dpcr;
+ case 0x74: return (dma->dicr >> 0) & 0xff;
+ case 0x75: return (dma->dicr >> 8) & 0xff;
+ case 0x76: return (dma->dicr >> 16) & 0xff;
+ case 0x77: return (dma->dicr >> 24) & 0xff;
+
+ default: {+ printf("Unhandled 8-bit DMA read at offset %08x\n", offset);+
+ return 0x0;
+ }
+ }
+}
+
+void dma_write_dicr(psx_dma_t* dma, uint32_t value) {+ uint32_t ack = value & DICR_FLAGS;
+ uint32_t flags = dma->dicr & DICR_FLAGS;
+
+ flags &= (~ack);
+ flags &= DICR_FLAGS;
+
+ dma->dicr &= 0x80000000;
+ dma->dicr |= flags;
+ dma->dicr |= value & 0xffffff;
+}
+
+void psx_dma_write32(psx_dma_t* dma, uint32_t offset, uint32_t value) {+ if (offset < 0x70) {+ int channel = (offset >> 4) & 0x7;
+ int reg = (offset >> 2) & 0x3;
+
+ CR(channel, reg) = value;
+
+ log_error("DMA channel %u register %u write (%08x) %08x", channel, reg, PSX_DMAR_BEGIN + offset, value);+
+ if (reg == 2)
+ g_psx_dma_do_table[channel](dma);
+ } else {+ switch (offset) {+ case 0x70: log_error("DMA control write %08x", value); dma->dpcr = value; break;+ case 0x74: {+ dma_write_dicr(dma, value);
+ } break;
+
+ default: {+ log_error("Unhandled 32-bit DMA write at offset %08x (%08x)", offset, value);+ } break;
+ }
+ }
+}
+
+void psx_dma_write16(psx_dma_t* dma, uint32_t offset, uint16_t value) {+ switch (offset) {+ case 0x74: dma_write_dicr(dma, ((uint32_t)value) << 0);
+ case 0x76: dma_write_dicr(dma, ((uint32_t)value) << 16);
+ default: {+ log_fatal("Unhandled 16-bit DMA write at offset %08x (%04x)", offset, value);+
+ //exit(1);
+ } break;
+ }
+}
+
+void psx_dma_write8(psx_dma_t* dma, uint32_t offset, uint8_t value) {+ switch (offset) {+ // DICR 8-bit???
+ case 0x74: dma_write_dicr(dma, ((uint32_t)value) << 0); break;
+ case 0x75: dma_write_dicr(dma, ((uint32_t)value) << 8); break;
+ case 0x76: dma_write_dicr(dma, ((uint32_t)value) << 16); break;
+ case 0x77: dma_write_dicr(dma, ((uint32_t)value) << 24); break;
+ default: {+ log_fatal("Unhandled 8-bit DMA write at offset %08x (%02x)", offset, value);+
+ //exit(1);
+ } break;
+ }
+}
+
+const char* g_psx_dma_sync_type_name_table[] = {+ "burst",
+ "request",
+ "linked",
+ "reserved"
+};
+
+void psx_dma_do_mdec_in(psx_dma_t* dma) {+ if (!CHCR_BUSY(mdec_in))
+ return;
+
+ // printf("dma mdec in size=%04x bcnt=%04x step=%u madr=%08x\n",+ // BCR_SIZE(mdec_in),
+ // BCR_BCNT(mdec_in),
+ // CHCR_STEP(mdec_in),
+ // dma->mdec_in.madr
+ // );
+
+ size_t size = BCR_SIZE(mdec_in) * BCR_BCNT(mdec_in);
+
+ int step = CHCR_STEP(mdec_in) ? -4 : 4;
+
+ for (int i = 0; i < size; i++) {+ uint32_t data = psx_bus_read32(dma->bus, dma->mdec_in.madr);
+
+ psx_bus_write32(dma->bus, 0x1f801820, data);
+
+ dma->mdec_in.madr += step;
+ }
+
+ dma->mdec_in_irq_delay = size;
+
+ dma->mdec_in.chcr = 0;
+ dma->mdec_in.bcr = 0;
+}
+
+void psx_dma_do_mdec_out(psx_dma_t* dma) {+ if (!CHCR_BUSY(mdec_out))
+ return;
+
+ // printf("dma mdec out size=%04x bcnt=%04x step=%u madr=%08x\n",+ // BCR_SIZE(mdec_out),
+ // BCR_BCNT(mdec_out),
+ // CHCR_STEP(mdec_out),
+ // dma->mdec_out.madr
+ // );
+
+ // printf("mdec out transfer\n");+
+ size_t size = BCR_SIZE(mdec_out) * BCR_BCNT(mdec_out);
+
+ for (int i = 0; i < size; i++) {+ uint32_t data = psx_bus_read32(dma->bus, 0x1f801820);
+
+ psx_bus_write32(dma->bus, dma->mdec_out.madr, data);
+
+ dma->mdec_out.madr += CHCR_STEP(mdec_out) ? -4 : 4;
+ }
+
+ dma->mdec_out_irq_delay = size;
+
+ dma->mdec_out.chcr = 0;
+ dma->mdec_out.bcr = 0;
+}
+
+void psx_dma_do_gpu_linked(psx_dma_t* dma) {+ uint32_t hdr = psx_bus_read32(dma->bus, dma->gpu.madr);
+ uint32_t size = hdr >> 24;
+ uint32_t addr = dma->gpu.madr;
+
+ int timeout = 16384;
+
+ while (timeout--) {+ while (size--) {+ addr = (addr + (CHCR_STEP(gpu) ? -4 : 4)) & 0x1ffffc;
+
+ // Get command from linked list
+ uint32_t cmd = psx_bus_read32(dma->bus, addr);
+
+ // Write to GP0
+ psx_bus_write32(dma->bus, 0x1f801810, cmd);
+
+ dma->gpu_irq_delay++;
+ }
+
+ addr = hdr & 0xffffff;
+
+ if (addr == 0xffffff)
+ break;
+
+ hdr = psx_bus_read32(dma->bus, addr);
+ size = hdr >> 24;
+ }
+}
+
+void psx_dma_do_gpu_request(psx_dma_t* dma) {+ if (!CHCR_BUSY(gpu))
+ return;
+
+ uint32_t size = BCR_SIZE(gpu) * BCR_BCNT(gpu);
+
+ if (CHCR_TDIR(gpu)) {+ for (int i = 0; i < size; i++) {+ uint32_t data = psx_bus_read32(dma->bus, dma->gpu.madr);
+
+ psx_bus_write32(dma->bus, 0x1f801810, data);
+
+ dma->gpu.madr += CHCR_STEP(gpu) ? -4 : 4;
+ }
+ } else {+ for (int i = 0; i < size; i++) {+ uint32_t data = psx_bus_read32(dma->bus, 0x1f801810);
+
+ psx_bus_write32(dma->bus, dma->gpu.madr, data);
+
+ dma->gpu.madr += CHCR_STEP(gpu) ? -4 : 4;
+ }
+ }
+
+ dma->gpu_irq_delay = size;
+}
+
void psx_dma_do_gpu_burst(psx_dma_t* dma) {USED(dma);
printf("GPU DMA burst sync mode unimplemented\n");@@ -293,249 +293,249 @@
exit(1);
}
-
-psx_dma_do_fn_t g_psx_dma_gpu_table[] = {
- psx_dma_do_gpu_burst,
- psx_dma_do_gpu_request,
- psx_dma_do_gpu_linked
-};
-
-#define TEST_SET_IRQ_FLAG()
-
-void psx_dma_do_gpu(psx_dma_t* dma) {
- if (!CHCR_BUSY(gpu))
- return;
-
- // log_error("GPU DMA transfer: madr=%08x, dir=%s, sync=%s (%u), step=%s, size=%x",
- // dma->gpu.madr,
- // CHCR_TDIR(gpu) ? "to device" : "to RAM",
- // g_psx_dma_sync_type_name_table[CHCR_SYNC(gpu)], CHCR_SYNC(gpu),
- // CHCR_STEP(gpu) ? "decrementing" : "incrementing",
- // BCR_SIZE(gpu)
- // );
-
- g_psx_dma_gpu_table[CHCR_SYNC(gpu)](dma);
-
- // Clear BCR and CHCR trigger and busy bits
- dma->gpu.chcr &= ~(CHCR_BUSY_MASK | CHCR_TRIG_MASK);
- dma->gpu.bcr = 0;
-}
-
-void psx_dma_do_cdrom(psx_dma_t* dma) {
- if (!CHCR_BUSY(cdrom))
- return;
-
- // printf("CDROM DMA transfer: madr=%08x, dir=%s, sync=%s (%u), step=%s, size=%x\n",
- // dma->cdrom.madr,
- // CHCR_TDIR(cdrom) ? "to device" : "to RAM",
- // g_psx_dma_sync_type_name_table[CHCR_SYNC(cdrom)], CHCR_SYNC(cdrom),
- // CHCR_STEP(cdrom) ? "decrementing" : "incrementing",
- // BCR_SIZE(cdrom)
- // );
-
- // printf("DICR: force=%u, en=%02x, irqen=%u, flags=%02x\n",
- // (dma->dicr >> 15) & 1,
- // (dma->dicr >> 16) & 0x7f,
- // (dma->dicr >> 23) & 1,
- // (dma->dicr >> 24) & 0x7f
- // );
-
- uint32_t size = BCR_SIZE(cdrom);
-
- if (!size)
- size = 0x10000;
-
- dma->cdrom_irq_delay = 1;
-
- if (!CHCR_TDIR(cdrom)) {
- for (int i = 0; i < size; i++) {
- uint32_t data = 0;
-
- data |= psx_bus_read8(dma->bus, 0x1f801802) << 0;
- data |= psx_bus_read8(dma->bus, 0x1f801802) << 8;
- data |= psx_bus_read8(dma->bus, 0x1f801802) << 16;
- data |= psx_bus_read8(dma->bus, 0x1f801802) << 24;
-
- psx_bus_write32(dma->bus, dma->cdrom.madr, data);
-
- dma->cdrom.madr += CHCR_STEP(cdrom) ? -4 : 4;
- }
- } else {
- log_fatal("Invalid CDROM DMA transfer direction");
- }
-
- // Clear BCR and CHCR trigger and busy bits
- dma->cdrom.chcr = 0;
- dma->cdrom.bcr = 0;
-}
-
-void psx_dma_do_spu(psx_dma_t* dma) {
- if (!CHCR_BUSY(spu))
- return;
-
- // log_set_quiet(0);
- // log_fatal("SPU DMA transfer: madr=%08x, dir=%s, sync=%s (%u), step=%s, size=%x, blocks=%u",
- // dma->spu.madr,
- // CHCR_TDIR(spu) ? "to device" : "to RAM",
- // g_psx_dma_sync_type_name_table[CHCR_SYNC(spu)], CHCR_SYNC(spu),
- // CHCR_STEP(spu) ? "decrementing" : "incrementing",
- // BCR_SIZE(spu), BCR_BCNT(spu)
- // );
-
- // log_fatal("DICR: force=%u, en=%02x, irqen=%u, flags=%02x",
- // (dma->dicr >> 15) & 1,
- // (dma->dicr >> 16) & 0x7f,
- // (dma->dicr >> 23) & 1,
- // (dma->dicr >> 24) & 0x7f
- // );
- // log_set_quiet(1);
-
- uint32_t size = BCR_SIZE(spu);
- uint32_t blocks = BCR_BCNT(spu);
-
- if (!size) {
- log_fatal("0 sized SPU DMA");
-
- // exit(1);
- }
-
- dma->spu_irq_delay = 32;
-
- if (CHCR_TDIR(spu)) {
- for (int j = 0; j < blocks; j++) {
- for (int i = 0; i < size; i++) {
- uint32_t data = psx_bus_read32(dma->bus, dma->spu.madr);
-
- psx_bus_write16(dma->bus, 0x1f801da8, data & 0xffff);
- psx_bus_write16(dma->bus, 0x1f801da8, data >> 16);
-
- dma->spu.madr += CHCR_STEP(spu) ? -4 : 4;
- }
- }
- } else {
- for (int j = 0; j < blocks; j++) {
- for (int i = 0; i < size; i++) {
- uint32_t data;
-
- data = psx_bus_read16(dma->bus, 0x1f801da8);
- data |= psx_bus_read16(dma->bus, 0x1f801da8) << 16;
-
- psx_bus_write32(dma->bus, dma->spu.madr, data);
-
- dma->spu.madr += CHCR_STEP(spu) ? -4 : 4;
- }
- }
-
- }
-
- // Clear BCR and CHCR trigger and busy bits
- dma->spu.chcr = 0;
- dma->spu.bcr = 0;
-}
-
+
+psx_dma_do_fn_t g_psx_dma_gpu_table[] = {+ psx_dma_do_gpu_burst,
+ psx_dma_do_gpu_request,
+ psx_dma_do_gpu_linked
+};
+
+#define TEST_SET_IRQ_FLAG()
+
+void psx_dma_do_gpu(psx_dma_t* dma) {+ if (!CHCR_BUSY(gpu))
+ return;
+
+ // log_error("GPU DMA transfer: madr=%08x, dir=%s, sync=%s (%u), step=%s, size=%x",+ // dma->gpu.madr,
+ // CHCR_TDIR(gpu) ? "to device" : "to RAM",
+ // g_psx_dma_sync_type_name_table[CHCR_SYNC(gpu)], CHCR_SYNC(gpu),
+ // CHCR_STEP(gpu) ? "decrementing" : "incrementing",
+ // BCR_SIZE(gpu)
+ // );
+
+ g_psx_dma_gpu_table[CHCR_SYNC(gpu)](dma);
+
+ // Clear BCR and CHCR trigger and busy bits
+ dma->gpu.chcr &= ~(CHCR_BUSY_MASK | CHCR_TRIG_MASK);
+ dma->gpu.bcr = 0;
+}
+
+void psx_dma_do_cdrom(psx_dma_t* dma) {+ if (!CHCR_BUSY(cdrom))
+ return;
+
+ // printf("CDROM DMA transfer: madr=%08x, dir=%s, sync=%s (%u), step=%s, size=%x\n",+ // dma->cdrom.madr,
+ // CHCR_TDIR(cdrom) ? "to device" : "to RAM",
+ // g_psx_dma_sync_type_name_table[CHCR_SYNC(cdrom)], CHCR_SYNC(cdrom),
+ // CHCR_STEP(cdrom) ? "decrementing" : "incrementing",
+ // BCR_SIZE(cdrom)
+ // );
+
+ // printf("DICR: force=%u, en=%02x, irqen=%u, flags=%02x\n",+ // (dma->dicr >> 15) & 1,
+ // (dma->dicr >> 16) & 0x7f,
+ // (dma->dicr >> 23) & 1,
+ // (dma->dicr >> 24) & 0x7f
+ // );
+
+ uint32_t size = BCR_SIZE(cdrom);
+
+ if (!size)
+ size = 0x10000;
+
+ dma->cdrom_irq_delay = 1;
+
+ if (!CHCR_TDIR(cdrom)) {+ for (int i = 0; i < size; i++) {+ uint32_t data = 0;
+
+ data |= psx_bus_read8(dma->bus, 0x1f801802) << 0;
+ data |= psx_bus_read8(dma->bus, 0x1f801802) << 8;
+ data |= psx_bus_read8(dma->bus, 0x1f801802) << 16;
+ data |= psx_bus_read8(dma->bus, 0x1f801802) << 24;
+
+ psx_bus_write32(dma->bus, dma->cdrom.madr, data);
+
+ dma->cdrom.madr += CHCR_STEP(cdrom) ? -4 : 4;
+ }
+ } else {+ log_fatal("Invalid CDROM DMA transfer direction");+ }
+
+ // Clear BCR and CHCR trigger and busy bits
+ dma->cdrom.chcr = 0;
+ dma->cdrom.bcr = 0;
+}
+
+void psx_dma_do_spu(psx_dma_t* dma) {+ if (!CHCR_BUSY(spu))
+ return;
+
+ // log_set_quiet(0);
+ // log_fatal("SPU DMA transfer: madr=%08x, dir=%s, sync=%s (%u), step=%s, size=%x, blocks=%u",+ // dma->spu.madr,
+ // CHCR_TDIR(spu) ? "to device" : "to RAM",
+ // g_psx_dma_sync_type_name_table[CHCR_SYNC(spu)], CHCR_SYNC(spu),
+ // CHCR_STEP(spu) ? "decrementing" : "incrementing",
+ // BCR_SIZE(spu), BCR_BCNT(spu)
+ // );
+
+ // log_fatal("DICR: force=%u, en=%02x, irqen=%u, flags=%02x",+ // (dma->dicr >> 15) & 1,
+ // (dma->dicr >> 16) & 0x7f,
+ // (dma->dicr >> 23) & 1,
+ // (dma->dicr >> 24) & 0x7f
+ // );
+ // log_set_quiet(1);
+
+ uint32_t size = BCR_SIZE(spu);
+ uint32_t blocks = BCR_BCNT(spu);
+
+ if (!size) {+ log_fatal("0 sized SPU DMA");+
+ // exit(1);
+ }
+
+ dma->spu_irq_delay = 32;
+
+ if (CHCR_TDIR(spu)) {+ for (int j = 0; j < blocks; j++) {+ for (int i = 0; i < size; i++) {+ uint32_t data = psx_bus_read32(dma->bus, dma->spu.madr);
+
+ psx_bus_write16(dma->bus, 0x1f801da8, data & 0xffff);
+ psx_bus_write16(dma->bus, 0x1f801da8, data >> 16);
+
+ dma->spu.madr += CHCR_STEP(spu) ? -4 : 4;
+ }
+ }
+ } else {+ for (int j = 0; j < blocks; j++) {+ for (int i = 0; i < size; i++) {+ uint32_t data;
+
+ data = psx_bus_read16(dma->bus, 0x1f801da8);
+ data |= psx_bus_read16(dma->bus, 0x1f801da8) << 16;
+
+ psx_bus_write32(dma->bus, dma->spu.madr, data);
+
+ dma->spu.madr += CHCR_STEP(spu) ? -4 : 4;
+ }
+ }
+
+ }
+
+ // Clear BCR and CHCR trigger and busy bits
+ dma->spu.chcr = 0;
+ dma->spu.bcr = 0;
+}
+
void psx_dma_do_pio(psx_dma_t* dma) {USED(dma);
log_fatal("PIO DMA channel unimplemented");}
-
-void psx_dma_do_otc(psx_dma_t* dma) {
- if ((!(dma->dpcr & DPCR_DMA6EN)) || (!CHCR_TRIG(otc)) || (!CHCR_BUSY(otc)))
- return;
-
- // log_fatal("OTC DMA transfer: madr=%08x, dir=%s, sync=%s, step=%s, size=%x",
- // dma->otc.madr,
- // CHCR_TDIR(otc) ? "to device" : "to RAM",
- // CHCR_SYNC(otc) ? "other" : "burst",
- // CHCR_STEP(otc) ? "decrementing" : "incrementing",
- // BCR_SIZE(otc)
- // );
-
- uint32_t size = BCR_SIZE(otc);
-
- if (!size)
- size = 0x10000;
-
- for (int i = size; i > 0; i--) {
- uint32_t addr = (i != 1) ? (dma->otc.madr - 4) : 0xffffff;
-
- psx_bus_write32(dma->bus, dma->otc.madr, addr & 0xffffff);
-
- dma->otc.madr -= 4;
- }
-
- dma->otc_irq_delay = size;
-
- // Clear BCR and CHCR trigger and busy bits
- dma->otc.chcr = 0;
- //dma->otc.chcr &= ~(CHCR_BUSY_MASK | CHCR_TRIG_MASK);
- dma->otc.bcr = 0;
-}
-
+
+void psx_dma_do_otc(psx_dma_t* dma) {+ if ((!(dma->dpcr & DPCR_DMA6EN)) || (!CHCR_TRIG(otc)) || (!CHCR_BUSY(otc)))
+ return;
+
+ // log_fatal("OTC DMA transfer: madr=%08x, dir=%s, sync=%s, step=%s, size=%x",+ // dma->otc.madr,
+ // CHCR_TDIR(otc) ? "to device" : "to RAM",
+ // CHCR_SYNC(otc) ? "other" : "burst",
+ // CHCR_STEP(otc) ? "decrementing" : "incrementing",
+ // BCR_SIZE(otc)
+ // );
+
+ uint32_t size = BCR_SIZE(otc);
+
+ if (!size)
+ size = 0x10000;
+
+ for (int i = size; i > 0; i--) {+ uint32_t addr = (i != 1) ? (dma->otc.madr - 4) : 0xffffff;
+
+ psx_bus_write32(dma->bus, dma->otc.madr, addr & 0xffffff);
+
+ dma->otc.madr -= 4;
+ }
+
+ dma->otc_irq_delay = size;
+
+ // Clear BCR and CHCR trigger and busy bits
+ dma->otc.chcr = 0;
+ //dma->otc.chcr &= ~(CHCR_BUSY_MASK | CHCR_TRIG_MASK);
+ dma->otc.bcr = 0;
+}
+
void psx_dma_update(psx_dma_t* dma, int cyc) {USED(cyc);
if (dma->cdrom_irq_delay) {- dma->cdrom_irq_delay = 0;
-
- if ((dma->dicr & DICR_DMA3EN) && !dma->cdrom_irq_delay)
- dma->dicr |= DICR_DMA3FL;
- }
-
- if (dma->spu_irq_delay) {
- dma->spu_irq_delay = 0;
-
- if (dma->spu_irq_delay <= 0)
- if (dma->dicr & DICR_DMA4EN)
- dma->dicr |= DICR_DMA4FL;
- }
-
- if (dma->gpu_irq_delay) {
- dma->gpu_irq_delay = 0;
-
- if (!dma->gpu_irq_delay)
- if (dma->dicr & DICR_DMA2EN)
- dma->dicr |= DICR_DMA2FL;
- }
-
- if (dma->otc_irq_delay) {
- dma->otc_irq_delay = 0;
-
- if (!dma->otc_irq_delay)
- if (dma->dicr & DICR_DMA6EN)
- dma->dicr |= DICR_DMA6FL;
- }
-
- if (dma->mdec_in_irq_delay) {
- --dma->mdec_in_irq_delay;
-
- if (!dma->mdec_in_irq_delay)
- if (dma->dicr & DICR_DMA0EN)
- dma->dicr |= DICR_DMA0FL;
- }
-
- if (dma->mdec_out_irq_delay) {
- --dma->mdec_out_irq_delay;
-
- if (!dma->mdec_out_irq_delay)
- if (dma->dicr & DICR_DMA1EN)
- dma->dicr |= DICR_DMA1FL;
- }
-
- int prev_irq_signal = (dma->dicr & DICR_IRQSI) != 0;
- int irq_on_flags = (dma->dicr & DICR_IRQEN) != 0;
- int force_irq = (dma->dicr & DICR_FORCE) != 0;
- int irq = (dma->dicr & DICR_FLAGS) != 0;
-
- int irq_signal = force_irq || ((irq & irq_on_flags) != 0);
-
- if (irq_signal && !prev_irq_signal)
- psx_ic_irq(dma->ic, IC_DMA);
-
- dma->dicr &= ~DICR_IRQSI;
- dma->dicr |= irq_signal << 31;
-}
-
-void psx_dma_destroy(psx_dma_t* dma) {
- free(dma);
-}
-
+ dma->cdrom_irq_delay = 0;
+
+ if ((dma->dicr & DICR_DMA3EN) && !dma->cdrom_irq_delay)
+ dma->dicr |= DICR_DMA3FL;
+ }
+
+ if (dma->spu_irq_delay) {+ dma->spu_irq_delay = 0;
+
+ if (dma->spu_irq_delay <= 0)
+ if (dma->dicr & DICR_DMA4EN)
+ dma->dicr |= DICR_DMA4FL;
+ }
+
+ if (dma->gpu_irq_delay) {+ dma->gpu_irq_delay = 0;
+
+ if (!dma->gpu_irq_delay)
+ if (dma->dicr & DICR_DMA2EN)
+ dma->dicr |= DICR_DMA2FL;
+ }
+
+ if (dma->otc_irq_delay) {+ dma->otc_irq_delay = 0;
+
+ if (!dma->otc_irq_delay)
+ if (dma->dicr & DICR_DMA6EN)
+ dma->dicr |= DICR_DMA6FL;
+ }
+
+ if (dma->mdec_in_irq_delay) {+ --dma->mdec_in_irq_delay;
+
+ if (!dma->mdec_in_irq_delay)
+ if (dma->dicr & DICR_DMA0EN)
+ dma->dicr |= DICR_DMA0FL;
+ }
+
+ if (dma->mdec_out_irq_delay) {+ --dma->mdec_out_irq_delay;
+
+ if (!dma->mdec_out_irq_delay)
+ if (dma->dicr & DICR_DMA1EN)
+ dma->dicr |= DICR_DMA1FL;
+ }
+
+ int prev_irq_signal = (dma->dicr & DICR_IRQSI) != 0;
+ int irq_on_flags = (dma->dicr & DICR_IRQEN) != 0;
+ int force_irq = (dma->dicr & DICR_FORCE) != 0;
+ int irq = (dma->dicr & DICR_FLAGS) != 0;
+
+ int irq_signal = force_irq || ((irq & irq_on_flags) != 0);
+
+ if (irq_signal && !prev_irq_signal)
+ psx_ic_irq(dma->ic, IC_DMA);
+
+ dma->dicr &= ~DICR_IRQSI;
+ dma->dicr |= irq_signal << 31;
+}
+
+void psx_dma_destroy(psx_dma_t* dma) {+ free(dma);
+}
+
#undef CR
--- a/psx/dev/dma.h
+++ b/psx/dev/dma.h
@@ -1,173 +1,173 @@
#ifndef PSX_DEV_DMA_H
-#define PSX_DEV_DMA_H
-
-#include "p9.h"
-
-#define PSX_DMAR_BEGIN 0x1f801080
-#define PSX_DMAR_SIZE 0x80
-#define PSX_DMAR_END 0x1f8010ff
-
-#include "bus.h"
-#include "dev/ic.h"
-
-typedef struct {
- uint32_t madr;
- uint32_t bcr;
- uint32_t chcr;
-} dma_channel_t;
-
+#define PSX_DEV_DMA_H
+
+#include "p9.h"
+
+#define PSX_DMAR_BEGIN 0x1f801080
+#define PSX_DMAR_SIZE 0x80
+#define PSX_DMAR_END 0x1f8010ff
+
+#include "bus.h"
+#include "dev/ic.h"
+
+typedef struct {+ uint32_t madr;
+ uint32_t bcr;
+ uint32_t chcr;
+} dma_channel_t;
+
struct psx_dma_t {uint32_t bus_delay;
uint32_t io_base, io_size;
-
- psx_bus_t* bus;
- psx_ic_t* ic;
-
- dma_channel_t mdec_in;
- dma_channel_t mdec_out;
- dma_channel_t gpu;
- dma_channel_t cdrom;
- dma_channel_t spu;
- dma_channel_t pio;
- dma_channel_t otc;
-
- int mdec_in_irq_delay;
- int mdec_out_irq_delay;
- int cdrom_irq_delay;
- int spu_irq_delay;
- int gpu_irq_delay;
- int otc_irq_delay;
-
+
+ psx_bus_t* bus;
+ psx_ic_t* ic;
+
+ dma_channel_t mdec_in;
+ dma_channel_t mdec_out;
+ dma_channel_t gpu;
+ dma_channel_t cdrom;
+ dma_channel_t spu;
+ dma_channel_t pio;
+ dma_channel_t otc;
+
+ int mdec_in_irq_delay;
+ int mdec_out_irq_delay;
+ int cdrom_irq_delay;
+ int spu_irq_delay;
+ int gpu_irq_delay;
+ int otc_irq_delay;
+
uint32_t dpcr;
uint32_t dicr;
};
typedef struct psx_dma_t psx_dma_t;
-
-psx_dma_t* psx_dma_create(void);
-void psx_dma_init(psx_dma_t*, psx_bus_t*, psx_ic_t*);
-void psx_dma_do_mdec_in(psx_dma_t*);
-void psx_dma_do_mdec_out(psx_dma_t*);
-void psx_dma_do_gpu(psx_dma_t*);
-void psx_dma_do_cdrom(psx_dma_t*);
-void psx_dma_do_spu(psx_dma_t*);
-void psx_dma_do_pio(psx_dma_t*);
-void psx_dma_do_otc(psx_dma_t*);
-void psx_dma_perform(psx_dma_t*, int);
-uint32_t psx_dma_read32(psx_dma_t*, uint32_t);
-uint16_t psx_dma_read16(psx_dma_t*, uint32_t);
-uint8_t psx_dma_read8(psx_dma_t*, uint32_t);
-void psx_dma_write32(psx_dma_t*, uint32_t, uint32_t);
-void psx_dma_write16(psx_dma_t*, uint32_t, uint16_t);
-void psx_dma_write8(psx_dma_t*, uint32_t, uint8_t);
-void psx_dma_destroy(psx_dma_t*);
-void psx_dma_update(psx_dma_t*, int);
-
-typedef void (*psx_dma_do_fn_t)(psx_dma_t*);
-
-/*
- 0-2 DMA0, MDECin Priority (0..7; 0=Highest, 7=Lowest)
- 3 DMA0, MDECin Master Enable (0=Disable, 1=Enable)
- 4-6 DMA1, MDECout Priority (0..7; 0=Highest, 7=Lowest)
- 7 DMA1, MDECout Master Enable (0=Disable, 1=Enable)
- 8-10 DMA2, GPU Priority (0..7; 0=Highest, 7=Lowest)
- 11 DMA2, GPU Master Enable (0=Disable, 1=Enable)
- 12-14 DMA3, CDROM Priority (0..7; 0=Highest, 7=Lowest)
- 15 DMA3, CDROM Master Enable (0=Disable, 1=Enable)
- 16-18 DMA4, SPU Priority (0..7; 0=Highest, 7=Lowest)
- 19 DMA4, SPU Master Enable (0=Disable, 1=Enable)
- 20-22 DMA5, PIO Priority (0..7; 0=Highest, 7=Lowest)
- 23 DMA5, PIO Master Enable (0=Disable, 1=Enable)
- 24-26 DMA6, OTC Priority (0..7; 0=Highest, 7=Lowest)
- 27 DMA6, OTC Master Enable (0=Disable, 1=Enable)
- 28-30 Unknown, Priority Offset or so? (R/W)
- 31 Unknown, no effect? (R/W)
-*/
-
-#define DPCR_DMA0EN 0x00000008
-#define DPCR_DMA1EN 0x00000080
-#define DPCR_DMA2EN 0x00000800
-#define DPCR_DMA3EN 0x00008000
-#define DPCR_DMA4EN 0x00080000
-#define DPCR_DMA5EN 0x00800000
-#define DPCR_DMA6EN 0x08000000
-
-/*
- 0 Transfer Direction (0=To Main RAM, 1=From Main RAM)
- 1 Memory Address Step (0=Forward;+4, 1=Backward;-4)
- 2-7 Not used (always zero)
- 8 Chopping Enable (0=Normal, 1=Chopping; run CPU during DMA gaps)
- 9-10 SyncMode, Transfer Synchronisation/Mode (0-3):
- 0 Start immediately and transfer all at once (used for CDROM, OTC)
- 1 Sync blocks to DMA requests (used for MDEC, SPU, and GPU-data)
- 2 Linked-List mode (used for GPU-command-lists)
- 3 Reserved (not used)
- 11-15 Not used (always zero)
- 16-18 Chopping DMA Window Size (1 SHL N words)
- 19 Not used (always zero)
- 20-22 Chopping CPU Window Size (1 SHL N clks)
- 23 Not used (always zero)
- 24 Start/Busy (0=Stopped/Completed, 1=Start/Enable/Busy)
- 25-27 Not used (always zero)
- 28 Start/Trigger (0=Normal, 1=Manual Start; use for SyncMode=0)
- 29 Unknown (R/W) Pause? (0=No, 1=Pause?) (For SyncMode=0 only?)
- 30 Unknown (R/W)
- 31 Not used (always zero)
-*/
-
-#define CHCR_TDIR_MASK 0x00000001
-#define CHCR_STEP_MASK 0x00000002
-#define CHCR_CPEN_MASK 0x00000100
-#define CHCR_SYNC_MASK 0x00000600
-#define CHCR_CDWS_MASK 0x00070000
-#define CHCR_CCWS_MASK 0x00380000
-#define CHCR_BUSY_MASK 0x01000000
-#define CHCR_TRIG_MASK 0x10000000
-
-#define SYNC_SHIF 9
-#define CDWS_SHIF 16
-#define CCWS_SHIF 19
-
-#define CHCR_TDIR(c) (dma->c.chcr & CHCR_TDIR_MASK)
-#define CHCR_STEP(c) (dma->c.chcr & CHCR_STEP_MASK)
-#define CHCR_CPEN(c) (dma->c.chcr & CHCR_CPEN_MASK)
-#define CHCR_SYNC(c) ((dma->c.chcr & CHCR_SYNC_MASK) >> SYNC_SHIF)
-#define CHCR_CDWS(c) ((dma->c.chcr & CHCR_CDWS_MASK) >> CDWS_SHIF)
-#define CHCR_CCWS(c) ((dma->c.chcr & CHCR_CCWS_MASK) >> CCWS_SHIF)
-#define CHCR_BUSY(c) (dma->c.chcr & CHCR_BUSY_MASK)
-#define CHCR_TRIG(c) (dma->c.chcr & CHCR_TRIG_MASK)
-
-#define BCR_SIZE(c) (dma->c.bcr & 0xffff)
-#define BCR_BCNT(c) ((dma->c.bcr >> 16) & 0xffff)
-
-/*
- 0-5 Unknown (read/write-able)
- 6-14 Not used (always zero)
- 15 Force IRQ (sets bit31) (0=None, 1=Force Bit31=1)
- 16-22 IRQ Enable setting bit24-30 upon DMA0..DMA6 (0=None, 1=Enable)
- 23 IRQ Enable setting bit31 when bit24-30=nonzero (0=None, 1=Enable)
- 24-30 IRQ Flags for DMA0..DMA6 (Write 1 to reset) (0=None, 1=IRQ)
- 31 IRQ Signal (0-to-1 triggers 1F801070h.bit3) (0=None, 1=IRQ) (R)
-*/
-
-#define DICR_FORCE 0x00008000
-#define DICR_FLGEN 0x007f0000
-#define DICR_IRQEN 0x00800000
-#define DICR_FLAGS 0x7f000000
-#define DICR_IRQSI 0x80000000
-#define DICR_DMA0EN 0x00010000
-#define DICR_DMA1EN 0x00020000
-#define DICR_DMA2EN 0x00040000
-#define DICR_DMA3EN 0x00080000
-#define DICR_DMA4EN 0x00100000
-#define DICR_DMA5EN 0x00200000
-#define DICR_DMA6EN 0x00400000
-#define DICR_DMA0FL 0x01000000
-#define DICR_DMA1FL 0x02000000
-#define DICR_DMA2FL 0x04000000
-#define DICR_DMA3FL 0x08000000
-#define DICR_DMA4FL 0x10000000
-#define DICR_DMA5FL 0x20000000
-#define DICR_DMA6FL 0x40000000
-
+
+psx_dma_t* psx_dma_create(void);
+void psx_dma_init(psx_dma_t*, psx_bus_t*, psx_ic_t*);
+void psx_dma_do_mdec_in(psx_dma_t*);
+void psx_dma_do_mdec_out(psx_dma_t*);
+void psx_dma_do_gpu(psx_dma_t*);
+void psx_dma_do_cdrom(psx_dma_t*);
+void psx_dma_do_spu(psx_dma_t*);
+void psx_dma_do_pio(psx_dma_t*);
+void psx_dma_do_otc(psx_dma_t*);
+void psx_dma_perform(psx_dma_t*, int);
+uint32_t psx_dma_read32(psx_dma_t*, uint32_t);
+uint16_t psx_dma_read16(psx_dma_t*, uint32_t);
+uint8_t psx_dma_read8(psx_dma_t*, uint32_t);
+void psx_dma_write32(psx_dma_t*, uint32_t, uint32_t);
+void psx_dma_write16(psx_dma_t*, uint32_t, uint16_t);
+void psx_dma_write8(psx_dma_t*, uint32_t, uint8_t);
+void psx_dma_destroy(psx_dma_t*);
+void psx_dma_update(psx_dma_t*, int);
+
+typedef void (*psx_dma_do_fn_t)(psx_dma_t*);
+
+/*
+ 0-2 DMA0, MDECin Priority (0..7; 0=Highest, 7=Lowest)
+ 3 DMA0, MDECin Master Enable (0=Disable, 1=Enable)
+ 4-6 DMA1, MDECout Priority (0..7; 0=Highest, 7=Lowest)
+ 7 DMA1, MDECout Master Enable (0=Disable, 1=Enable)
+ 8-10 DMA2, GPU Priority (0..7; 0=Highest, 7=Lowest)
+ 11 DMA2, GPU Master Enable (0=Disable, 1=Enable)
+ 12-14 DMA3, CDROM Priority (0..7; 0=Highest, 7=Lowest)
+ 15 DMA3, CDROM Master Enable (0=Disable, 1=Enable)
+ 16-18 DMA4, SPU Priority (0..7; 0=Highest, 7=Lowest)
+ 19 DMA4, SPU Master Enable (0=Disable, 1=Enable)
+ 20-22 DMA5, PIO Priority (0..7; 0=Highest, 7=Lowest)
+ 23 DMA5, PIO Master Enable (0=Disable, 1=Enable)
+ 24-26 DMA6, OTC Priority (0..7; 0=Highest, 7=Lowest)
+ 27 DMA6, OTC Master Enable (0=Disable, 1=Enable)
+ 28-30 Unknown, Priority Offset or so? (R/W)
+ 31 Unknown, no effect? (R/W)
+*/
+
+#define DPCR_DMA0EN 0x00000008
+#define DPCR_DMA1EN 0x00000080
+#define DPCR_DMA2EN 0x00000800
+#define DPCR_DMA3EN 0x00008000
+#define DPCR_DMA4EN 0x00080000
+#define DPCR_DMA5EN 0x00800000
+#define DPCR_DMA6EN 0x08000000
+
+/*
+ 0 Transfer Direction (0=To Main RAM, 1=From Main RAM)
+ 1 Memory Address Step (0=Forward;+4, 1=Backward;-4)
+ 2-7 Not used (always zero)
+ 8 Chopping Enable (0=Normal, 1=Chopping; run CPU during DMA gaps)
+ 9-10 SyncMode, Transfer Synchronisation/Mode (0-3):
+ 0 Start immediately and transfer all at once (used for CDROM, OTC)
+ 1 Sync blocks to DMA requests (used for MDEC, SPU, and GPU-data)
+ 2 Linked-List mode (used for GPU-command-lists)
+ 3 Reserved (not used)
+ 11-15 Not used (always zero)
+ 16-18 Chopping DMA Window Size (1 SHL N words)
+ 19 Not used (always zero)
+ 20-22 Chopping CPU Window Size (1 SHL N clks)
+ 23 Not used (always zero)
+ 24 Start/Busy (0=Stopped/Completed, 1=Start/Enable/Busy)
+ 25-27 Not used (always zero)
+ 28 Start/Trigger (0=Normal, 1=Manual Start; use for SyncMode=0)
+ 29 Unknown (R/W) Pause? (0=No, 1=Pause?) (For SyncMode=0 only?)
+ 30 Unknown (R/W)
+ 31 Not used (always zero)
+*/
+
+#define CHCR_TDIR_MASK 0x00000001
+#define CHCR_STEP_MASK 0x00000002
+#define CHCR_CPEN_MASK 0x00000100
+#define CHCR_SYNC_MASK 0x00000600
+#define CHCR_CDWS_MASK 0x00070000
+#define CHCR_CCWS_MASK 0x00380000
+#define CHCR_BUSY_MASK 0x01000000
+#define CHCR_TRIG_MASK 0x10000000
+
+#define SYNC_SHIF 9
+#define CDWS_SHIF 16
+#define CCWS_SHIF 19
+
+#define CHCR_TDIR(c) (dma->c.chcr & CHCR_TDIR_MASK)
+#define CHCR_STEP(c) (dma->c.chcr & CHCR_STEP_MASK)
+#define CHCR_CPEN(c) (dma->c.chcr & CHCR_CPEN_MASK)
+#define CHCR_SYNC(c) ((dma->c.chcr & CHCR_SYNC_MASK) >> SYNC_SHIF)
+#define CHCR_CDWS(c) ((dma->c.chcr & CHCR_CDWS_MASK) >> CDWS_SHIF)
+#define CHCR_CCWS(c) ((dma->c.chcr & CHCR_CCWS_MASK) >> CCWS_SHIF)
+#define CHCR_BUSY(c) (dma->c.chcr & CHCR_BUSY_MASK)
+#define CHCR_TRIG(c) (dma->c.chcr & CHCR_TRIG_MASK)
+
+#define BCR_SIZE(c) (dma->c.bcr & 0xffff)
+#define BCR_BCNT(c) ((dma->c.bcr >> 16) & 0xffff)
+
+/*
+ 0-5 Unknown (read/write-able)
+ 6-14 Not used (always zero)
+ 15 Force IRQ (sets bit31) (0=None, 1=Force Bit31=1)
+ 16-22 IRQ Enable setting bit24-30 upon DMA0..DMA6 (0=None, 1=Enable)
+ 23 IRQ Enable setting bit31 when bit24-30=nonzero (0=None, 1=Enable)
+ 24-30 IRQ Flags for DMA0..DMA6 (Write 1 to reset) (0=None, 1=IRQ)
+ 31 IRQ Signal (0-to-1 triggers 1F801070h.bit3) (0=None, 1=IRQ) (R)
+*/
+
+#define DICR_FORCE 0x00008000
+#define DICR_FLGEN 0x007f0000
+#define DICR_IRQEN 0x00800000
+#define DICR_FLAGS 0x7f000000
+#define DICR_IRQSI 0x80000000
+#define DICR_DMA0EN 0x00010000
+#define DICR_DMA1EN 0x00020000
+#define DICR_DMA2EN 0x00040000
+#define DICR_DMA3EN 0x00080000
+#define DICR_DMA4EN 0x00100000
+#define DICR_DMA5EN 0x00200000
+#define DICR_DMA6EN 0x00400000
+#define DICR_DMA0FL 0x01000000
+#define DICR_DMA1FL 0x02000000
+#define DICR_DMA2FL 0x04000000
+#define DICR_DMA3FL 0x08000000
+#define DICR_DMA4FL 0x10000000
+#define DICR_DMA5FL 0x20000000
+#define DICR_DMA6FL 0x40000000
+
#endif
--- a/psx/dev/exp1.c
+++ b/psx/dev/exp1.c
@@ -1,58 +1,58 @@
-#include "p9.h"
-
-#include "log.h"
-#include "dev/exp1.h"
-
-psx_exp1_t* psx_exp1_create(void) {
- return (psx_exp1_t*)malloc(sizeof(psx_exp1_t));
-}
-
-int psx_exp1_init(psx_exp1_t* exp1, psx_mc1_t* mc1, const char* path) {
- memset(exp1, 0, sizeof(psx_exp1_t));
-
- exp1->io_base = PSX_EXP1_BEGIN;
- exp1->io_size = PSX_EXP1_SIZE;
-
- exp1->mc1 = mc1;
- exp1->rom = (uint8_t*)malloc(PSX_EXP1_SIZE);
-
- memset(exp1->rom, 0xff, PSX_EXP1_SIZE);
-
- if (path)
- return psx_exp1_load(exp1, path);
-
- return 0;
-}
-
-int psx_exp1_load(psx_exp1_t* exp1, const char* path) {
- if (!path)
- return 0;
-
- FILE* file = fopen(path, "rb");
-
- if (!file)
- return 1;
-
- if (!fread(exp1->rom, 1, PSX_EXP1_SIZE, file))
- return 2;
-
- fclose(file);
-
- return 0;
-}
-
-uint32_t psx_exp1_read32(psx_exp1_t* exp1, uint32_t offset) {
- return *((uint32_t*)(exp1->rom + offset));
-}
-
-uint16_t psx_exp1_read16(psx_exp1_t* exp1, uint32_t offset) {
- return *((uint16_t*)(exp1->rom + offset));
-}
-
-uint8_t psx_exp1_read8(psx_exp1_t* exp1, uint32_t offset) {
- return exp1->rom[offset];
-}
-
+#include "p9.h"
+
+#include "log.h"
+#include "dev/exp1.h"
+
+psx_exp1_t* psx_exp1_create(void) {+ return (psx_exp1_t*)malloc(sizeof(psx_exp1_t));
+}
+
+int psx_exp1_init(psx_exp1_t* exp1, psx_mc1_t* mc1, const char* path) {+ memset(exp1, 0, sizeof(psx_exp1_t));
+
+ exp1->io_base = PSX_EXP1_BEGIN;
+ exp1->io_size = PSX_EXP1_SIZE;
+
+ exp1->mc1 = mc1;
+ exp1->rom = (uint8_t*)malloc(PSX_EXP1_SIZE);
+
+ memset(exp1->rom, 0xff, PSX_EXP1_SIZE);
+
+ if (path)
+ return psx_exp1_load(exp1, path);
+
+ return 0;
+}
+
+int psx_exp1_load(psx_exp1_t* exp1, const char* path) {+ if (!path)
+ return 0;
+
+ FILE* file = fopen(path, "rb");
+
+ if (!file)
+ return 1;
+
+ if (!fread(exp1->rom, 1, PSX_EXP1_SIZE, file))
+ return 2;
+
+ fclose(file);
+
+ return 0;
+}
+
+uint32_t psx_exp1_read32(psx_exp1_t* exp1, uint32_t offset) {+ return *((uint32_t*)(exp1->rom + offset));
+}
+
+uint16_t psx_exp1_read16(psx_exp1_t* exp1, uint32_t offset) {+ return *((uint16_t*)(exp1->rom + offset));
+}
+
+uint8_t psx_exp1_read8(psx_exp1_t* exp1, uint32_t offset) {+ return exp1->rom[offset];
+}
+
void psx_exp1_write32(psx_exp1_t* exp1, uint32_t offset, uint32_t value) {USED(exp1);
log_warn("Unhandled 32-bit EXP1 write at offset %08x (%08x)", offset, value);@@ -67,8 +67,8 @@
USED(exp1);
log_warn("Unhandled 8-bit EXP1 write at offset %08x (%02x)", offset, value);}
-
-void psx_exp1_destroy(psx_exp1_t* exp1) {
- free(exp1->rom);
- free(exp1);
+
+void psx_exp1_destroy(psx_exp1_t* exp1) {+ free(exp1->rom);
+ free(exp1);
}
--- a/psx/dev/exp1.h
+++ b/psx/dev/exp1.h
@@ -1,14 +1,14 @@
#ifndef PSX_DEV_EXP1_H
-#define PSX_DEV_EXP1_H
-
-#include "p9.h"
-
-#include "dev/mc1.h"
-
-#define PSX_EXP1_BEGIN 0x1f000000
-#define PSX_EXP1_SIZE 0x80000
-#define PSX_EXP1_END 0x1f080000
-
+#define PSX_DEV_EXP1_H
+
+#include "p9.h"
+
+#include "dev/mc1.h"
+
+#define PSX_EXP1_BEGIN 0x1f000000
+#define PSX_EXP1_SIZE 0x80000
+#define PSX_EXP1_END 0x1f080000
+
struct psx_exp1_t {uint32_t bus_delay;
uint32_t io_base, io_size;
@@ -18,16 +18,16 @@
};
typedef struct psx_exp1_t psx_exp1_t;
-
-psx_exp1_t* psx_exp1_create(void);
-int psx_exp1_init(psx_exp1_t*, psx_mc1_t*, const char*);
-int psx_exp1_load(psx_exp1_t*, const char*);
-uint32_t psx_exp1_read32(psx_exp1_t*, uint32_t);
-uint16_t psx_exp1_read16(psx_exp1_t*, uint32_t);
-uint8_t psx_exp1_read8(psx_exp1_t*, uint32_t);
-void psx_exp1_write32(psx_exp1_t*, uint32_t, uint32_t);
-void psx_exp1_write16(psx_exp1_t*, uint32_t, uint16_t);
-void psx_exp1_write8(psx_exp1_t*, uint32_t, uint8_t);
-void psx_exp1_destroy(psx_exp1_t*);
-
+
+psx_exp1_t* psx_exp1_create(void);
+int psx_exp1_init(psx_exp1_t*, psx_mc1_t*, const char*);
+int psx_exp1_load(psx_exp1_t*, const char*);
+uint32_t psx_exp1_read32(psx_exp1_t*, uint32_t);
+uint16_t psx_exp1_read16(psx_exp1_t*, uint32_t);
+uint8_t psx_exp1_read8(psx_exp1_t*, uint32_t);
+void psx_exp1_write32(psx_exp1_t*, uint32_t, uint32_t);
+void psx_exp1_write16(psx_exp1_t*, uint32_t, uint16_t);
+void psx_exp1_write8(psx_exp1_t*, uint32_t, uint8_t);
+void psx_exp1_destroy(psx_exp1_t*);
+
#endif
--- a/psx/dev/exp2.c
+++ b/psx/dev/exp2.c
@@ -1,26 +1,26 @@
-#include "p9.h"
-
-#include "log.h"
-#include "dev/exp2.h"
-
-psx_exp2_t* psx_exp2_create(void) {
- return (psx_exp2_t*)malloc(sizeof(psx_exp2_t));
-}
-
-void psx_exp2_init(psx_exp2_t* exp2, exp2_tty_tx atcons_tx, exp2_tty_tx duart_tx) {
- memset(exp2, 0, sizeof(psx_exp2_t));
-
- exp2->io_base = PSX_EXP2_BEGIN;
- exp2->io_size = PSX_EXP2_SIZE;
- exp2->atcons_tx = atcons_tx;
- exp2->duart_tx = duart_tx;
-}
-
-void psx_exp2_atcons_put(psx_exp2_t* exp2, char c) {
- exp2->atc_stat |= 0x10;
- exp2->atc_rx = c;
-}
-
+#include "p9.h"
+
+#include "log.h"
+#include "dev/exp2.h"
+
+psx_exp2_t* psx_exp2_create(void) {+ return (psx_exp2_t*)malloc(sizeof(psx_exp2_t));
+}
+
+void psx_exp2_init(psx_exp2_t* exp2, exp2_tty_tx atcons_tx, exp2_tty_tx duart_tx) {+ memset(exp2, 0, sizeof(psx_exp2_t));
+
+ exp2->io_base = PSX_EXP2_BEGIN;
+ exp2->io_size = PSX_EXP2_SIZE;
+ exp2->atcons_tx = atcons_tx;
+ exp2->duart_tx = duart_tx;
+}
+
+void psx_exp2_atcons_put(psx_exp2_t* exp2, char c) {+ exp2->atc_stat |= 0x10;
+ exp2->atc_rx = c;
+}
+
void psx_exp2_duart_put(psx_exp2_t* exp2, char c) {USED(exp2);
USED(c);
@@ -38,20 +38,20 @@
USED(offset);
return 0;
}
-
-uint8_t psx_exp2_read8(psx_exp2_t* exp2, uint32_t offset) {
- switch (offset) {
- case EXP2_DTL_ATC_STAT:
- return exp2->atc_stat | 8;
-
- case EXP2_DTL_ATC_DATA:
- exp2->atc_stat &= 0xef;
- return exp2->atc_rx;
- }
-
- return 0;
-}
-
+
+uint8_t psx_exp2_read8(psx_exp2_t* exp2, uint32_t offset) {+ switch (offset) {+ case EXP2_DTL_ATC_STAT:
+ return exp2->atc_stat | 8;
+
+ case EXP2_DTL_ATC_DATA:
+ exp2->atc_stat &= 0xef;
+ return exp2->atc_rx;
+ }
+
+ return 0;
+}
+
void psx_exp2_write32(psx_exp2_t* exp2, uint32_t offset, uint32_t value) {USED(exp2);
log_warn("Unhandled 32-bit EXP2 write at offset %08x (%08x)", offset, value);@@ -61,26 +61,26 @@
USED(exp2);
log_warn("Unhandled 16-bit EXP2 write at offset %08x (%04x)", offset, value);}
-
-void psx_exp2_write8(psx_exp2_t* exp2, uint32_t offset, uint8_t value) {
- switch (offset) {
- case EXP2_DTL_ATC_DATA:
- if (exp2->atcons_tx)
- exp2->atcons_tx(exp2->atcons_udata, value);
- return;
- break;
-
- case EXP2_LED:
- case EXP2_POST:
- case EXP2_POST2:
- // To-do: Do something with this data
- return;
- break;
- }
-
- log_warn("Unhandled 8-bit EXP2 write at offset %08x (%02x)", offset, value);
-}
-
-void psx_exp2_destroy(psx_exp2_t* exp2) {
- free(exp2);
+
+void psx_exp2_write8(psx_exp2_t* exp2, uint32_t offset, uint8_t value) {+ switch (offset) {+ case EXP2_DTL_ATC_DATA:
+ if (exp2->atcons_tx)
+ exp2->atcons_tx(exp2->atcons_udata, value);
+ return;
+ break;
+
+ case EXP2_LED:
+ case EXP2_POST:
+ case EXP2_POST2:
+ // To-do: Do something with this data
+ return;
+ break;
+ }
+
+ log_warn("Unhandled 8-bit EXP2 write at offset %08x (%02x)", offset, value);+}
+
+void psx_exp2_destroy(psx_exp2_t* exp2) {+ free(exp2);
}
--- a/psx/dev/exp2.h
+++ b/psx/dev/exp2.h
@@ -1,32 +1,32 @@
#ifndef PSX_DEV_EXP2_H
-#define PSX_DEV_EXP2_H
-
-#include "p9.h"
-
-#define PSX_EXP2_BEGIN 0x1f802000
-#define PSX_EXP2_SIZE 0x1fe000
-#define PSX_EXP2_END 0x1f9fffff
-
-#define EXP2_DTL_ATC_STAT 0x00 // 1f802000
-#define EXP2_DTL_ATC_DATA 0x02 // 1f802002
-#define EXP2_DTL_HDATA 0x04 // 1f802004
-#define EXP2_DTL_SEC_IRQ10 0x30 // 1f802030
-#define EXP2_DTL_IRQ_CTRL 0x32 // 1f802032
-#define EXP2_DTL_BOOT_DIP 0x40 // 1f802040
-#define EXP2_POST 0x41 // 1f802041
-#define EXP2_LED 0x42 // 1f802042
-#define EXP2_POST2 0x70 // 1f802070
-
-typedef void (*exp2_tty_tx)(void*, uint8_t);
-
+#define PSX_DEV_EXP2_H
+
+#include "p9.h"
+
+#define PSX_EXP2_BEGIN 0x1f802000
+#define PSX_EXP2_SIZE 0x1fe000
+#define PSX_EXP2_END 0x1f9fffff
+
+#define EXP2_DTL_ATC_STAT 0x00 // 1f802000
+#define EXP2_DTL_ATC_DATA 0x02 // 1f802002
+#define EXP2_DTL_HDATA 0x04 // 1f802004
+#define EXP2_DTL_SEC_IRQ10 0x30 // 1f802030
+#define EXP2_DTL_IRQ_CTRL 0x32 // 1f802032
+#define EXP2_DTL_BOOT_DIP 0x40 // 1f802040
+#define EXP2_POST 0x41 // 1f802041
+#define EXP2_LED 0x42 // 1f802042
+#define EXP2_POST2 0x70 // 1f802070
+
+typedef void (*exp2_tty_tx)(void*, uint8_t);
+
struct psx_exp2_t {uint32_t bus_delay;
uint32_t io_base, io_size;
-
- void* duart_udata;
- void* atcons_udata;
-
- exp2_tty_tx duart_tx;
+
+ void* duart_udata;
+ void* atcons_udata;
+
+ exp2_tty_tx duart_tx;
exp2_tty_tx atcons_tx;
uint8_t atc_stat;
@@ -34,17 +34,17 @@
};
typedef struct psx_exp2_t psx_exp2_t;
-
-psx_exp2_t* psx_exp2_create(void);
-void psx_exp2_init(psx_exp2_t*, exp2_tty_tx atcons_tx, exp2_tty_tx duart_tx);
-void psx_exp2_atcons_put(psx_exp2_t*, char);
-void psx_exp2_duart_put(psx_exp2_t*, char);
-uint32_t psx_exp2_read32(psx_exp2_t*, uint32_t);
-uint16_t psx_exp2_read16(psx_exp2_t*, uint32_t);
-uint8_t psx_exp2_read8(psx_exp2_t*, uint32_t);
-void psx_exp2_write32(psx_exp2_t*, uint32_t, uint32_t);
-void psx_exp2_write16(psx_exp2_t*, uint32_t, uint16_t);
-void psx_exp2_write8(psx_exp2_t*, uint32_t, uint8_t);
-void psx_exp2_destroy(psx_exp2_t*);
-
+
+psx_exp2_t* psx_exp2_create(void);
+void psx_exp2_init(psx_exp2_t*, exp2_tty_tx atcons_tx, exp2_tty_tx duart_tx);
+void psx_exp2_atcons_put(psx_exp2_t*, char);
+void psx_exp2_duart_put(psx_exp2_t*, char);
+uint32_t psx_exp2_read32(psx_exp2_t*, uint32_t);
+uint16_t psx_exp2_read16(psx_exp2_t*, uint32_t);
+uint8_t psx_exp2_read8(psx_exp2_t*, uint32_t);
+void psx_exp2_write32(psx_exp2_t*, uint32_t, uint32_t);
+void psx_exp2_write16(psx_exp2_t*, uint32_t, uint16_t);
+void psx_exp2_write8(psx_exp2_t*, uint32_t, uint8_t);
+void psx_exp2_destroy(psx_exp2_t*);
+
#endif
--- a/psx/dev/gpu.c
+++ b/psx/dev/gpu.c
@@ -1,428 +1,428 @@
-#include "p9.h"
-
-#include "dev/gpu.h"
-
-#define SE10(v) ((int16_t)((v) << 5) >> 5)
-
-int g_psx_gpu_dither_kernel[] = {
- -4, +0, -3, +1,
- +2, -2, +3, -1,
- -3, +1, -4, +0,
- +3, -1, +2, -2,
-};
-
-uint16_t gpu_to_bgr555(uint32_t color) {
- return ((color & 0x0000f8) >> 3) |
- ((color & 0x00f800) >> 6) |
- ((color & 0xf80000) >> 9);
-}
-
-#define BGR555(c) \
- (((c & 0x0000f8) >> 3) | \
- ((c & 0x00f800) >> 6) | \
- ((c & 0xf80000) >> 9))
-
-// #define BGR555(c) gpu_to_bgr555(c)
-
-int min3(int a, int b, int c) {
- int m = (a <= b) ? a : b;
-
- return (m <= c) ? m : c;
-}
-
-int max3(int a, int b, int c) {
- int m = (a > b) ? a : b;
-
- return (m > c) ? m : c;
-}
-
-psx_gpu_t* psx_gpu_create(void) {
- return (psx_gpu_t*)malloc(sizeof(psx_gpu_t));
-}
-
-void psx_gpu_init(psx_gpu_t* gpu, psx_ic_t* ic) {
- memset(gpu, 0, sizeof(psx_gpu_t));
-
- gpu->io_base = PSX_GPU_BEGIN;
- gpu->io_size = PSX_GPU_SIZE;
-
- gpu->vram = (uint16_t*)malloc(PSX_GPU_VRAM_SIZE);
- gpu->empty = malloc(PSX_GPU_VRAM_SIZE);
-
- memset(gpu->empty, 0, PSX_GPU_VRAM_SIZE);
-
- gpu->state = GPU_STATE_RECV_CMD;
- gpu->gpustat |= 0x800000;
-
- // Default window size, this is not normally needed
- gpu->display_mode = 1;
-
- gpu->ic = ic;
-}
-
-uint32_t psx_gpu_read32(psx_gpu_t* gpu, uint32_t offset) {
- switch (offset) {
- case 0x00: {
- uint32_t data = 0x0;
-
- if (gpu->c0_tsiz) {
- data |= gpu->vram[gpu->c0_addr + (gpu->c0_xcnt + (gpu->c0_ycnt * 1024))];
-
- gpu->c0_xcnt += 1;
-
- if (gpu->c0_xcnt == gpu->c0_xsiz) {
- gpu->c0_ycnt += 1;
- gpu->c0_xcnt = 0;
- }
-
- data |= gpu->vram[gpu->c0_addr + (gpu->c0_xcnt + (gpu->c0_ycnt * 1024))] << 16;
-
- gpu->c0_xcnt += 1;
-
- if (gpu->c0_xcnt == gpu->c0_xsiz) {
- gpu->c0_ycnt += 1;
- gpu->c0_xcnt = 0;
- }
-
- gpu->c0_tsiz -= 2;
- }
-
- if (gpu->gp1_10h_req) {
- switch (gpu->gp1_10h_req & 7) {
- case 2: {
- data = ((gpu->texw_oy / 8) << 15) | ((gpu->texw_ox / 8) << 10) | ((gpu->texw_my / 8) << 5) | (gpu->texw_mx / 8);
- } break;
- case 3: {
- data = (gpu->draw_y1 << 10) | gpu->draw_x1;
- } break;
- case 4: {
- data = (gpu->draw_y2 << 10) | gpu->draw_x2;
- } break;
- case 5: {
- data = (gpu->off_y << 10) | gpu->off_x;
- } break;
- }
-
- gpu->gp1_10h_req = 0;
- }
-
- return data;
- } break;
- case 0x04: return gpu->gpustat | 0x1c000000;
- }
-
+#include "p9.h"
+
+#include "dev/gpu.h"
+
+#define SE10(v) ((int16_t)((v) << 5) >> 5)
+
+int g_psx_gpu_dither_kernel[] = {+ -4, +0, -3, +1,
+ +2, -2, +3, -1,
+ -3, +1, -4, +0,
+ +3, -1, +2, -2,
+};
+
+uint16_t gpu_to_bgr555(uint32_t color) {+ return ((color & 0x0000f8) >> 3) |
+ ((color & 0x00f800) >> 6) |
+ ((color & 0xf80000) >> 9);
+}
+
+#define BGR555(c) \
+ (((c & 0x0000f8) >> 3) | \
+ ((c & 0x00f800) >> 6) | \
+ ((c & 0xf80000) >> 9))
+
+// #define BGR555(c) gpu_to_bgr555(c)
+
+int min3(int a, int b, int c) {+ int m = (a <= b) ? a : b;
+
+ return (m <= c) ? m : c;
+}
+
+int max3(int a, int b, int c) {+ int m = (a > b) ? a : b;
+
+ return (m > c) ? m : c;
+}
+
+psx_gpu_t* psx_gpu_create(void) {+ return (psx_gpu_t*)malloc(sizeof(psx_gpu_t));
+}
+
+void psx_gpu_init(psx_gpu_t* gpu, psx_ic_t* ic) {+ memset(gpu, 0, sizeof(psx_gpu_t));
+
+ gpu->io_base = PSX_GPU_BEGIN;
+ gpu->io_size = PSX_GPU_SIZE;
+
+ gpu->vram = (uint16_t*)malloc(PSX_GPU_VRAM_SIZE);
+ gpu->empty = malloc(PSX_GPU_VRAM_SIZE);
+
+ memset(gpu->empty, 0, PSX_GPU_VRAM_SIZE);
+
+ gpu->state = GPU_STATE_RECV_CMD;
+ gpu->gpustat |= 0x800000;
+
+ // Default window size, this is not normally needed
+ gpu->display_mode = 1;
+
+ gpu->ic = ic;
+}
+
+uint32_t psx_gpu_read32(psx_gpu_t* gpu, uint32_t offset) {+ switch (offset) {+ case 0x00: {+ uint32_t data = 0x0;
+
+ if (gpu->c0_tsiz) {+ data |= gpu->vram[gpu->c0_addr + (gpu->c0_xcnt + (gpu->c0_ycnt * 1024))];
+
+ gpu->c0_xcnt += 1;
+
+ if (gpu->c0_xcnt == gpu->c0_xsiz) {+ gpu->c0_ycnt += 1;
+ gpu->c0_xcnt = 0;
+ }
+
+ data |= gpu->vram[gpu->c0_addr + (gpu->c0_xcnt + (gpu->c0_ycnt * 1024))] << 16;
+
+ gpu->c0_xcnt += 1;
+
+ if (gpu->c0_xcnt == gpu->c0_xsiz) {+ gpu->c0_ycnt += 1;
+ gpu->c0_xcnt = 0;
+ }
+
+ gpu->c0_tsiz -= 2;
+ }
+
+ if (gpu->gp1_10h_req) {+ switch (gpu->gp1_10h_req & 7) {+ case 2: {+ data = ((gpu->texw_oy / 8) << 15) | ((gpu->texw_ox / 8) << 10) | ((gpu->texw_my / 8) << 5) | (gpu->texw_mx / 8);
+ } break;
+ case 3: {+ data = (gpu->draw_y1 << 10) | gpu->draw_x1;
+ } break;
+ case 4: {+ data = (gpu->draw_y2 << 10) | gpu->draw_x2;
+ } break;
+ case 5: {+ data = (gpu->off_y << 10) | gpu->off_x;
+ } break;
+ }
+
+ gpu->gp1_10h_req = 0;
+ }
+
+ return data;
+ } break;
+ case 0x04: return gpu->gpustat | 0x1c000000;
+ }
+
print("Unhandled 32-bit GPU read at offset %08x\n", offset);-
- return 0x0;
-}
-
+
+ return 0x0;
+}
+
uint16_t psx_gpu_read16(psx_gpu_t* gpu, uint32_t offset) {USED(gpu);
printf("Unhandled 16-bit GPU read at offset %08x\n", offset);-
- return 0;
-
- // exit(1);
-}
-
+
+ return 0;
+
+ // exit(1);
+}
+
uint8_t psx_gpu_read8(psx_gpu_t* gpu, uint32_t offset) {USED(gpu);
printf("Unhandled 8-bit GPU read at offset %08x\n", offset);-
- return 0;
-
- // exit(1);
-}
-
-int min(int x0, int x1) {
- return (x0 <= x1) ? x0 : x1;
-}
-
-int max(int x0, int x1) {
- return (x0 >= x1) ? x0 : x1;
-}
-
-#define EDGE(a, b, c) ((b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x))
-
-uint16_t gpu_fetch_texel(psx_gpu_t* gpu, uint16_t tx, uint16_t ty, uint32_t tpx, uint32_t tpy, uint16_t clutx, uint16_t cluty, int depth) {
- tx = (tx & ~gpu->texw_mx) | (gpu->texw_ox & gpu->texw_mx);
- ty = (ty & ~gpu->texw_my) | (gpu->texw_oy & gpu->texw_my);
- tx &= 0xff;
- ty &= 0xff;
-
- switch (depth) {
- // 4-bit
- case 0: {
- uint16_t texel = gpu->vram[(tpx + (tx >> 2)) + ((tpy + ty) * 1024)];
-
- int index = (texel >> ((tx & 0x3) << 2)) & 0xf;
-
- return gpu->vram[(clutx + index) + (cluty * 1024)];
- } break;
-
- // 8-bit
- case 1: {
- uint16_t texel = gpu->vram[(tpx + (tx >> 1)) + ((tpy + ty) * 1024)];
-
- int index = (texel >> ((tx & 0x1) << 3)) & 0xff;
-
- return gpu->vram[(clutx + index) + (cluty * 1024)];
- } break;
-
- // 15-bit
- default: {
- return gpu->vram[(tpx + tx) + ((tpy + ty) * 1024)];
- } break;
- }
-}
-
-uint16_t gpu_fetch_texel_bilinear(psx_gpu_t* gpu, float tx, float ty, uint32_t tpx, uint32_t tpy, uint16_t clutx, uint16_t cluty, int depth) {
- float txf = floorf(tx);
- float tyf = floorf(ty);
- float txc = txf + 1.0f;
- float tyc = tyf + 1.0f;
-
- int s0 = gpu_fetch_texel(gpu, (int)txf, (int)tyf, tpx, tpy, clutx, cluty, depth);
-
- if (!s0)
- return 0;
-
- int s1 = gpu_fetch_texel(gpu, (int)txc, (int)tyf, tpx, tpy, clutx, cluty, depth);
- int s2 = gpu_fetch_texel(gpu, (int)txf, (int)tyc, tpx, tpy, clutx, cluty, depth);
- int s3 = gpu_fetch_texel(gpu, (int)txc, (int)tyc, tpx, tpy, clutx, cluty, depth);
-
- float s0r = (s0 >> 0) & 0x1f;
- float s0g = (s0 >> 5) & 0x1f;
- float s0b = (s0 >> 10) & 0x1f;
- float s1r = (s1 >> 0) & 0x1f;
- float s1g = (s1 >> 5) & 0x1f;
- float s1b = (s1 >> 10) & 0x1f;
- float s2r = (s2 >> 0) & 0x1f;
- float s2g = (s2 >> 5) & 0x1f;
- float s2b = (s2 >> 10) & 0x1f;
- float s3r = (s3 >> 0) & 0x1f;
- float s3g = (s3 >> 5) & 0x1f;
- float s3b = (s3 >> 10) & 0x1f;
-
- float q1r = s0r * (txc - tx) + s1r * (tx - txf);
- float q1g = s0g * (txc - tx) + s1g * (tx - txf);
- float q1b = s0b * (txc - tx) + s1b * (tx - txf);
- float q2r = s2r * (txc - tx) + s3r * (tx - txf);
- float q2g = s2g * (txc - tx) + s3g * (tx - txf);
- float q2b = s2b * (txc - tx) + s3b * (tx - txf);
- int qr = q1r * (tyc - ty) + q2r * (ty - tyf);
- int qg = q1g * (tyc - ty) + q2g * (ty - tyf);
- int qb = q1b * (tyc - ty) + q2b * (ty - tyf);
-
- return qr | (qg << 5) | (qb << 10) | (s0 & 0x8000) | (s1 & 0x8000) | (s2 & 0x8000) | (s3 & 0x8000);
-}
-
-#define TL(z, a, b) \
- ((z < 0) || ((z == 0) && ((b.y > a.y) || ((b.y == a.y) && (b.x < a.x)))))
-
+
+ return 0;
+
+ // exit(1);
+}
+
+int min(int x0, int x1) {+ return (x0 <= x1) ? x0 : x1;
+}
+
+int max(int x0, int x1) {+ return (x0 >= x1) ? x0 : x1;
+}
+
+#define EDGE(a, b, c) ((b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x))
+
+uint16_t gpu_fetch_texel(psx_gpu_t* gpu, uint16_t tx, uint16_t ty, uint32_t tpx, uint32_t tpy, uint16_t clutx, uint16_t cluty, int depth) {+ tx = (tx & ~gpu->texw_mx) | (gpu->texw_ox & gpu->texw_mx);
+ ty = (ty & ~gpu->texw_my) | (gpu->texw_oy & gpu->texw_my);
+ tx &= 0xff;
+ ty &= 0xff;
+
+ switch (depth) {+ // 4-bit
+ case 0: {+ uint16_t texel = gpu->vram[(tpx + (tx >> 2)) + ((tpy + ty) * 1024)];
+
+ int index = (texel >> ((tx & 0x3) << 2)) & 0xf;
+
+ return gpu->vram[(clutx + index) + (cluty * 1024)];
+ } break;
+
+ // 8-bit
+ case 1: {+ uint16_t texel = gpu->vram[(tpx + (tx >> 1)) + ((tpy + ty) * 1024)];
+
+ int index = (texel >> ((tx & 0x1) << 3)) & 0xff;
+
+ return gpu->vram[(clutx + index) + (cluty * 1024)];
+ } break;
+
+ // 15-bit
+ default: {+ return gpu->vram[(tpx + tx) + ((tpy + ty) * 1024)];
+ } break;
+ }
+}
+
+uint16_t gpu_fetch_texel_bilinear(psx_gpu_t* gpu, float tx, float ty, uint32_t tpx, uint32_t tpy, uint16_t clutx, uint16_t cluty, int depth) {+ float txf = floorf(tx);
+ float tyf = floorf(ty);
+ float txc = txf + 1.0f;
+ float tyc = tyf + 1.0f;
+
+ int s0 = gpu_fetch_texel(gpu, (int)txf, (int)tyf, tpx, tpy, clutx, cluty, depth);
+
+ if (!s0)
+ return 0;
+
+ int s1 = gpu_fetch_texel(gpu, (int)txc, (int)tyf, tpx, tpy, clutx, cluty, depth);
+ int s2 = gpu_fetch_texel(gpu, (int)txf, (int)tyc, tpx, tpy, clutx, cluty, depth);
+ int s3 = gpu_fetch_texel(gpu, (int)txc, (int)tyc, tpx, tpy, clutx, cluty, depth);
+
+ float s0r = (s0 >> 0) & 0x1f;
+ float s0g = (s0 >> 5) & 0x1f;
+ float s0b = (s0 >> 10) & 0x1f;
+ float s1r = (s1 >> 0) & 0x1f;
+ float s1g = (s1 >> 5) & 0x1f;
+ float s1b = (s1 >> 10) & 0x1f;
+ float s2r = (s2 >> 0) & 0x1f;
+ float s2g = (s2 >> 5) & 0x1f;
+ float s2b = (s2 >> 10) & 0x1f;
+ float s3r = (s3 >> 0) & 0x1f;
+ float s3g = (s3 >> 5) & 0x1f;
+ float s3b = (s3 >> 10) & 0x1f;
+
+ float q1r = s0r * (txc - tx) + s1r * (tx - txf);
+ float q1g = s0g * (txc - tx) + s1g * (tx - txf);
+ float q1b = s0b * (txc - tx) + s1b * (tx - txf);
+ float q2r = s2r * (txc - tx) + s3r * (tx - txf);
+ float q2g = s2g * (txc - tx) + s3g * (tx - txf);
+ float q2b = s2b * (txc - tx) + s3b * (tx - txf);
+ int qr = q1r * (tyc - ty) + q2r * (ty - tyf);
+ int qg = q1g * (tyc - ty) + q2g * (ty - tyf);
+ int qb = q1b * (tyc - ty) + q2b * (ty - tyf);
+
+ return qr | (qg << 5) | (qb << 10) | (s0 & 0x8000) | (s1 & 0x8000) | (s2 & 0x8000) | (s3 & 0x8000);
+}
+
+#define TL(z, a, b) \
+ ((z < 0) || ((z == 0) && ((b.y > a.y) || ((b.y == a.y) && (b.x < a.x)))))
+
void gpu_render_triangle(psx_gpu_t* gpu, vertex_t v0, vertex_t v1, vertex_t v2, poly_data_t data, int edge) {USED(edge);
vertex_t a, b, c, p;
-
- int tpx = (data.texp & 0xf) << 6;
- int tpy = (data.texp & 0x10) << 4;
- int clutx = (data.clut & 0x3f) << 4;
- int cluty = (data.clut >> 6) & 0x1ff;
- int depth = (data.texp >> 7) & 3;
- int transp = (data.attrib & PA_TRANSP) != 0;
- int transp_mode;
-
- if (data.attrib & PA_TEXTURED) {
- transp_mode = (data.texp >> 5) & 3;
- } else {
- transp_mode = (gpu->gpustat >> 5) & 3;
- }
-
- a = v0;
-
- /* Ensure the winding order is correct */
- if (EDGE(v0, v1, v2) < 0) {
- b = v2;
- c = v1;
- } else {
- b = v1;
- c = v2;
- }
-
- a.x += gpu->off_x;
- b.x += gpu->off_x;
- c.x += gpu->off_x;
- a.y += gpu->off_y;
- b.y += gpu->off_y;
- c.y += gpu->off_y;
-
- int xmin = min3(a.x, b.x, c.x);
- int ymin = min3(a.y, b.y, c.y);
- int xmax = max3(a.x, b.x, c.x);
- int ymax = max3(a.y, b.y, c.y);
-
- if (((xmax - xmin) > 2048) || ((ymax - ymin) > 1024))
- return;
-
- float area = EDGE(a, b, c);
-
- for (int y = ymin; y < ymax; y++) {
- for (int x = xmin; x < xmax; x++) {
- int bc = (x >= gpu->draw_x1) && (x <= gpu->draw_x2) &&
- (y >= gpu->draw_y1) && (y <= gpu->draw_y2);
-
- if (!bc)
- continue;
-
- p.x = x;
- p.y = y;
-
- float z0 = EDGE(b, c, p);
-
- if (TL(z0, b, c))
- continue;
-
- float z1 = EDGE(c, a, p);
-
- if (TL(z1, c, a))
- continue;
-
- float z2 = EDGE(a, b, p);
-
- if (TL(z2, a, b))
- continue;
-
+
+ int tpx = (data.texp & 0xf) << 6;
+ int tpy = (data.texp & 0x10) << 4;
+ int clutx = (data.clut & 0x3f) << 4;
+ int cluty = (data.clut >> 6) & 0x1ff;
+ int depth = (data.texp >> 7) & 3;
+ int transp = (data.attrib & PA_TRANSP) != 0;
+ int transp_mode;
+
+ if (data.attrib & PA_TEXTURED) {+ transp_mode = (data.texp >> 5) & 3;
+ } else {+ transp_mode = (gpu->gpustat >> 5) & 3;
+ }
+
+ a = v0;
+
+ /* Ensure the winding order is correct */
+ if (EDGE(v0, v1, v2) < 0) {+ b = v2;
+ c = v1;
+ } else {+ b = v1;
+ c = v2;
+ }
+
+ a.x += gpu->off_x;
+ b.x += gpu->off_x;
+ c.x += gpu->off_x;
+ a.y += gpu->off_y;
+ b.y += gpu->off_y;
+ c.y += gpu->off_y;
+
+ int xmin = min3(a.x, b.x, c.x);
+ int ymin = min3(a.y, b.y, c.y);
+ int xmax = max3(a.x, b.x, c.x);
+ int ymax = max3(a.y, b.y, c.y);
+
+ if (((xmax - xmin) > 2048) || ((ymax - ymin) > 1024))
+ return;
+
+ float area = EDGE(a, b, c);
+
+ for (int y = ymin; y < ymax; y++) {+ for (int x = xmin; x < xmax; x++) {+ int bc = (x >= gpu->draw_x1) && (x <= gpu->draw_x2) &&
+ (y >= gpu->draw_y1) && (y <= gpu->draw_y2);
+
+ if (!bc)
+ continue;
+
+ p.x = x;
+ p.y = y;
+
+ float z0 = EDGE(b, c, p);
+
+ if (TL(z0, b, c))
+ continue;
+
+ float z1 = EDGE(c, a, p);
+
+ if (TL(z1, c, a))
+ continue;
+
+ float z2 = EDGE(a, b, p);
+
+ if (TL(z2, a, b))
+ continue;
+
uint16_t color;
uint32_t mod;
-
- if (data.attrib & PA_SHADED) {
- float cr = (z0 * ((a.c >> 0) & 0xff) + z1 * ((b.c >> 0) & 0xff) + z2 * ((c.c >> 0) & 0xff)) / area;
- float cg = (z0 * ((a.c >> 8) & 0xff) + z1 * ((b.c >> 8) & 0xff) + z2 * ((c.c >> 8) & 0xff)) / area;
- float cb = (z0 * ((a.c >> 16) & 0xff) + z1 * ((b.c >> 16) & 0xff) + z2 * ((c.c >> 16) & 0xff)) / area;
-
- int dy = (y - ymin) & 3;
- int dx = (x - xmin) & 3;
-
- int dither = g_psx_gpu_dither_kernel[dx + (dy * 4)];
-
- cr += dither;
- cg += dither;
- cb += dither;
-
- // Saturate (clamp) to 00-ff
- cr = (cr >= 255.0f) ? 255.0f : ((cr <= 0.0f) ? 0.0f : cr);
- cg = (cg >= 255.0f) ? 255.0f : ((cg <= 0.0f) ? 0.0f : cg);
- cb = (cb >= 255.0f) ? 255.0f : ((cb <= 0.0f) ? 0.0f : cb);
-
- unsigned int ucr = roundf(cr);
- unsigned int ucg = roundf(cg);
- unsigned int ucb = roundf(cb);
-
- uint32_t rgb = (ucb << 16) | (ucg << 8) | ucr;
-
- mod = rgb;
- } else {
- mod = data.v[0].c;
- }
-
- if (data.attrib & PA_TEXTURED) {
- float tx = ((z0 * a.tx) + (z1 * b.tx) + (z2 * c.tx)) / area;
- float ty = ((z0 * a.ty) + (z1 * b.ty) + (z2 * c.ty)) / area;
-
- uint16_t texel = gpu_fetch_texel_bilinear(gpu, tx, ty, tpx, tpy, clutx, cluty, depth);
-
- if (!texel)
- continue;
-
- if (data.attrib & PA_TRANSP)
- transp = (texel & 0x8000) != 0;
-
- if (data.attrib & PA_RAW) {
- color = texel;
- } else {
- float tr = ((texel >> 0 ) & 0x1f) << 3;
- float tg = ((texel >> 5 ) & 0x1f) << 3;
- float tb = ((texel >> 10) & 0x1f) << 3;
-
- float mr = (mod >> 0 ) & 0xff;
- float mg = (mod >> 8 ) & 0xff;
- float mb = (mod >> 16) & 0xff;
-
- float cr = (tr * mr) / 128.0f;
- float cg = (tg * mg) / 128.0f;
- float cb = (tb * mb) / 128.0f;
-
- cr = (cr >= 255.0f) ? 255.0f : ((cr <= 0.0f) ? 0.0f : cr);
- cg = (cg >= 255.0f) ? 255.0f : ((cg <= 0.0f) ? 0.0f : cg);
- cb = (cb >= 255.0f) ? 255.0f : ((cb <= 0.0f) ? 0.0f : cb);
-
- unsigned int ucr = roundf(cr);
- unsigned int ucg = roundf(cg);
- unsigned int ucb = roundf(cb);
-
- uint32_t rgb = ucr | (ucg << 8) | (ucb << 16);
-
- color = BGR555(rgb);
- }
- } else {
- color = BGR555(mod);
- }
-
- float cr = ((color >> 0 ) & 0x1f) << 3;
- float cg = ((color >> 5 ) & 0x1f) << 3;
- float cb = ((color >> 10) & 0x1f) << 3;
-
- if (transp) {
- uint16_t back = gpu->vram[x + (y * 1024)];
-
- float br = ((back >> 0 ) & 0x1f) << 3;
- float bg = ((back >> 5 ) & 0x1f) << 3;
- float bb = ((back >> 10) & 0x1f) << 3;
-
- // Do we use transp or gpustat here?
- switch (transp_mode) {
- case 0: {
- cr = (0.5f * br) + (0.5f * cr);
- cg = (0.5f * bg) + (0.5f * cg);
- cb = (0.5f * bb) + (0.5f * cb);
- } break;
- case 1: {
- cr = br + cr;
- cg = bg + cg;
- cb = bb + cb;
- } break;
- case 2: {
- cr = br - cr;
- cg = bg - cg;
- cb = bb - cb;
- } break;
- case 3: {
- cr = br + (0.25 * cr);
- cg = bg + (0.25 * cg);
- cb = bb + (0.25 * cb);
- } break;
- }
-
- cr = (cr >= 255.0f) ? 255.0f : ((cr <= 0.0f) ? 0.0f : cr);
- cg = (cg >= 255.0f) ? 255.0f : ((cg <= 0.0f) ? 0.0f : cg);
- cb = (cb >= 255.0f) ? 255.0f : ((cb <= 0.0f) ? 0.0f : cb);
-
- unsigned int ucr = roundf(cr);
- unsigned int ucg = roundf(cg);
- unsigned int ucb = roundf(cb);
-
- uint32_t rgb = ucr | (ucg << 8) | (ucb << 16);
-
- color = BGR555(rgb);
- }
-
- gpu->vram[x + (y * 1024)] = color;
- }
- }
-}
-
-#define CLAMP(v, d, u) ((v) <= (d)) ? (d) : (((v) >= (u)) ? (u) : (v))
-
+
+ if (data.attrib & PA_SHADED) {+ float cr = (z0 * ((a.c >> 0) & 0xff) + z1 * ((b.c >> 0) & 0xff) + z2 * ((c.c >> 0) & 0xff)) / area;
+ float cg = (z0 * ((a.c >> 8) & 0xff) + z1 * ((b.c >> 8) & 0xff) + z2 * ((c.c >> 8) & 0xff)) / area;
+ float cb = (z0 * ((a.c >> 16) & 0xff) + z1 * ((b.c >> 16) & 0xff) + z2 * ((c.c >> 16) & 0xff)) / area;
+
+ int dy = (y - ymin) & 3;
+ int dx = (x - xmin) & 3;
+
+ int dither = g_psx_gpu_dither_kernel[dx + (dy * 4)];
+
+ cr += dither;
+ cg += dither;
+ cb += dither;
+
+ // Saturate (clamp) to 00-ff
+ cr = (cr >= 255.0f) ? 255.0f : ((cr <= 0.0f) ? 0.0f : cr);
+ cg = (cg >= 255.0f) ? 255.0f : ((cg <= 0.0f) ? 0.0f : cg);
+ cb = (cb >= 255.0f) ? 255.0f : ((cb <= 0.0f) ? 0.0f : cb);
+
+ unsigned int ucr = roundf(cr);
+ unsigned int ucg = roundf(cg);
+ unsigned int ucb = roundf(cb);
+
+ uint32_t rgb = (ucb << 16) | (ucg << 8) | ucr;
+
+ mod = rgb;
+ } else {+ mod = data.v[0].c;
+ }
+
+ if (data.attrib & PA_TEXTURED) {+ float tx = ((z0 * a.tx) + (z1 * b.tx) + (z2 * c.tx)) / area;
+ float ty = ((z0 * a.ty) + (z1 * b.ty) + (z2 * c.ty)) / area;
+
+ uint16_t texel = gpu_fetch_texel_bilinear(gpu, tx, ty, tpx, tpy, clutx, cluty, depth);
+
+ if (!texel)
+ continue;
+
+ if (data.attrib & PA_TRANSP)
+ transp = (texel & 0x8000) != 0;
+
+ if (data.attrib & PA_RAW) {+ color = texel;
+ } else {+ float tr = ((texel >> 0 ) & 0x1f) << 3;
+ float tg = ((texel >> 5 ) & 0x1f) << 3;
+ float tb = ((texel >> 10) & 0x1f) << 3;
+
+ float mr = (mod >> 0 ) & 0xff;
+ float mg = (mod >> 8 ) & 0xff;
+ float mb = (mod >> 16) & 0xff;
+
+ float cr = (tr * mr) / 128.0f;
+ float cg = (tg * mg) / 128.0f;
+ float cb = (tb * mb) / 128.0f;
+
+ cr = (cr >= 255.0f) ? 255.0f : ((cr <= 0.0f) ? 0.0f : cr);
+ cg = (cg >= 255.0f) ? 255.0f : ((cg <= 0.0f) ? 0.0f : cg);
+ cb = (cb >= 255.0f) ? 255.0f : ((cb <= 0.0f) ? 0.0f : cb);
+
+ unsigned int ucr = roundf(cr);
+ unsigned int ucg = roundf(cg);
+ unsigned int ucb = roundf(cb);
+
+ uint32_t rgb = ucr | (ucg << 8) | (ucb << 16);
+
+ color = BGR555(rgb);
+ }
+ } else {+ color = BGR555(mod);
+ }
+
+ float cr = ((color >> 0 ) & 0x1f) << 3;
+ float cg = ((color >> 5 ) & 0x1f) << 3;
+ float cb = ((color >> 10) & 0x1f) << 3;
+
+ if (transp) {+ uint16_t back = gpu->vram[x + (y * 1024)];
+
+ float br = ((back >> 0 ) & 0x1f) << 3;
+ float bg = ((back >> 5 ) & 0x1f) << 3;
+ float bb = ((back >> 10) & 0x1f) << 3;
+
+ // Do we use transp or gpustat here?
+ switch (transp_mode) {+ case 0: {+ cr = (0.5f * br) + (0.5f * cr);
+ cg = (0.5f * bg) + (0.5f * cg);
+ cb = (0.5f * bb) + (0.5f * cb);
+ } break;
+ case 1: {+ cr = br + cr;
+ cg = bg + cg;
+ cb = bb + cb;
+ } break;
+ case 2: {+ cr = br - cr;
+ cg = bg - cg;
+ cb = bb - cb;
+ } break;
+ case 3: {+ cr = br + (0.25 * cr);
+ cg = bg + (0.25 * cg);
+ cb = bb + (0.25 * cb);
+ } break;
+ }
+
+ cr = (cr >= 255.0f) ? 255.0f : ((cr <= 0.0f) ? 0.0f : cr);
+ cg = (cg >= 255.0f) ? 255.0f : ((cg <= 0.0f) ? 0.0f : cg);
+ cb = (cb >= 255.0f) ? 255.0f : ((cb <= 0.0f) ? 0.0f : cb);
+
+ unsigned int ucr = roundf(cr);
+ unsigned int ucg = roundf(cg);
+ unsigned int ucb = roundf(cb);
+
+ uint32_t rgb = ucr | (ucg << 8) | (ucb << 16);
+
+ color = BGR555(rgb);
+ }
+
+ gpu->vram[x + (y * 1024)] = color;
+ }
+ }
+}
+
+#define CLAMP(v, d, u) ((v) <= (d)) ? (d) : (((v) >= (u)) ? (u) : (v))
+
void gpu_render_rect(psx_gpu_t* gpu, rect_data_t data) {uint16_t width, height;
@@ -433,14 +433,14 @@
case RS_16X16 : { width = 16 ; height = 16 ; } break; default : { width = 0 ; height = 0 ; } break;}
-
- int textured = (data.attrib & RA_TEXTURED) != 0;
- int transp = (data.attrib & RA_TRANSP) != 0;
- int transp_mode = (gpu->gpustat >> 5) & 3;
-
- int clutx = (data.clut & 0x3f) << 4;
- int cluty = (data.clut >> 6) & 0x1ff;
-
+
+ int textured = (data.attrib & RA_TEXTURED) != 0;
+ int transp = (data.attrib & RA_TRANSP) != 0;
+ int transp_mode = (gpu->gpustat >> 5) & 3;
+
+ int clutx = (data.clut & 0x3f) << 4;
+ int cluty = (data.clut >> 6) & 0x1ff;
+
/* Offset coordinates */
data.v0.x += gpu->off_x;
data.v0.y += gpu->off_y;
@@ -447,1425 +447,1425 @@
data.v0.x = SE10(data.v0.x);
data.v0.y = SE10(data.v0.y);
/* Calculate bounding box */
- int xmax = data.v0.x + width;
- int ymax = data.v0.y + height;
-
- xmax = CLAMP(xmax, -1024, 1024);
- ymax = CLAMP(ymax, -1024, 1024);
- data.v0.x = CLAMP(data.v0.x, -1024, 1024);
- data.v0.y = CLAMP(data.v0.y, -1024, 1024);
-
- int32_t xc = 0, yc = 0;
-
- for (int16_t y = data.v0.y; y < ymax; y++) {
- for (int16_t x = data.v0.x; x < xmax; x++) {
- int bc = (x >= gpu->draw_x1) && (x <= gpu->draw_x2) &&
- (y >= gpu->draw_y1) && (y <= gpu->draw_y2);
-
- if (!bc)
- goto skip;
-
- uint16_t color;
-
- if (textured) {
- uint16_t texel = gpu_fetch_texel(
- gpu,
- data.v0.tx + xc, data.v0.ty + yc,
- gpu->texp_x, gpu->texp_y,
- clutx, cluty,
- gpu->texp_d
- );
-
- if (!texel)
- goto skip;
-
- if ((data.attrib & RA_TRANSP) != 0)
- transp = (texel & 0x8000) != 0;
-
- float tr = ((texel >> 0 ) & 0x1f) << 3;
- float tg = ((texel >> 5 ) & 0x1f) << 3;
- float tb = ((texel >> 10) & 0x1f) << 3;
-
- float mr = (data.v0.c >> 0 ) & 0xff;
- float mg = (data.v0.c >> 8 ) & 0xff;
- float mb = (data.v0.c >> 16) & 0xff;
-
- float cr = (tr * mr) / 128.0f;
- float cg = (tg * mg) / 128.0f;
- float cb = (tb * mb) / 128.0f;
-
- cr = (cr >= 255.0f) ? 255.0f : ((cr <= 0.0f) ? 0.0f : cr);
- cg = (cg >= 255.0f) ? 255.0f : ((cg <= 0.0f) ? 0.0f : cg);
- cb = (cb >= 255.0f) ? 255.0f : ((cb <= 0.0f) ? 0.0f : cb);
-
- unsigned int ucr = roundf(cr);
- unsigned int ucg = roundf(cg);
- unsigned int ucb = roundf(cb);
-
- uint32_t rgb = ucr | (ucg << 8) | (ucb << 16);
-
- color = BGR555(rgb);
- } else {
- color = BGR555(data.v0.c);
- }
-
- float cr = ((color >> 0 ) & 0x1f) << 3;
- float cg = ((color >> 5 ) & 0x1f) << 3;
- float cb = ((color >> 10) & 0x1f) << 3;
-
- if (transp) {
- uint16_t back = gpu->vram[x + (y * 1024)];
-
- float br = ((back >> 0 ) & 0x1f) << 3;
- float bg = ((back >> 5 ) & 0x1f) << 3;
- float bb = ((back >> 10) & 0x1f) << 3;
-
- switch (transp_mode) {
- case 0: {
- cr = (0.5f * br) + (0.5f * cr);
- cg = (0.5f * bg) + (0.5f * cg);
- cb = (0.5f * bb) + (0.5f * cb);
- } break;
- case 1: {
- cr = br + cr;
- cg = bg + cg;
- cb = bb + cb;
- } break;
- case 2: {
- cr = br - cr;
- cg = bg - cg;
- cb = bb - cb;
- } break;
- case 3: {
- cr = br + (0.25f * cr);
- cg = bg + (0.25f * cg);
- cb = bb + (0.25f * cb);
- } break;
- }
-
- cr = (cr >= 255.0f) ? 255.0f : ((cr <= 0.0f) ? 0.0f : cr);
- cg = (cg >= 255.0f) ? 255.0f : ((cg <= 0.0f) ? 0.0f : cg);
- cb = (cb >= 255.0f) ? 255.0f : ((cb <= 0.0f) ? 0.0f : cb);
-
- unsigned int ucr = roundf(cr);
- unsigned int ucg = roundf(cg);
- unsigned int ucb = roundf(cb);
-
- uint32_t rgb = ucr | (ucg << 8) | (ucb << 16);
-
- color = BGR555(rgb);
- }
-
- gpu->vram[x + (y * 1024)] = color;
-
- skip:
-
- ++xc;
- }
-
- xc = 0;
-
- ++yc;
- }
-}
-
-void plotLineLow(psx_gpu_t* gpu, int x0, int y0, int x1, int y1, uint16_t color) {
- int dx = x1 - x0;
- int dy = y1 - y0;
- int yi = 1;
- if (dy < 0) {
- yi = -1;
- dy = -dy;
- }
- int d = (2 * dy) - dx;
- int y = y0;
-
- for (int x = x0; x < x1; x++) {
- int bc = (x >= gpu->draw_x1) && (x <= gpu->draw_x2) &&
- (y >= gpu->draw_y1) && (y <= gpu->draw_y2);
-
- if ((x < 1024) && (y < 512) && (x >= 0) && (y >= 0) && bc)
- gpu->vram[x + (y * 1024)] = color;
-
- if (d > 0) {
- y += yi;
- d += (2 * (dy - dx));
- } else {
- d += 2*dy;
- }
- }
-}
-
-void plotLineHigh(psx_gpu_t* gpu, int x0, int y0, int x1, int y1, uint16_t color) {
- int dx = x1 - x0;
- int dy = y1 - y0;
- int xi = 1;
- if (dx < 0) {
- xi = -1;
- dx = -dx;
- }
- int d = (2 * dx) - dy;
- int x = x0;
-
- for (int y = y0; y < y1; y++) {
- int bc = (x >= gpu->draw_x1) && (x <= gpu->draw_x2) &&
- (y >= gpu->draw_y1) && (y <= gpu->draw_y2);
-
- if ((x < 1024) && (y < 512) && (x >= 0) && (y >= 0) && bc)
- gpu->vram[x + (y * 1024)] = color;
-
- if (d > 0) {
- x = x + xi;
- d += (2 * (dx - dy));
- } else {
- d += 2*dx;
- }
- }
-}
-
-void plotLine(psx_gpu_t* gpu, int x0, int y0, int x1, int y1, uint16_t color) {
- if (abs(y1 - y0) < abs(x1 - x0)) {
- if (x0 > x1) {
- plotLineLow(gpu, x1, y1, x0, y0, color);
- } else {
- plotLineLow(gpu, x0, y0, x1, y1, color);
- }
- } else {
- if (y0 > y1) {
- plotLineHigh(gpu, x1, y1, x0, y0, color);
- } else {
- plotLineHigh(gpu, x0, y0, x1, y1, color);
- }
- }
-}
-
-void gpu_render_flat_line(psx_gpu_t* gpu, vertex_t v0, vertex_t v1, uint32_t color) {
- v0.x += gpu->off_x;
- v0.y += gpu->off_y;
- v1.x += gpu->off_x;
- v1.y += gpu->off_y;
-
- plotLine(gpu, v0.x, v0.y, v1.x, v1.y, color);
-}
-
-void gpu_render_flat_rectangle(psx_gpu_t* gpu, vertex_t v, uint32_t w, uint32_t h, uint32_t color) {
- /* Offset coordinates */
- v.x += gpu->off_x;
- v.y += gpu->off_y;
-
- /* Calculate bounding box */
- int xmin = max(v.x, gpu->draw_x1);
- int ymin = max(v.y, gpu->draw_y1);
- int xmax = min(xmin + w, gpu->draw_x2);
- int ymax = min(ymin + h, gpu->draw_y2);
-
- for (uint32_t y = ymin; y < ymax; y++) {
- for (uint32_t x = xmin; x < xmax; x++) {
- int bc = (x >= gpu->draw_x1) && (x <= gpu->draw_x2) &&
- (y >= gpu->draw_y1) && (y <= gpu->draw_y2);
-
- if (!bc)
- continue;
-
- gpu->vram[x + (y * 1024)] = color;
- }
- }
-}
-
+ int xmax = data.v0.x + width;
+ int ymax = data.v0.y + height;
+
+ xmax = CLAMP(xmax, -1024, 1024);
+ ymax = CLAMP(ymax, -1024, 1024);
+ data.v0.x = CLAMP(data.v0.x, -1024, 1024);
+ data.v0.y = CLAMP(data.v0.y, -1024, 1024);
+
+ int32_t xc = 0, yc = 0;
+
+ for (int16_t y = data.v0.y; y < ymax; y++) {+ for (int16_t x = data.v0.x; x < xmax; x++) {+ int bc = (x >= gpu->draw_x1) && (x <= gpu->draw_x2) &&
+ (y >= gpu->draw_y1) && (y <= gpu->draw_y2);
+
+ if (!bc)
+ goto skip;
+
+ uint16_t color;
+
+ if (textured) {+ uint16_t texel = gpu_fetch_texel(
+ gpu,
+ data.v0.tx + xc, data.v0.ty + yc,
+ gpu->texp_x, gpu->texp_y,
+ clutx, cluty,
+ gpu->texp_d
+ );
+
+ if (!texel)
+ goto skip;
+
+ if ((data.attrib & RA_TRANSP) != 0)
+ transp = (texel & 0x8000) != 0;
+
+ float tr = ((texel >> 0 ) & 0x1f) << 3;
+ float tg = ((texel >> 5 ) & 0x1f) << 3;
+ float tb = ((texel >> 10) & 0x1f) << 3;
+
+ float mr = (data.v0.c >> 0 ) & 0xff;
+ float mg = (data.v0.c >> 8 ) & 0xff;
+ float mb = (data.v0.c >> 16) & 0xff;
+
+ float cr = (tr * mr) / 128.0f;
+ float cg = (tg * mg) / 128.0f;
+ float cb = (tb * mb) / 128.0f;
+
+ cr = (cr >= 255.0f) ? 255.0f : ((cr <= 0.0f) ? 0.0f : cr);
+ cg = (cg >= 255.0f) ? 255.0f : ((cg <= 0.0f) ? 0.0f : cg);
+ cb = (cb >= 255.0f) ? 255.0f : ((cb <= 0.0f) ? 0.0f : cb);
+
+ unsigned int ucr = roundf(cr);
+ unsigned int ucg = roundf(cg);
+ unsigned int ucb = roundf(cb);
+
+ uint32_t rgb = ucr | (ucg << 8) | (ucb << 16);
+
+ color = BGR555(rgb);
+ } else {+ color = BGR555(data.v0.c);
+ }
+
+ float cr = ((color >> 0 ) & 0x1f) << 3;
+ float cg = ((color >> 5 ) & 0x1f) << 3;
+ float cb = ((color >> 10) & 0x1f) << 3;
+
+ if (transp) {+ uint16_t back = gpu->vram[x + (y * 1024)];
+
+ float br = ((back >> 0 ) & 0x1f) << 3;
+ float bg = ((back >> 5 ) & 0x1f) << 3;
+ float bb = ((back >> 10) & 0x1f) << 3;
+
+ switch (transp_mode) {+ case 0: {+ cr = (0.5f * br) + (0.5f * cr);
+ cg = (0.5f * bg) + (0.5f * cg);
+ cb = (0.5f * bb) + (0.5f * cb);
+ } break;
+ case 1: {+ cr = br + cr;
+ cg = bg + cg;
+ cb = bb + cb;
+ } break;
+ case 2: {+ cr = br - cr;
+ cg = bg - cg;
+ cb = bb - cb;
+ } break;
+ case 3: {+ cr = br + (0.25f * cr);
+ cg = bg + (0.25f * cg);
+ cb = bb + (0.25f * cb);
+ } break;
+ }
+
+ cr = (cr >= 255.0f) ? 255.0f : ((cr <= 0.0f) ? 0.0f : cr);
+ cg = (cg >= 255.0f) ? 255.0f : ((cg <= 0.0f) ? 0.0f : cg);
+ cb = (cb >= 255.0f) ? 255.0f : ((cb <= 0.0f) ? 0.0f : cb);
+
+ unsigned int ucr = roundf(cr);
+ unsigned int ucg = roundf(cg);
+ unsigned int ucb = roundf(cb);
+
+ uint32_t rgb = ucr | (ucg << 8) | (ucb << 16);
+
+ color = BGR555(rgb);
+ }
+
+ gpu->vram[x + (y * 1024)] = color;
+
+ skip:
+
+ ++xc;
+ }
+
+ xc = 0;
+
+ ++yc;
+ }
+}
+
+void plotLineLow(psx_gpu_t* gpu, int x0, int y0, int x1, int y1, uint16_t color) {+ int dx = x1 - x0;
+ int dy = y1 - y0;
+ int yi = 1;
+ if (dy < 0) {+ yi = -1;
+ dy = -dy;
+ }
+ int d = (2 * dy) - dx;
+ int y = y0;
+
+ for (int x = x0; x < x1; x++) {+ int bc = (x >= gpu->draw_x1) && (x <= gpu->draw_x2) &&
+ (y >= gpu->draw_y1) && (y <= gpu->draw_y2);
+
+ if ((x < 1024) && (y < 512) && (x >= 0) && (y >= 0) && bc)
+ gpu->vram[x + (y * 1024)] = color;
+
+ if (d > 0) {+ y += yi;
+ d += (2 * (dy - dx));
+ } else {+ d += 2*dy;
+ }
+ }
+}
+
+void plotLineHigh(psx_gpu_t* gpu, int x0, int y0, int x1, int y1, uint16_t color) {+ int dx = x1 - x0;
+ int dy = y1 - y0;
+ int xi = 1;
+ if (dx < 0) {+ xi = -1;
+ dx = -dx;
+ }
+ int d = (2 * dx) - dy;
+ int x = x0;
+
+ for (int y = y0; y < y1; y++) {+ int bc = (x >= gpu->draw_x1) && (x <= gpu->draw_x2) &&
+ (y >= gpu->draw_y1) && (y <= gpu->draw_y2);
+
+ if ((x < 1024) && (y < 512) && (x >= 0) && (y >= 0) && bc)
+ gpu->vram[x + (y * 1024)] = color;
+
+ if (d > 0) {+ x = x + xi;
+ d += (2 * (dx - dy));
+ } else {+ d += 2*dx;
+ }
+ }
+}
+
+void plotLine(psx_gpu_t* gpu, int x0, int y0, int x1, int y1, uint16_t color) {+ if (abs(y1 - y0) < abs(x1 - x0)) {+ if (x0 > x1) {+ plotLineLow(gpu, x1, y1, x0, y0, color);
+ } else {+ plotLineLow(gpu, x0, y0, x1, y1, color);
+ }
+ } else {+ if (y0 > y1) {+ plotLineHigh(gpu, x1, y1, x0, y0, color);
+ } else {+ plotLineHigh(gpu, x0, y0, x1, y1, color);
+ }
+ }
+}
+
+void gpu_render_flat_line(psx_gpu_t* gpu, vertex_t v0, vertex_t v1, uint32_t color) {+ v0.x += gpu->off_x;
+ v0.y += gpu->off_y;
+ v1.x += gpu->off_x;
+ v1.y += gpu->off_y;
+
+ plotLine(gpu, v0.x, v0.y, v1.x, v1.y, color);
+}
+
+void gpu_render_flat_rectangle(psx_gpu_t* gpu, vertex_t v, uint32_t w, uint32_t h, uint32_t color) {+ /* Offset coordinates */
+ v.x += gpu->off_x;
+ v.y += gpu->off_y;
+
+ /* Calculate bounding box */
+ int xmin = max(v.x, gpu->draw_x1);
+ int ymin = max(v.y, gpu->draw_y1);
+ int xmax = min(xmin + w, gpu->draw_x2);
+ int ymax = min(ymin + h, gpu->draw_y2);
+
+ for (uint32_t y = ymin; y < ymax; y++) {+ for (uint32_t x = xmin; x < xmax; x++) {+ int bc = (x >= gpu->draw_x1) && (x <= gpu->draw_x2) &&
+ (y >= gpu->draw_y1) && (y <= gpu->draw_y2);
+
+ if (!bc)
+ continue;
+
+ gpu->vram[x + (y * 1024)] = color;
+ }
+ }
+}
+
void gpu_render_textured_rectangle(psx_gpu_t* gpu, vertex_t v, uint32_t w, uint32_t h, uint16_t clutx, uint16_t cluty, uint32_t color) {USED(color);
vertex_t a = v;
-
- a.x += gpu->off_x;
- a.y += gpu->off_y;
-
- int xmin = max(a.x, gpu->draw_x1);
- int ymin = max(a.y, gpu->draw_y1);
- int xmax = min(xmin + w, gpu->draw_x2);
- int ymax = min(ymin + h, gpu->draw_y2);
-
- uint32_t xc = 0, yc = 0;
-
- for (int y = ymin; y < ymax; y++) {
- for (int x = xmin; x < xmax; x++) {
- uint16_t texel = gpu_fetch_texel(
- gpu,
- a.tx + xc, a.ty + yc,
- gpu->texp_x, gpu->texp_y,
- clutx, cluty,
- gpu->texp_d
- );
-
- ++xc;
-
- gpu->vram[x + (y * 1024)] = texel;
- }
-
- xc = 0;
-
- ++yc;
- }
-}
-
-void gpu_render_flat_triangle(psx_gpu_t* gpu, vertex_t v0, vertex_t v1, vertex_t v2, uint32_t color) {
- vertex_t a, b, c;
-
- a = v0;
-
- /* Ensure the winding order is correct */
- if (EDGE(v0, v1, v2) < 0) {
- b = v2;
- c = v1;
- } else {
- b = v1;
- c = v2;
- }
-
- a.x += gpu->off_x;
- a.y += gpu->off_y;
- b.x += gpu->off_x;
- b.y += gpu->off_y;
- c.x += gpu->off_x;
- c.y += gpu->off_y;
-
- int xmin = max(min(min(a.x, b.x), c.x), gpu->draw_x1);
- int ymin = max(min(min(a.y, b.y), c.y), gpu->draw_y1);
- int xmax = min(max(max(a.x, b.x), c.x), gpu->draw_x2);
- int ymax = min(max(max(a.y, b.y), c.y), gpu->draw_y2);
-
- for (int y = ymin; y < ymax; y++) {
- for (int x = xmin; x < xmax; x++) {
- int z0 = ((b.x - a.x) * (y - a.y)) - ((b.y - a.y) * (x - a.x));
- int z1 = ((c.x - b.x) * (y - b.y)) - ((c.y - b.y) * (x - b.x));
- int z2 = ((a.x - c.x) * (y - c.y)) - ((a.y - c.y) * (x - c.x));
-
- if ((z0 >= 0) && (z1 >= 0) && (z2 >= 0)) {
- gpu->vram[x + (y * 1024)] = BGR555(color);
- }
- }
- }
-}
-
-void gpu_render_shaded_triangle(psx_gpu_t* gpu, vertex_t v0, vertex_t v1, vertex_t v2) {
- vertex_t a, b, c, p;
-
- a = v0;
-
- /* Ensure the winding order is correct */
- if (EDGE(v0, v1, v2) < 0) {
- b = v2;
- c = v1;
- } else {
- b = v1;
- c = v2;
- }
-
- a.x += gpu->off_x;
- a.y += gpu->off_y;
- b.x += gpu->off_x;
- b.y += gpu->off_y;
- c.x += gpu->off_x;
- c.y += gpu->off_y;
-
- int xmin = max(min(min(a.x, b.x), c.x), gpu->draw_x1);
- int ymin = max(min(min(a.y, b.y), c.y), gpu->draw_y1);
- int xmax = min(max(max(a.x, b.x), c.x), gpu->draw_x2);
- int ymax = min(max(max(a.y, b.y), c.y), gpu->draw_y2);
-
- int area = EDGE(a, b, c);
-
- for (int y = ymin; y < ymax; y++) {
- for (int x = xmin; x < xmax; x++) {
- p.x = x;
- p.y = y;
-
- float z0 = EDGE((float)b, (float)c, (float)p);
- float z1 = EDGE((float)c, (float)a, (float)p);
- float z2 = EDGE((float)a, (float)b, (float)p);
-
- if ((z0 >= 0) && (z1 >= 0) && (z2 >= 0)) {
- int cr = (z0 * ((a.c >> 0) & 0xff) + z1 * ((b.c >> 0) & 0xff) + z2 * ((c.c >> 0) & 0xff)) / area;
- int cg = (z0 * ((a.c >> 8) & 0xff) + z1 * ((b.c >> 8) & 0xff) + z2 * ((c.c >> 8) & 0xff)) / area;
- int cb = (z0 * ((a.c >> 16) & 0xff) + z1 * ((b.c >> 16) & 0xff) + z2 * ((c.c >> 16) & 0xff)) / area;
-
- // Calculate positions within our 4x4 dither
- // kernel
- int dy = (y - ymin) % 4;
- int dx = (x - xmin) % 4;
-
- // Shift two pixels horizontally on the last
- // two scanlines?
- // if (dy > 1) {
- // dx = ((x + 2) - xmin) % 4;
- // }
-
- int dither = g_psx_gpu_dither_kernel[dx + (dy * 4)];
-
- // Add to the original 8-bit color values
- cr += dither;
- cg += dither;
- cb += dither;
-
- // Saturate (clamp) to 00-ff
- cr = (cr >= 0xff) ? 0xff : ((cr <= 0) ? 0 : cr);
- cg = (cg >= 0xff) ? 0xff : ((cg <= 0) ? 0 : cg);
- cb = (cb >= 0xff) ? 0xff : ((cb <= 0) ? 0 : cb);
-
- uint32_t color = (cb << 16) | (cg << 8) | cr;
-
- gpu->vram[x + (y * 1024)] = BGR555(color);
- }
- }
- }
-}
-
-void gpu_render_textured_triangle(psx_gpu_t* gpu, vertex_t v0, vertex_t v1, vertex_t v2, uint32_t tpx, uint32_t tpy, uint16_t clutx, uint16_t cluty, int depth) {
- vertex_t a, b, c;
-
- a = v0;
-
- /* Ensure the winding order is correct */
- if (EDGE(v0, v1, v2) < 0) {
- b = v2;
- c = v1;
- } else {
- b = v1;
- c = v2;
- }
-
- a.x += gpu->off_x;
- a.y += gpu->off_y;
- b.x += gpu->off_x;
- b.y += gpu->off_y;
- c.x += gpu->off_x;
- c.y += gpu->off_y;
-
- int xmin = max(min(min(a.x, b.x), c.x), gpu->draw_x1);
- int ymin = max(min(min(a.y, b.y), c.y), gpu->draw_y1);
- int xmax = min(max(max(a.x, b.x), c.x), gpu->draw_x2);
- int ymax = min(max(max(a.y, b.y), c.y), gpu->draw_y2);
-
- uint32_t area = EDGE(a, b, c);
-
- for (int y = ymin; y < ymax; y++) {
- for (int x = xmin; x < xmax; x++) {
- vertex_t p;
-
- p.x = x;
- p.y = y;
-
- float z0 = EDGE((float)b, (float)c, (float)p);
- float z1 = EDGE((float)c, (float)a, (float)p);
- float z2 = EDGE((float)a, (float)b, (float)p);
-
- if ((z0 >= 0) && (z1 >= 0) && (z2 >= 0)) {
- uint32_t tx = ((z0 * a.tx) + (z1 * b.tx) + (z2 * c.tx)) / area;
- uint32_t ty = ((z0 * a.ty) + (z1 * b.ty) + (z2 * c.ty)) / area;
-
- uint16_t color = gpu_fetch_texel(
- gpu,
- tx, ty,
- tpx, tpy,
- clutx, cluty,
- depth
- );
-
- if (!color) continue;
-
- gpu->vram[x + (y * 1024)] = color;
- }
- }
- }
-}
-
-#define I32(v, b) (((int32_t)((v) << (31-b))) >> (31-b))
-
-void gpu_rect(psx_gpu_t* gpu) {
- switch (gpu->state) {
- case GPU_STATE_RECV_CMD: {
- gpu->state = GPU_STATE_RECV_ARGS;
-
- int size = (gpu->buf[0] >> 27) & 3;
- int textured = (gpu->buf[0] & 0x04000000) != 0;
-
- gpu->cmd_args_remaining = 1 + (size == RS_VARIABLE) + textured;
- } break;
-
- case GPU_STATE_RECV_ARGS: {
- if (!gpu->cmd_args_remaining) {
- rect_data_t rect;
-
- rect.attrib = gpu->buf[0] >> 24;
-
- int textured = (rect.attrib & RA_TEXTURED) != 0;
- int raw = (rect.attrib & RA_RAW) != 0;
-
- // Add 1 if is textured
- int size_offset = 2 + textured;
-
- rect.v0.c = gpu->buf[0] & 0xffffff;
- rect.v0.x = SE10(gpu->buf[1] & 0xffff);
- rect.v0.y = SE10(gpu->buf[1] >> 16);
- rect.v0.tx = (gpu->buf[2] >> 0) & 0xff;
- rect.v0.ty = (gpu->buf[2] >> 8) & 0xff;
- rect.clut = gpu->buf[2] >> 16;
- rect.width = gpu->buf[size_offset] & 0xffff;
- rect.height = gpu->buf[size_offset] >> 16;
-
- if (textured && raw)
- rect.v0.c = 0x808080;
-
- gpu_render_rect(gpu, rect);
-
- gpu->state = GPU_STATE_RECV_CMD;
- }
- } break;
- }
-}
-
-void gpu_poly(psx_gpu_t* gpu) {
- switch (gpu->state) {
- case GPU_STATE_RECV_CMD: {
- gpu->state = GPU_STATE_RECV_ARGS;
-
- int shaded = (gpu->buf[0] & 0x10000000) != 0;
- int quad = (gpu->buf[0] & 0x08000000) != 0;
- int textured = (gpu->buf[0] & 0x04000000) != 0;
-
- int fields_per_vertex = 1 + shaded + textured;
- int vertices = 3 + quad;
-
- gpu->cmd_args_remaining = (fields_per_vertex * vertices) - shaded;
- } break;
-
- case GPU_STATE_RECV_ARGS: {
- if (!gpu->cmd_args_remaining) {
- poly_data_t poly;
-
- poly.attrib = gpu->buf[0] >> 24;
-
- int shaded = (poly.attrib & PA_SHADED) != 0;
- int textured = (poly.attrib & PA_TEXTURED) != 0;
-
- int color_offset = shaded * (2 + textured);
- int vert_offset = 1 + (textured | shaded) +
- (textured & shaded);
- int texc_offset = textured * (2 + shaded);
- int texp_offset = textured * (4 + shaded);
-
- poly.clut = gpu->buf[2] >> 16;
- poly.texp = gpu->buf[texp_offset] >> 16;
-
- // Undocumented behavior?
- // Fixes Mortal Kombat II, Bubble Bobble, Driver 1 & 2
- if (textured) {
- gpu->texp_x = (poly.texp & 0xf) << 6;
- gpu->texp_y = (poly.texp & 0x10) << 4;
- gpu->texp_d = (poly.texp >> 7) & 0x3;
- gpu->gpustat &= 0xfffffe00;
- gpu->gpustat |= poly.texp & 0x1ff;
- }
-
- poly.v[0].c = gpu->buf[0+0*color_offset] & 0xffffff;
- poly.v[1].c = gpu->buf[0+1*color_offset] & 0xffffff;
- poly.v[2].c = gpu->buf[0+2*color_offset] & 0xffffff;
- poly.v[3].c = gpu->buf[0+3*color_offset] & 0xffffff;
- poly.v[0].x = SE10(gpu->buf[1+0*vert_offset] & 0xffff);
- poly.v[1].x = SE10(gpu->buf[1+1*vert_offset] & 0xffff);
- poly.v[2].x = SE10(gpu->buf[1+2*vert_offset] & 0xffff);
- poly.v[3].x = SE10(gpu->buf[1+3*vert_offset] & 0xffff);
- poly.v[0].y = SE10(gpu->buf[1+0*vert_offset] >> 16);
- poly.v[1].y = SE10(gpu->buf[1+1*vert_offset] >> 16);
- poly.v[2].y = SE10(gpu->buf[1+2*vert_offset] >> 16);
- poly.v[3].y = SE10(gpu->buf[1+3*vert_offset] >> 16);
- poly.v[0].tx = gpu->buf[2+0*texc_offset] & 0xff;
- poly.v[1].tx = gpu->buf[2+1*texc_offset] & 0xff;
- poly.v[2].tx = gpu->buf[2+2*texc_offset] & 0xff;
- poly.v[3].tx = gpu->buf[2+3*texc_offset] & 0xff;
- poly.v[0].ty = (gpu->buf[2+0*texc_offset] >> 8) & 0xff;
- poly.v[1].ty = (gpu->buf[2+1*texc_offset] >> 8) & 0xff;
- poly.v[2].ty = (gpu->buf[2+2*texc_offset] >> 8) & 0xff;
- poly.v[3].ty = (gpu->buf[2+3*texc_offset] >> 8) & 0xff;
-
- if (poly.attrib & PA_QUAD) {
- gpu_render_triangle(gpu, poly.v[0], poly.v[1], poly.v[2], poly, 1);
- gpu_render_triangle(gpu, poly.v[1], poly.v[2], poly.v[3], poly, 1);
- } else {
- gpu_render_triangle(gpu, poly.v[0], poly.v[1], poly.v[2], poly, 0);
- }
-
- gpu->state = GPU_STATE_RECV_CMD;
- }
- } break;
- }
-}
-
-void gpu_line(psx_gpu_t* gpu) {
- switch (gpu->state) {
- case GPU_STATE_RECV_CMD: {
- gpu->state = GPU_STATE_RECV_ARGS;
-
- int shaded = (gpu->buf[0] & 0x10000000) != 0;
- int polyline = (gpu->buf[0] & 0x08000000) != 0;
-
- gpu->cmd_args_remaining = polyline ? -1 : (shaded ? 3 : 2);
- gpu->line_done = 0;
- } break;
-
- case GPU_STATE_RECV_ARGS: {
- if (gpu->buf[0] & 0x08000000) {
- if ((gpu->buf[gpu->buf_index - 1] & 0xf000f000) == 0x50005000) {
- gpu->state = GPU_STATE_RECV_CMD;
-
- return;
- }
-
- // int shaded = (gpu->buf[0] & 0x10000000) != 0;
-
- // if (shaded) {
- // if (gpu->buf_index > 2) {
-
- // }
- // }
-
- // if (gpu->buf_index > overflow) {
- // vertex_t v0, v1;
-
- // if (shaded) {
- // v0.c = gpu->buf[0] & 0xffffff;
- // v1.c = gpu->buf[4] & 0xffffff;
- // v0.x = gpu->buf[1] & 0xffff;
- // v0.y = gpu->buf[1] >> 16;
- // v1.x = gpu->buf[3] & 0xffff;
- // v1.y = gpu->buf[3] >> 16;
- // } else {
- // v0.c = gpu->buf[0] & 0xffffff;
- // v1.c = gpu->buf[0] & 0xffffff;
- // v0.x = gpu->buf[1] & 0xffff;
- // v0.y = gpu->buf[1] >> 16;
- // v1.x = gpu->buf[2] & 0xffff;
- // v1.y = gpu->buf[2] >> 16;
- // }
-
- // gpu->prev_line_vertex = v1;
-
- // gpu_render_flat_line(gpu, v0, v1, gpu->buf[0] & 0xffffff);
-
- // gpu->buf_index = 1;
- // }
- } else if (!gpu->cmd_args_remaining) {
- vertex_t v0, v1;
-
- if (gpu->buf[0] & 0x10000000) {
- v0.c = gpu->buf[0] & 0xffffff;
- v1.c = gpu->buf[2] & 0xffffff;
- v0.x = gpu->buf[1] & 0xffff;
- v0.y = gpu->buf[1] >> 16;
- v1.x = gpu->buf[3] & 0xffff;
- v1.y = gpu->buf[3] >> 16;
- } else {
- v0.c = gpu->buf[0] & 0xffffff;
- v1.c = gpu->buf[0] & 0xffffff;
- v0.x = gpu->buf[1] & 0xffff;
- v0.y = gpu->buf[1] >> 16;
- v1.x = gpu->buf[2] & 0xffff;
- v1.y = gpu->buf[2] >> 16;
- }
-
- gpu_render_flat_line(gpu, v0, v1, BGR555(gpu->buf[0] & 0xffffff));
-
- gpu->state = GPU_STATE_RECV_CMD;
- }
- } break;
- }
-}
-
-void gpu_cmd_a0(psx_gpu_t* gpu) {
- switch (gpu->state) {
- case GPU_STATE_RECV_CMD: {
- gpu->state = GPU_STATE_RECV_ARGS;
- gpu->cmd_args_remaining = 2;
- } break;
-
- case GPU_STATE_RECV_ARGS: {
- if (!gpu->cmd_args_remaining) {
- gpu->state = GPU_STATE_RECV_DATA;
-
- // Save static data
- gpu->xpos = gpu->buf[1] & 0x3ff;
- gpu->ypos = (gpu->buf[1] >> 16) & 0x1ff;
- gpu->xsiz = gpu->buf[2] & 0xffff;
- gpu->ysiz = gpu->buf[2] >> 16;
- gpu->xsiz = ((gpu->xsiz - 1) & 0x3ff) + 1;
- gpu->ysiz = ((gpu->ysiz - 1) & 0x1ff) + 1;
- gpu->tsiz = ((gpu->xsiz * gpu->ysiz) + 1) & 0xfffffffe;
- gpu->addr = gpu->xpos + (gpu->ypos * 1024);
- gpu->xcnt = 0;
- gpu->ycnt = 0;
- }
- } break;
-
- case GPU_STATE_RECV_DATA: {
- unsigned int xpos = (gpu->xpos + gpu->xcnt) & 0x3ff;
- unsigned int ypos = (gpu->ypos + gpu->ycnt) & 0x1ff;
-
- gpu->vram[xpos + (ypos * 1024)] = gpu->recv_data & 0xffff;
-
- ++gpu->xcnt;
-
- xpos = (gpu->xpos + gpu->xcnt) & 0x3ff;
- ypos = (gpu->ypos + gpu->ycnt) & 0x1ff;
-
- if (gpu->xcnt == gpu->xsiz) {
- ++gpu->ycnt;
- gpu->xcnt = 0;
-
- ypos = (gpu->ypos + gpu->ycnt) & 0x1ff;
- xpos = (gpu->xpos + gpu->xcnt) & 0x3ff;
- }
-
- gpu->vram[xpos + (ypos * 1024)] = gpu->recv_data >> 16;
-
- ++gpu->xcnt;
-
+
+ a.x += gpu->off_x;
+ a.y += gpu->off_y;
+
+ int xmin = max(a.x, gpu->draw_x1);
+ int ymin = max(a.y, gpu->draw_y1);
+ int xmax = min(xmin + w, gpu->draw_x2);
+ int ymax = min(ymin + h, gpu->draw_y2);
+
+ uint32_t xc = 0, yc = 0;
+
+ for (int y = ymin; y < ymax; y++) {+ for (int x = xmin; x < xmax; x++) {+ uint16_t texel = gpu_fetch_texel(
+ gpu,
+ a.tx + xc, a.ty + yc,
+ gpu->texp_x, gpu->texp_y,
+ clutx, cluty,
+ gpu->texp_d
+ );
+
+ ++xc;
+
+ gpu->vram[x + (y * 1024)] = texel;
+ }
+
+ xc = 0;
+
+ ++yc;
+ }
+}
+
+void gpu_render_flat_triangle(psx_gpu_t* gpu, vertex_t v0, vertex_t v1, vertex_t v2, uint32_t color) {+ vertex_t a, b, c;
+
+ a = v0;
+
+ /* Ensure the winding order is correct */
+ if (EDGE(v0, v1, v2) < 0) {+ b = v2;
+ c = v1;
+ } else {+ b = v1;
+ c = v2;
+ }
+
+ a.x += gpu->off_x;
+ a.y += gpu->off_y;
+ b.x += gpu->off_x;
+ b.y += gpu->off_y;
+ c.x += gpu->off_x;
+ c.y += gpu->off_y;
+
+ int xmin = max(min(min(a.x, b.x), c.x), gpu->draw_x1);
+ int ymin = max(min(min(a.y, b.y), c.y), gpu->draw_y1);
+ int xmax = min(max(max(a.x, b.x), c.x), gpu->draw_x2);
+ int ymax = min(max(max(a.y, b.y), c.y), gpu->draw_y2);
+
+ for (int y = ymin; y < ymax; y++) {+ for (int x = xmin; x < xmax; x++) {+ int z0 = ((b.x - a.x) * (y - a.y)) - ((b.y - a.y) * (x - a.x));
+ int z1 = ((c.x - b.x) * (y - b.y)) - ((c.y - b.y) * (x - b.x));
+ int z2 = ((a.x - c.x) * (y - c.y)) - ((a.y - c.y) * (x - c.x));
+
+ if ((z0 >= 0) && (z1 >= 0) && (z2 >= 0)) {+ gpu->vram[x + (y * 1024)] = BGR555(color);
+ }
+ }
+ }
+}
+
+void gpu_render_shaded_triangle(psx_gpu_t* gpu, vertex_t v0, vertex_t v1, vertex_t v2) {+ vertex_t a, b, c, p;
+
+ a = v0;
+
+ /* Ensure the winding order is correct */
+ if (EDGE(v0, v1, v2) < 0) {+ b = v2;
+ c = v1;
+ } else {+ b = v1;
+ c = v2;
+ }
+
+ a.x += gpu->off_x;
+ a.y += gpu->off_y;
+ b.x += gpu->off_x;
+ b.y += gpu->off_y;
+ c.x += gpu->off_x;
+ c.y += gpu->off_y;
+
+ int xmin = max(min(min(a.x, b.x), c.x), gpu->draw_x1);
+ int ymin = max(min(min(a.y, b.y), c.y), gpu->draw_y1);
+ int xmax = min(max(max(a.x, b.x), c.x), gpu->draw_x2);
+ int ymax = min(max(max(a.y, b.y), c.y), gpu->draw_y2);
+
+ int area = EDGE(a, b, c);
+
+ for (int y = ymin; y < ymax; y++) {+ for (int x = xmin; x < xmax; x++) {+ p.x = x;
+ p.y = y;
+
+ float z0 = EDGE((float)b, (float)c, (float)p);
+ float z1 = EDGE((float)c, (float)a, (float)p);
+ float z2 = EDGE((float)a, (float)b, (float)p);
+
+ if ((z0 >= 0) && (z1 >= 0) && (z2 >= 0)) {+ int cr = (z0 * ((a.c >> 0) & 0xff) + z1 * ((b.c >> 0) & 0xff) + z2 * ((c.c >> 0) & 0xff)) / area;
+ int cg = (z0 * ((a.c >> 8) & 0xff) + z1 * ((b.c >> 8) & 0xff) + z2 * ((c.c >> 8) & 0xff)) / area;
+ int cb = (z0 * ((a.c >> 16) & 0xff) + z1 * ((b.c >> 16) & 0xff) + z2 * ((c.c >> 16) & 0xff)) / area;
+
+ // Calculate positions within our 4x4 dither
+ // kernel
+ int dy = (y - ymin) % 4;
+ int dx = (x - xmin) % 4;
+
+ // Shift two pixels horizontally on the last
+ // two scanlines?
+ // if (dy > 1) {+ // dx = ((x + 2) - xmin) % 4;
+ // }
+
+ int dither = g_psx_gpu_dither_kernel[dx + (dy * 4)];
+
+ // Add to the original 8-bit color values
+ cr += dither;
+ cg += dither;
+ cb += dither;
+
+ // Saturate (clamp) to 00-ff
+ cr = (cr >= 0xff) ? 0xff : ((cr <= 0) ? 0 : cr);
+ cg = (cg >= 0xff) ? 0xff : ((cg <= 0) ? 0 : cg);
+ cb = (cb >= 0xff) ? 0xff : ((cb <= 0) ? 0 : cb);
+
+ uint32_t color = (cb << 16) | (cg << 8) | cr;
+
+ gpu->vram[x + (y * 1024)] = BGR555(color);
+ }
+ }
+ }
+}
+
+void gpu_render_textured_triangle(psx_gpu_t* gpu, vertex_t v0, vertex_t v1, vertex_t v2, uint32_t tpx, uint32_t tpy, uint16_t clutx, uint16_t cluty, int depth) {+ vertex_t a, b, c;
+
+ a = v0;
+
+ /* Ensure the winding order is correct */
+ if (EDGE(v0, v1, v2) < 0) {+ b = v2;
+ c = v1;
+ } else {+ b = v1;
+ c = v2;
+ }
+
+ a.x += gpu->off_x;
+ a.y += gpu->off_y;
+ b.x += gpu->off_x;
+ b.y += gpu->off_y;
+ c.x += gpu->off_x;
+ c.y += gpu->off_y;
+
+ int xmin = max(min(min(a.x, b.x), c.x), gpu->draw_x1);
+ int ymin = max(min(min(a.y, b.y), c.y), gpu->draw_y1);
+ int xmax = min(max(max(a.x, b.x), c.x), gpu->draw_x2);
+ int ymax = min(max(max(a.y, b.y), c.y), gpu->draw_y2);
+
+ uint32_t area = EDGE(a, b, c);
+
+ for (int y = ymin; y < ymax; y++) {+ for (int x = xmin; x < xmax; x++) {+ vertex_t p;
+
+ p.x = x;
+ p.y = y;
+
+ float z0 = EDGE((float)b, (float)c, (float)p);
+ float z1 = EDGE((float)c, (float)a, (float)p);
+ float z2 = EDGE((float)a, (float)b, (float)p);
+
+ if ((z0 >= 0) && (z1 >= 0) && (z2 >= 0)) {+ uint32_t tx = ((z0 * a.tx) + (z1 * b.tx) + (z2 * c.tx)) / area;
+ uint32_t ty = ((z0 * a.ty) + (z1 * b.ty) + (z2 * c.ty)) / area;
+
+ uint16_t color = gpu_fetch_texel(
+ gpu,
+ tx, ty,
+ tpx, tpy,
+ clutx, cluty,
+ depth
+ );
+
+ if (!color) continue;
+
+ gpu->vram[x + (y * 1024)] = color;
+ }
+ }
+ }
+}
+
+#define I32(v, b) (((int32_t)((v) << (31-b))) >> (31-b))
+
+void gpu_rect(psx_gpu_t* gpu) {+ switch (gpu->state) {+ case GPU_STATE_RECV_CMD: {+ gpu->state = GPU_STATE_RECV_ARGS;
+
+ int size = (gpu->buf[0] >> 27) & 3;
+ int textured = (gpu->buf[0] & 0x04000000) != 0;
+
+ gpu->cmd_args_remaining = 1 + (size == RS_VARIABLE) + textured;
+ } break;
+
+ case GPU_STATE_RECV_ARGS: {+ if (!gpu->cmd_args_remaining) {+ rect_data_t rect;
+
+ rect.attrib = gpu->buf[0] >> 24;
+
+ int textured = (rect.attrib & RA_TEXTURED) != 0;
+ int raw = (rect.attrib & RA_RAW) != 0;
+
+ // Add 1 if is textured
+ int size_offset = 2 + textured;
+
+ rect.v0.c = gpu->buf[0] & 0xffffff;
+ rect.v0.x = SE10(gpu->buf[1] & 0xffff);
+ rect.v0.y = SE10(gpu->buf[1] >> 16);
+ rect.v0.tx = (gpu->buf[2] >> 0) & 0xff;
+ rect.v0.ty = (gpu->buf[2] >> 8) & 0xff;
+ rect.clut = gpu->buf[2] >> 16;
+ rect.width = gpu->buf[size_offset] & 0xffff;
+ rect.height = gpu->buf[size_offset] >> 16;
+
+ if (textured && raw)
+ rect.v0.c = 0x808080;
+
+ gpu_render_rect(gpu, rect);
+
+ gpu->state = GPU_STATE_RECV_CMD;
+ }
+ } break;
+ }
+}
+
+void gpu_poly(psx_gpu_t* gpu) {+ switch (gpu->state) {+ case GPU_STATE_RECV_CMD: {+ gpu->state = GPU_STATE_RECV_ARGS;
+
+ int shaded = (gpu->buf[0] & 0x10000000) != 0;
+ int quad = (gpu->buf[0] & 0x08000000) != 0;
+ int textured = (gpu->buf[0] & 0x04000000) != 0;
+
+ int fields_per_vertex = 1 + shaded + textured;
+ int vertices = 3 + quad;
+
+ gpu->cmd_args_remaining = (fields_per_vertex * vertices) - shaded;
+ } break;
+
+ case GPU_STATE_RECV_ARGS: {+ if (!gpu->cmd_args_remaining) {+ poly_data_t poly;
+
+ poly.attrib = gpu->buf[0] >> 24;
+
+ int shaded = (poly.attrib & PA_SHADED) != 0;
+ int textured = (poly.attrib & PA_TEXTURED) != 0;
+
+ int color_offset = shaded * (2 + textured);
+ int vert_offset = 1 + (textured | shaded) +
+ (textured & shaded);
+ int texc_offset = textured * (2 + shaded);
+ int texp_offset = textured * (4 + shaded);
+
+ poly.clut = gpu->buf[2] >> 16;
+ poly.texp = gpu->buf[texp_offset] >> 16;
+
+ // Undocumented behavior?
+ // Fixes Mortal Kombat II, Bubble Bobble, Driver 1 & 2
+ if (textured) {+ gpu->texp_x = (poly.texp & 0xf) << 6;
+ gpu->texp_y = (poly.texp & 0x10) << 4;
+ gpu->texp_d = (poly.texp >> 7) & 0x3;
+ gpu->gpustat &= 0xfffffe00;
+ gpu->gpustat |= poly.texp & 0x1ff;
+ }
+
+ poly.v[0].c = gpu->buf[0+0*color_offset] & 0xffffff;
+ poly.v[1].c = gpu->buf[0+1*color_offset] & 0xffffff;
+ poly.v[2].c = gpu->buf[0+2*color_offset] & 0xffffff;
+ poly.v[3].c = gpu->buf[0+3*color_offset] & 0xffffff;
+ poly.v[0].x = SE10(gpu->buf[1+0*vert_offset] & 0xffff);
+ poly.v[1].x = SE10(gpu->buf[1+1*vert_offset] & 0xffff);
+ poly.v[2].x = SE10(gpu->buf[1+2*vert_offset] & 0xffff);
+ poly.v[3].x = SE10(gpu->buf[1+3*vert_offset] & 0xffff);
+ poly.v[0].y = SE10(gpu->buf[1+0*vert_offset] >> 16);
+ poly.v[1].y = SE10(gpu->buf[1+1*vert_offset] >> 16);
+ poly.v[2].y = SE10(gpu->buf[1+2*vert_offset] >> 16);
+ poly.v[3].y = SE10(gpu->buf[1+3*vert_offset] >> 16);
+ poly.v[0].tx = gpu->buf[2+0*texc_offset] & 0xff;
+ poly.v[1].tx = gpu->buf[2+1*texc_offset] & 0xff;
+ poly.v[2].tx = gpu->buf[2+2*texc_offset] & 0xff;
+ poly.v[3].tx = gpu->buf[2+3*texc_offset] & 0xff;
+ poly.v[0].ty = (gpu->buf[2+0*texc_offset] >> 8) & 0xff;
+ poly.v[1].ty = (gpu->buf[2+1*texc_offset] >> 8) & 0xff;
+ poly.v[2].ty = (gpu->buf[2+2*texc_offset] >> 8) & 0xff;
+ poly.v[3].ty = (gpu->buf[2+3*texc_offset] >> 8) & 0xff;
+
+ if (poly.attrib & PA_QUAD) {+ gpu_render_triangle(gpu, poly.v[0], poly.v[1], poly.v[2], poly, 1);
+ gpu_render_triangle(gpu, poly.v[1], poly.v[2], poly.v[3], poly, 1);
+ } else {+ gpu_render_triangle(gpu, poly.v[0], poly.v[1], poly.v[2], poly, 0);
+ }
+
+ gpu->state = GPU_STATE_RECV_CMD;
+ }
+ } break;
+ }
+}
+
+void gpu_line(psx_gpu_t* gpu) {+ switch (gpu->state) {+ case GPU_STATE_RECV_CMD: {+ gpu->state = GPU_STATE_RECV_ARGS;
+
+ int shaded = (gpu->buf[0] & 0x10000000) != 0;
+ int polyline = (gpu->buf[0] & 0x08000000) != 0;
+
+ gpu->cmd_args_remaining = polyline ? -1 : (shaded ? 3 : 2);
+ gpu->line_done = 0;
+ } break;
+
+ case GPU_STATE_RECV_ARGS: {+ if (gpu->buf[0] & 0x08000000) {+ if ((gpu->buf[gpu->buf_index - 1] & 0xf000f000) == 0x50005000) {+ gpu->state = GPU_STATE_RECV_CMD;
+
+ return;
+ }
+
+ // int shaded = (gpu->buf[0] & 0x10000000) != 0;
+
+ // if (shaded) {+ // if (gpu->buf_index > 2) {+
+ // }
+ // }
+
+ // if (gpu->buf_index > overflow) {+ // vertex_t v0, v1;
+
+ // if (shaded) {+ // v0.c = gpu->buf[0] & 0xffffff;
+ // v1.c = gpu->buf[4] & 0xffffff;
+ // v0.x = gpu->buf[1] & 0xffff;
+ // v0.y = gpu->buf[1] >> 16;
+ // v1.x = gpu->buf[3] & 0xffff;
+ // v1.y = gpu->buf[3] >> 16;
+ // } else {+ // v0.c = gpu->buf[0] & 0xffffff;
+ // v1.c = gpu->buf[0] & 0xffffff;
+ // v0.x = gpu->buf[1] & 0xffff;
+ // v0.y = gpu->buf[1] >> 16;
+ // v1.x = gpu->buf[2] & 0xffff;
+ // v1.y = gpu->buf[2] >> 16;
+ // }
+
+ // gpu->prev_line_vertex = v1;
+
+ // gpu_render_flat_line(gpu, v0, v1, gpu->buf[0] & 0xffffff);
+
+ // gpu->buf_index = 1;
+ // }
+ } else if (!gpu->cmd_args_remaining) {+ vertex_t v0, v1;
+
+ if (gpu->buf[0] & 0x10000000) {+ v0.c = gpu->buf[0] & 0xffffff;
+ v1.c = gpu->buf[2] & 0xffffff;
+ v0.x = gpu->buf[1] & 0xffff;
+ v0.y = gpu->buf[1] >> 16;
+ v1.x = gpu->buf[3] & 0xffff;
+ v1.y = gpu->buf[3] >> 16;
+ } else {+ v0.c = gpu->buf[0] & 0xffffff;
+ v1.c = gpu->buf[0] & 0xffffff;
+ v0.x = gpu->buf[1] & 0xffff;
+ v0.y = gpu->buf[1] >> 16;
+ v1.x = gpu->buf[2] & 0xffff;
+ v1.y = gpu->buf[2] >> 16;
+ }
+
+ gpu_render_flat_line(gpu, v0, v1, BGR555(gpu->buf[0] & 0xffffff));
+
+ gpu->state = GPU_STATE_RECV_CMD;
+ }
+ } break;
+ }
+}
+
+void gpu_cmd_a0(psx_gpu_t* gpu) {+ switch (gpu->state) {+ case GPU_STATE_RECV_CMD: {+ gpu->state = GPU_STATE_RECV_ARGS;
+ gpu->cmd_args_remaining = 2;
+ } break;
+
+ case GPU_STATE_RECV_ARGS: {+ if (!gpu->cmd_args_remaining) {+ gpu->state = GPU_STATE_RECV_DATA;
+
+ // Save static data
+ gpu->xpos = gpu->buf[1] & 0x3ff;
+ gpu->ypos = (gpu->buf[1] >> 16) & 0x1ff;
+ gpu->xsiz = gpu->buf[2] & 0xffff;
+ gpu->ysiz = gpu->buf[2] >> 16;
+ gpu->xsiz = ((gpu->xsiz - 1) & 0x3ff) + 1;
+ gpu->ysiz = ((gpu->ysiz - 1) & 0x1ff) + 1;
+ gpu->tsiz = ((gpu->xsiz * gpu->ysiz) + 1) & 0xfffffffe;
+ gpu->addr = gpu->xpos + (gpu->ypos * 1024);
+ gpu->xcnt = 0;
+ gpu->ycnt = 0;
+ }
+ } break;
+
+ case GPU_STATE_RECV_DATA: {+ unsigned int xpos = (gpu->xpos + gpu->xcnt) & 0x3ff;
+ unsigned int ypos = (gpu->ypos + gpu->ycnt) & 0x1ff;
+
+ gpu->vram[xpos + (ypos * 1024)] = gpu->recv_data & 0xffff;
+
+ ++gpu->xcnt;
+
+ xpos = (gpu->xpos + gpu->xcnt) & 0x3ff;
+ ypos = (gpu->ypos + gpu->ycnt) & 0x1ff;
+
if (gpu->xcnt == gpu->xsiz) {++gpu->ycnt;
gpu->xcnt = 0;
+
+ ypos = (gpu->ypos + gpu->ycnt) & 0x1ff;
+ xpos = (gpu->xpos + gpu->xcnt) & 0x3ff;
}
-
- gpu->tsiz -= 2;
-
- if (!gpu->tsiz) {
- gpu->xcnt = 0;
- gpu->ycnt = 0;
- gpu->state = GPU_STATE_RECV_CMD;
- }
- } break;
- }
-}
-
-// Monochrome Opaque Quadrilateral
-void gpu_cmd_28(psx_gpu_t* gpu) {
- switch (gpu->state) {
- case GPU_STATE_RECV_CMD: {
- gpu->state = GPU_STATE_RECV_ARGS;
- gpu->cmd_args_remaining = 4;
- } break;
-
- case GPU_STATE_RECV_ARGS: {
- if (!gpu->cmd_args_remaining) {
- gpu->state = GPU_STATE_RECV_DATA;
-
- gpu->v0.x = gpu->buf[1] & 0xffff;
- gpu->v0.y = gpu->buf[1] >> 16;
- gpu->v1.x = gpu->buf[2] & 0xffff;
- gpu->v1.y = gpu->buf[2] >> 16;
- gpu->v2.x = gpu->buf[3] & 0xffff;
- gpu->v2.y = gpu->buf[3] >> 16;
- gpu->v3.x = gpu->buf[4] & 0xffff;
- gpu->v3.y = gpu->buf[4] >> 16;
- gpu->color = gpu->buf[0] & 0xffffff;
-
- gpu_render_flat_triangle(gpu, gpu->v0, gpu->v1, gpu->v2, gpu->color);
- gpu_render_flat_triangle(gpu, gpu->v1, gpu->v2, gpu->v3, gpu->color);
-
- gpu->state = GPU_STATE_RECV_CMD;
- }
- } break;
- }
-}
-
-// Monochrome Opaque Quadrilateral
-void gpu_cmd_30(psx_gpu_t* gpu) {
- switch (gpu->state) {
- case GPU_STATE_RECV_CMD: {
- gpu->state = GPU_STATE_RECV_ARGS;
- gpu->cmd_args_remaining = 5;
- } break;
-
- case GPU_STATE_RECV_ARGS: {
- if (!gpu->cmd_args_remaining) {
- gpu->state = GPU_STATE_RECV_DATA;
-
- gpu->v0.c = gpu->buf[0] & 0xffffff;
- gpu->v0.x = gpu->buf[1] & 0xffff;
- gpu->v0.y = gpu->buf[1] >> 16;
- gpu->v1.c = gpu->buf[2] & 0xffffff;
- gpu->v1.x = gpu->buf[3] & 0xffff;
- gpu->v1.y = gpu->buf[3] >> 16;
- gpu->v2.c = gpu->buf[4] & 0xffffff;
- gpu->v2.x = gpu->buf[5] & 0xffff;
- gpu->v2.y = gpu->buf[5] >> 16;
-
- gpu_render_shaded_triangle(gpu, gpu->v0, gpu->v1, gpu->v2);
-
- gpu->state = GPU_STATE_RECV_CMD;
- }
- } break;
- }
-}
-
-// Monochrome Opaque Quadrilateral
-void gpu_cmd_38(psx_gpu_t* gpu) {
- switch (gpu->state) {
- case GPU_STATE_RECV_CMD: {
- gpu->state = GPU_STATE_RECV_ARGS;
- gpu->cmd_args_remaining = 7;
- } break;
-
- case GPU_STATE_RECV_ARGS: {
- if (!gpu->cmd_args_remaining) {
- gpu->state = GPU_STATE_RECV_DATA;
-
- gpu->v0.c = gpu->buf[0] & 0xffffff;
- gpu->v0.x = gpu->buf[1] & 0xffff;
- gpu->v0.y = gpu->buf[1] >> 16;
- gpu->v1.c = gpu->buf[2] & 0xffffff;
- gpu->v1.x = gpu->buf[3] & 0xffff;
- gpu->v1.y = gpu->buf[3] >> 16;
- gpu->v2.c = gpu->buf[4] & 0xffffff;
- gpu->v2.x = gpu->buf[5] & 0xffff;
- gpu->v2.y = gpu->buf[5] >> 16;
- gpu->v3.c = gpu->buf[6] & 0xffffff;
- gpu->v3.x = gpu->buf[7] & 0xffff;
- gpu->v3.y = gpu->buf[7] >> 16;
-
- gpu_render_shaded_triangle(gpu, gpu->v0, gpu->v1, gpu->v2);
- gpu_render_shaded_triangle(gpu, gpu->v1, gpu->v2, gpu->v3);
-
- gpu->state = GPU_STATE_RECV_CMD;
- }
- } break;
- }
-}
-
-// Monochrome Opaque Quadrilateral
-void gpu_cmd_3c(psx_gpu_t* gpu) {
- switch (gpu->state) {
- case GPU_STATE_RECV_CMD: {
- gpu->state = GPU_STATE_RECV_ARGS;
- gpu->cmd_args_remaining = 11;
- } break;
-
- case GPU_STATE_RECV_ARGS: {
- if (!gpu->cmd_args_remaining) {
- gpu->state = GPU_STATE_RECV_DATA;
-
- uint32_t texp = gpu->buf[5] >> 16;
- gpu->color = gpu->buf[0] & 0xffffff;
- gpu->pal = gpu->buf[2] >> 16;
- gpu->v0.tx = gpu->buf[2] & 0xff;
- gpu->v0.ty = (gpu->buf[2] >> 8) & 0xff;
- gpu->v1.tx = gpu->buf[5] & 0xff;
- gpu->v1.ty = (gpu->buf[5] >> 8) & 0xff;
- gpu->v2.tx = gpu->buf[8] & 0xff;
- gpu->v2.ty = (gpu->buf[8] >> 8) & 0xff;
- gpu->v3.tx = gpu->buf[11] & 0xff;
- gpu->v3.ty = (gpu->buf[11] >> 8) & 0xff;
- gpu->v0.x = gpu->buf[1] & 0xffff;
- gpu->v0.y = gpu->buf[1] >> 16;
- gpu->v1.x = gpu->buf[4] & 0xffff;
- gpu->v1.y = gpu->buf[4] >> 16;
- gpu->v2.x = gpu->buf[7] & 0xffff;
- gpu->v2.y = gpu->buf[7] >> 16;
- gpu->v3.x = gpu->buf[10] & 0xffff;
- gpu->v3.y = gpu->buf[10] >> 16;
-
- uint16_t clutx = (gpu->pal & 0x3f) << 4;
- uint16_t cluty = (gpu->pal >> 6) & 0x1ff;
- uint16_t tpx = (texp & 0xf) << 6;
- uint16_t tpy = (texp & 0x10) << 4;
- uint16_t depth = (texp >> 7) & 0x3;
-
- gpu_render_textured_triangle(gpu, gpu->v0, gpu->v1, gpu->v2, tpx, tpy, clutx, cluty, depth);
- gpu_render_textured_triangle(gpu, gpu->v1, gpu->v2, gpu->v3, tpx, tpy, clutx, cluty, depth);
-
- gpu->state = GPU_STATE_RECV_CMD;
- }
- } break;
- }
-}
-
-// Monochrome Opaque Quadrilateral
-void gpu_cmd_2c(psx_gpu_t* gpu) {
- switch (gpu->state) {
- case GPU_STATE_RECV_CMD: {
- gpu->state = GPU_STATE_RECV_ARGS;
- gpu->cmd_args_remaining = 8;
- } break;
-
- case GPU_STATE_RECV_ARGS: {
- if (!gpu->cmd_args_remaining) {
- gpu->state = GPU_STATE_RECV_DATA;
-
- uint32_t texp = gpu->buf[4] >> 16;
- gpu->color = gpu->buf[0] & 0xffffff;
- gpu->pal = gpu->buf[2] >> 16;
- gpu->v0.tx = gpu->buf[2] & 0xff;
- gpu->v0.ty = (gpu->buf[2] >> 8) & 0xff;
- gpu->v1.tx = gpu->buf[4] & 0xff;
- gpu->v1.ty = (gpu->buf[4] >> 8) & 0xff;
- gpu->v2.tx = gpu->buf[6] & 0xff;
- gpu->v2.ty = (gpu->buf[6] >> 8) & 0xff;
- gpu->v3.tx = gpu->buf[8] & 0xff;
- gpu->v3.ty = (gpu->buf[8] >> 8) & 0xff;
- gpu->v0.x = gpu->buf[1] & 0xffff;
- gpu->v0.y = gpu->buf[1] >> 16;
- gpu->v1.x = gpu->buf[3] & 0xffff;
- gpu->v1.y = gpu->buf[3] >> 16;
- gpu->v2.x = gpu->buf[5] & 0xffff;
- gpu->v2.y = gpu->buf[5] >> 16;
- gpu->v3.x = gpu->buf[7] & 0xffff;
- gpu->v3.y = gpu->buf[7] >> 16;
-
- uint16_t clutx = (gpu->pal & 0x3f) << 4;
- uint16_t cluty = (gpu->pal >> 6) & 0x1ff;
- uint16_t tpx = (texp & 0xf) << 6;
- uint16_t tpy = (texp & 0x10) << 4;
- uint16_t depth = (texp >> 7) & 0x3;
-
- gpu_render_textured_triangle(gpu, gpu->v0, gpu->v1, gpu->v2, tpx, tpy, clutx, cluty, depth);
- gpu_render_textured_triangle(gpu, gpu->v1, gpu->v2, gpu->v3, tpx, tpy, clutx, cluty, depth);
-
- gpu->state = GPU_STATE_RECV_CMD;
- }
- } break;
- }
-}
-
-// Monochrome Opaque Quadrilateral
-void gpu_cmd_24(psx_gpu_t* gpu) {
- switch (gpu->state) {
- case GPU_STATE_RECV_CMD: {
- gpu->state = GPU_STATE_RECV_ARGS;
- gpu->cmd_args_remaining = 6;
- } break;
-
- case GPU_STATE_RECV_ARGS: {
- if (!gpu->cmd_args_remaining) {
- gpu->state = GPU_STATE_RECV_DATA;
-
- uint32_t texp = gpu->buf[4] >> 16;
- gpu->color = gpu->buf[0] & 0xffffff;
- gpu->pal = gpu->buf[2] >> 16;
- gpu->v0.tx = gpu->buf[2] & 0xff;
- gpu->v0.ty = (gpu->buf[2] >> 8) & 0xff;
- gpu->v1.tx = gpu->buf[4] & 0xff;
- gpu->v1.ty = (gpu->buf[4] >> 8) & 0xff;
- gpu->v2.tx = gpu->buf[6] & 0xff;
- gpu->v2.ty = (gpu->buf[6] >> 8) & 0xff;
- gpu->v0.x = gpu->buf[1] & 0xffff;
- gpu->v0.y = gpu->buf[1] >> 16;
- gpu->v1.x = gpu->buf[3] & 0xffff;
- gpu->v1.y = gpu->buf[3] >> 16;
- gpu->v2.x = gpu->buf[5] & 0xffff;
- gpu->v2.y = gpu->buf[5] >> 16;
-
- uint16_t clutx = (gpu->pal & 0x3f) << 4;
- uint16_t cluty = (gpu->pal >> 6) & 0x1ff;
- uint16_t tpx = (texp & 0xf) << 6;
- uint16_t tpy = (texp & 0x10) << 4;
- uint16_t depth = (texp >> 7) & 0x3;
-
- gpu_render_textured_triangle(gpu, gpu->v0, gpu->v1, gpu->v2, tpx, tpy, clutx, cluty, depth);
- gpu_render_textured_triangle(gpu, gpu->v1, gpu->v2, gpu->v3, tpx, tpy, clutx, cluty, depth);
-
- gpu->state = GPU_STATE_RECV_CMD;
- }
- } break;
- }
-}
-
-// Monochrome Opaque Quadrilateral
-void gpu_cmd_2d(psx_gpu_t* gpu) {
- switch (gpu->state) {
- case GPU_STATE_RECV_CMD: {
- gpu->state = GPU_STATE_RECV_ARGS;
- gpu->cmd_args_remaining = 8;
- } break;
-
- case GPU_STATE_RECV_ARGS: {
- if (!gpu->cmd_args_remaining) {
- gpu->state = GPU_STATE_RECV_DATA;
-
- uint32_t texp = gpu->buf[4] >> 16;
- gpu->color = gpu->buf[0] & 0xffffff;
- gpu->pal = gpu->buf[2] >> 16;
- gpu->v0.tx = gpu->buf[2] & 0xff;
- gpu->v0.ty = (gpu->buf[2] >> 8) & 0xff;
- gpu->v1.tx = gpu->buf[4] & 0xff;
- gpu->v1.ty = (gpu->buf[4] >> 8) & 0xff;
- gpu->v2.tx = gpu->buf[6] & 0xff;
- gpu->v2.ty = (gpu->buf[6] >> 8) & 0xff;
- gpu->v3.tx = gpu->buf[8] & 0xff;
- gpu->v3.ty = (gpu->buf[8] >> 8) & 0xff;
- gpu->v0.x = gpu->buf[1] & 0xffff;
- gpu->v0.y = gpu->buf[1] >> 16;
- gpu->v1.x = gpu->buf[3] & 0xffff;
- gpu->v1.y = gpu->buf[3] >> 16;
- gpu->v2.x = gpu->buf[5] & 0xffff;
- gpu->v2.y = gpu->buf[5] >> 16;
- gpu->v3.x = gpu->buf[7] & 0xffff;
- gpu->v3.y = gpu->buf[7] >> 16;
-
- uint16_t clutx = (gpu->pal & 0x3f) << 4;
- uint16_t cluty = (gpu->pal >> 6) & 0x1ff;
- uint16_t tpx = (texp & 0xf) << 6;
- uint16_t tpy = (texp & 0x10) << 4;
- uint16_t depth = (texp >> 7) & 0x3;
-
- gpu_render_textured_triangle(gpu, gpu->v0, gpu->v1, gpu->v2, tpx, tpy, clutx, cluty, depth);
- gpu_render_textured_triangle(gpu, gpu->v1, gpu->v2, gpu->v3, tpx, tpy, clutx, cluty, depth);
-
- gpu->state = GPU_STATE_RECV_CMD;
- }
- } break;
- }
-}
-
-void gpu_cmd_64(psx_gpu_t* gpu) {
- switch (gpu->state) {
- case GPU_STATE_RECV_CMD: {
- gpu->state = GPU_STATE_RECV_ARGS;
- gpu->cmd_args_remaining = 3;
- } break;
-
- case GPU_STATE_RECV_ARGS: {
- if (!gpu->cmd_args_remaining) {
- gpu->state = GPU_STATE_RECV_DATA;
-
- gpu->color = gpu->buf[0] & 0xffffff;
- gpu->v0.x = gpu->buf[1] & 0xffff;
- gpu->v0.y = gpu->buf[1] >> 16;
- gpu->v0.tx = gpu->buf[2] & 0xff;
- gpu->v0.ty = (gpu->buf[2] >> 8) & 0xff;
- gpu->pal = gpu->buf[2] >> 16;
-
- uint32_t w = gpu->buf[3] & 0xffff;
- uint32_t h = gpu->buf[3] >> 16;
- uint16_t clutx = (gpu->pal & 0x3f) << 4;
- uint16_t cluty = (gpu->pal >> 6) & 0x1ff;
-
- gpu_render_textured_rectangle(gpu, gpu->v0, w, h, clutx, cluty, gpu->color);
-
- gpu->state = GPU_STATE_RECV_CMD;
- }
- } break;
- }
-}
-
-void gpu_cmd_7c(psx_gpu_t* gpu) {
- switch (gpu->state) {
- case GPU_STATE_RECV_CMD: {
- gpu->state = GPU_STATE_RECV_ARGS;
- gpu->cmd_args_remaining = 2;
- } break;
-
- case GPU_STATE_RECV_ARGS: {
- if (!gpu->cmd_args_remaining) {
- gpu->state = GPU_STATE_RECV_DATA;
-
- gpu->color = gpu->buf[0] & 0xffffff;
- gpu->v0.x = gpu->buf[1] & 0xffff;
- gpu->v0.y = gpu->buf[1] >> 16;
- gpu->v0.tx = gpu->buf[2] & 0xff;
- gpu->v0.ty = (gpu->buf[2] >> 8) & 0xff;
- gpu->pal = gpu->buf[2] >> 16;
-
- uint32_t w = 16;
- uint32_t h = 16;
- uint16_t clutx = (gpu->pal & 0x3f) << 4;
- uint16_t cluty = (gpu->pal >> 6) & 0x1ff;
-
- gpu_render_textured_rectangle(gpu, gpu->v0, w, h, clutx, cluty, gpu->color);
-
- gpu->state = GPU_STATE_RECV_CMD;
- }
- } break;
- }
-}
-
-void gpu_cmd_74(psx_gpu_t* gpu) {
- switch (gpu->state) {
- case GPU_STATE_RECV_CMD: {
- gpu->state = GPU_STATE_RECV_ARGS;
- gpu->cmd_args_remaining = 2;
- } break;
-
- case GPU_STATE_RECV_ARGS: {
- if (!gpu->cmd_args_remaining) {
- gpu->state = GPU_STATE_RECV_DATA;
-
- gpu->color = gpu->buf[0] & 0xffffff;
- gpu->v0.x = gpu->buf[1] & 0xffff;
- gpu->v0.y = gpu->buf[1] >> 16;
- gpu->v0.tx = gpu->buf[2] & 0xff;
- gpu->v0.ty = (gpu->buf[2] >> 8) & 0xff;
- gpu->pal = gpu->buf[2] >> 16;
-
- uint32_t w = 8;
- uint32_t h = 8;
- uint16_t clutx = (gpu->pal & 0x3f) << 4;
- uint16_t cluty = (gpu->pal >> 6) & 0x1ff;
-
- gpu_render_textured_rectangle(gpu, gpu->v0, w, h, clutx, cluty, gpu->color);
-
- gpu->state = GPU_STATE_RECV_CMD;
- }
- } break;
- }
-}
-
-void gpu_cmd_60(psx_gpu_t* gpu) {
- switch (gpu->state) {
- case GPU_STATE_RECV_CMD: {
- gpu->state = GPU_STATE_RECV_ARGS;
- gpu->cmd_args_remaining = 2;
- } break;
-
- case GPU_STATE_RECV_ARGS: {
- if (!gpu->cmd_args_remaining) {
- gpu->state = GPU_STATE_RECV_DATA;
-
- gpu->color = gpu->buf[0] & 0xffffff;
- gpu->v0.x = gpu->buf[1] & 0xffff;
- gpu->v0.y = gpu->buf[1] >> 16;
- gpu->xsiz = gpu->buf[2] & 0xffff;
- gpu->ysiz = gpu->buf[2] >> 16;
-
- gpu->v0.x += gpu->off_x;
- gpu->v0.y += gpu->off_y;
-
- gpu_render_flat_rectangle(gpu, gpu->v0, gpu->xsiz, gpu->ysiz, BGR555(gpu->color));
-
- gpu->state = GPU_STATE_RECV_CMD;
- }
- } break;
- }
-}
-
-void gpu_cmd_68(psx_gpu_t* gpu) {
- switch (gpu->state) {
- case GPU_STATE_RECV_CMD: {
- gpu->state = GPU_STATE_RECV_ARGS;
- gpu->cmd_args_remaining = 1;
- } break;
-
- case GPU_STATE_RECV_ARGS: {
- if (!gpu->cmd_args_remaining) {
- gpu->state = GPU_STATE_RECV_DATA;
-
- gpu->color = gpu->buf[0] & 0xffffff;
- gpu->v0.x = gpu->buf[1] & 0xffff;
- gpu->v0.y = gpu->buf[1] >> 16;
-
- gpu->v0.x += gpu->off_x;
- gpu->v0.y += gpu->off_y;
-
- gpu->vram[gpu->v0.x + (gpu->v0.y * 1024)] = BGR555(gpu->color);
-
- gpu->state = GPU_STATE_RECV_CMD;
- }
- } break;
- }
-}
-
-void gpu_cmd_40(psx_gpu_t* gpu) {
- switch (gpu->state) {
- case GPU_STATE_RECV_CMD: {
- gpu->state = GPU_STATE_RECV_ARGS;
- gpu->cmd_args_remaining = 2;
- } break;
-
- case GPU_STATE_RECV_ARGS: {
- if (!gpu->cmd_args_remaining) {
- gpu->color = gpu->buf[0] & 0xffffff;
- gpu->v0.x = gpu->buf[1] & 0xffff;
- gpu->v0.y = gpu->buf[1] >> 16;
- gpu->v1.x = gpu->buf[2] & 0xffff;
- gpu->v1.y = gpu->buf[2] >> 16;
-
- gpu_render_flat_line(gpu, gpu->v0, gpu->v1, BGR555(gpu->color));
-
- gpu->state = GPU_STATE_RECV_CMD;
- }
- } break;
- }
-}
-
-void gpu_cmd_c0(psx_gpu_t* gpu) {
- switch (gpu->state) {
- case GPU_STATE_RECV_CMD: {
- gpu->state = GPU_STATE_RECV_ARGS;
- gpu->cmd_args_remaining = 2;
- } break;
-
- case GPU_STATE_RECV_ARGS: {
- if (!gpu->cmd_args_remaining) {
- gpu->c0_xcnt = 0;
- gpu->c0_ycnt = 0;
- uint32_t c0_xpos = gpu->buf[1] & 0xffff;
- uint32_t c0_ypos = gpu->buf[1] >> 16;
- gpu->c0_xsiz = gpu->buf[2] & 0xffff;
- gpu->c0_ysiz = gpu->buf[2] >> 16;
- c0_xpos = c0_xpos & 0x3ff;
- c0_ypos = c0_ypos & 0x1ff;
- gpu->c0_xsiz = ((gpu->c0_xsiz - 1) & 0x3ff) + 1;
- gpu->c0_ysiz = ((gpu->c0_ysiz - 1) & 0x1ff) + 1;
- gpu->c0_tsiz = ((gpu->c0_xsiz * gpu->c0_ysiz) + 1) & 0xfffffffe;
- gpu->c0_addr = c0_xpos + (c0_ypos * 1024);
-
- gpu->state = GPU_STATE_RECV_CMD;
- }
- } break;
- }
-}
-
-void gpu_cmd_02(psx_gpu_t* gpu) {
- switch (gpu->state) {
- case GPU_STATE_RECV_CMD: {
- gpu->state = GPU_STATE_RECV_ARGS;
- gpu->cmd_args_remaining = 2;
- } break;
-
- case GPU_STATE_RECV_ARGS: {
- if (!gpu->cmd_args_remaining) {
- gpu->state = GPU_STATE_RECV_DATA;
-
- gpu->color = gpu->buf[0] & 0xffffff;
- gpu->v0.x = gpu->buf[1] & 0xffff;
- gpu->v0.y = gpu->buf[1] >> 16;
- gpu->xsiz = gpu->buf[2] & 0xffff;
- gpu->ysiz = gpu->buf[2] >> 16;
-
- gpu->v0.x = (gpu->v0.x & 0x3f0);
- gpu->v0.y = gpu->v0.y & 0x1ff;
- gpu->xsiz = (((gpu->xsiz & 0x3ff) + 0x0f) & 0xfffffff0);
- gpu->ysiz = gpu->ysiz & 0x1ff;
-
- uint16_t color = BGR555(gpu->color);
-
- // printf("02 draw=(%u,%u-%u,%u) v0=(%u,%u) siz=(%u,%u)\n",
- // gpu->draw_x1,
- // gpu->draw_y1,
- // gpu->draw_x2,
- // gpu->draw_y2,
- // gpu->v0.x,
- // gpu->v0.y,
- // gpu->xsiz,
- // gpu->ysiz
- // );
-
- for (int y = gpu->v0.y; y < (gpu->v0.y + gpu->ysiz); y++) {
- for (int x = gpu->v0.x; x < (gpu->v0.x + gpu->xsiz); x++) {
- // This shouldn't be needed
- // int bc = (x >= gpu->draw_x1) && (x <= gpu->draw_x2) &&
- // (y >= gpu->draw_y1) && (y <= gpu->draw_y2);
-
- // if (!bc)
- // continue;
-
- if ((x < 1024) && (y < 512) && (x >= 0) && (y >= 0))
- gpu->vram[x + (y * 1024)] = color;
- }
- }
-
- gpu->state = GPU_STATE_RECV_CMD;
- }
- } break;
- }
-}
-
-void gpu_cmd_80(psx_gpu_t* gpu) {
- switch (gpu->state) {
- case GPU_STATE_RECV_CMD: {
- gpu->state = GPU_STATE_RECV_ARGS;
- gpu->cmd_args_remaining = 3;
- } break;
-
- case GPU_STATE_RECV_ARGS: {
- if (!gpu->cmd_args_remaining) {
- gpu->state = GPU_STATE_RECV_DATA;
-
- uint32_t srcx = gpu->buf[1] & 0xffff;
- uint32_t srcy = gpu->buf[1] >> 16;
- uint32_t dstx = gpu->buf[2] & 0xffff;
- uint32_t dsty = gpu->buf[2] >> 16;
- uint32_t xsiz = gpu->buf[3] & 0xffff;
- uint32_t ysiz = gpu->buf[3] >> 16;
-
- for (int y = 0; y < ysiz; y++) {
- for (int x = 0; x < xsiz; x++) {
- int dstb = ((dstx + x) < 1024) && ((dsty + y) < 512);
- int srcb = ((srcx + x) < 1024) && ((srcy + y) < 512);
-
- if (dstb && srcb)
- gpu->vram[(dstx + x) + (dsty + y) * 1024] = gpu->vram[(srcx + x) + (srcy + y) * 1024];
- }
- }
-
- gpu->state = GPU_STATE_RECV_CMD;
- }
- } break;
- }
-}
-
-void psx_gpu_update_cmd(psx_gpu_t* gpu) {
- int type = (gpu->buf[0] >> 29) & 7;
-
- switch (type) {
- case 1: gpu_poly(gpu); return;
- case 2: gpu_line(gpu); return;
- case 3: gpu_rect(gpu); return;
- }
-
- switch (gpu->buf[0] >> 24) {
- case 0x00: /* nop */ break;
- case 0x01: /* Cache clear */ break;
- case 0x02: gpu_cmd_02(gpu); break;
- case 0x24: gpu_cmd_24(gpu); break;
- case 0x25: gpu_cmd_24(gpu); break;
- case 0x26: gpu_cmd_24(gpu); break;
- case 0x27: gpu_cmd_24(gpu); break;
- case 0x28: gpu_cmd_28(gpu); break;
- case 0x2a: gpu_cmd_28(gpu); break;
- case 0x2c: gpu_cmd_2d(gpu); break;
- case 0x2d: gpu_cmd_2d(gpu); break;
- case 0x2e: gpu_cmd_2d(gpu); break;
- case 0x2f: gpu_cmd_2d(gpu); break;
- case 0x30: gpu_cmd_30(gpu); break;
- case 0x32: gpu_cmd_30(gpu); break;
- case 0x38: gpu_cmd_38(gpu); break;
- case 0x3c: gpu_cmd_3c(gpu); break;
- case 0x3e: gpu_cmd_3c(gpu); break;
- case 0x40: gpu_cmd_40(gpu); break;
- case 0x60: gpu_cmd_60(gpu); break;
- case 0x62: gpu_cmd_60(gpu); break;
- case 0x64: gpu_cmd_64(gpu); break;
- case 0x65: gpu_cmd_64(gpu); break;
- case 0x66: gpu_cmd_64(gpu); break;
- case 0x67: gpu_cmd_64(gpu); break;
- case 0x68: gpu_cmd_68(gpu); break;
- case 0x74: gpu_cmd_74(gpu); break;
- case 0x75: gpu_cmd_74(gpu); break;
- case 0x76: gpu_cmd_74(gpu); break;
- case 0x77: gpu_cmd_74(gpu); break;
- case 0x7c: gpu_cmd_7c(gpu); break;
- case 0x7d: gpu_cmd_7c(gpu); break;
- case 0x7e: gpu_cmd_7c(gpu); break;
- case 0x7f: gpu_cmd_7c(gpu); break;
- case 0x80: gpu_cmd_80(gpu); break;
- case 0xa0: gpu_cmd_a0(gpu); break;
- case 0xc0: gpu_cmd_c0(gpu); break;
- case 0xe1: {
- gpu->gpustat &= 0xfffff800;
- gpu->gpustat |= gpu->buf[0] & 0x7ff;
- gpu->texp_x = (gpu->gpustat & 0xf) << 6;
- gpu->texp_y = (gpu->gpustat & 0x10) << 4;
- gpu->texp_d = (gpu->gpustat >> 7) & 0x3;
- } break;
- case 0xe2: {
- gpu->texw_mx = ((gpu->buf[0] >> 0 ) & 0x1f) << 3;
- gpu->texw_my = ((gpu->buf[0] >> 5 ) & 0x1f) << 3;
- gpu->texw_ox = ((gpu->buf[0] >> 10) & 0x1f) << 3;
- gpu->texw_oy = ((gpu->buf[0] >> 15) & 0x1f) << 3;
- } break;
- case 0xe3: {
- gpu->draw_x1 = (gpu->buf[0] >> 0 ) & 0x3ff;
- gpu->draw_y1 = (gpu->buf[0] >> 10) & 0x1ff;
- } break;
- case 0xe4: {
- gpu->draw_x2 = (gpu->buf[0] >> 0 ) & 0x3ff;
- gpu->draw_y2 = (gpu->buf[0] >> 10) & 0x1ff;
- } break;
- case 0xe5: {
- gpu->off_x = ((int32_t)(((gpu->buf[0] >> 0 ) & 0x7ff) << 21)) >> 21;
- gpu->off_y = ((int32_t)(((gpu->buf[0] >> 11) & 0x7ff) << 21)) >> 21;
- } break;
- case 0xe6: {
- /* To-do: Implement mask bit thing */
- } break;
- default: {
- // log_set_quiet(0);
- // log_fatal("Unhandled GP0(%02Xh)", gpu->buf[0] >> 24);
- // log_set_quiet(1);
-
- // exit(1);
- } break;
- }
-}
-
-void psx_gpu_write32(psx_gpu_t* gpu, uint32_t offset, uint32_t value) {
- switch (offset) {
- // GP0
- case 0x00: {
- switch (gpu->state) {
- case GPU_STATE_RECV_CMD: {
- gpu->buf_index = 0;
- gpu->buf[gpu->buf_index++] = value;
-
- psx_gpu_update_cmd(gpu);
- } break;
-
- case GPU_STATE_RECV_ARGS: {
- gpu->buf[gpu->buf_index++] = value;
- gpu->cmd_args_remaining--;
-
- psx_gpu_update_cmd(gpu);
- } break;
-
- case GPU_STATE_RECV_DATA: {
- gpu->recv_data = value;
-
- psx_gpu_update_cmd(gpu);
- } break;
- }
-
- return;
- } break;
-
- // GP1
- case 0x04: {
- uint8_t cmd = value >> 24;
-
- switch (cmd) {
- // Display enable
- case 0x03: {
- gpu->gpustat &= ~0x00800000;
- gpu->gpustat |= (value << 23) & 0x00800000;
- } break;
- case 0x04: {
- } break;
- case 0x05: {
- gpu->disp_x = value & 0x3ff;
- gpu->disp_y = (value >> 10) & 0x1ff;
- } break;
- case 0x06: {
- gpu->disp_x1 = value & 0xfff;
- gpu->disp_x2 = (value >> 12) & 0xfff;
- } break;
- case 0x07: {
- gpu->disp_y1 = value & 0x1ff;
- gpu->disp_y2 = (value >> 10) & 0x1ff;
- } break;
- case 0x08:
- gpu->display_mode = value & 0xffffff;
-
- if (gpu->event_cb_table[GPU_EVENT_DMODE])
- gpu->event_cb_table[GPU_EVENT_DMODE](gpu);
- break;
-
- case 0x10: {
- gpu->gp1_10h_req = value & 7;
- } break;
- }
-
+
+ gpu->vram[xpos + (ypos * 1024)] = gpu->recv_data >> 16;
+
+ ++gpu->xcnt;
+
+ if (gpu->xcnt == gpu->xsiz) {+ ++gpu->ycnt;
+ gpu->xcnt = 0;
+ }
+
+ gpu->tsiz -= 2;
+
+ if (!gpu->tsiz) {+ gpu->xcnt = 0;
+ gpu->ycnt = 0;
+ gpu->state = GPU_STATE_RECV_CMD;
+ }
+ } break;
+ }
+}
+
+// Monochrome Opaque Quadrilateral
+void gpu_cmd_28(psx_gpu_t* gpu) {+ switch (gpu->state) {+ case GPU_STATE_RECV_CMD: {+ gpu->state = GPU_STATE_RECV_ARGS;
+ gpu->cmd_args_remaining = 4;
+ } break;
+
+ case GPU_STATE_RECV_ARGS: {+ if (!gpu->cmd_args_remaining) {+ gpu->state = GPU_STATE_RECV_DATA;
+
+ gpu->v0.x = gpu->buf[1] & 0xffff;
+ gpu->v0.y = gpu->buf[1] >> 16;
+ gpu->v1.x = gpu->buf[2] & 0xffff;
+ gpu->v1.y = gpu->buf[2] >> 16;
+ gpu->v2.x = gpu->buf[3] & 0xffff;
+ gpu->v2.y = gpu->buf[3] >> 16;
+ gpu->v3.x = gpu->buf[4] & 0xffff;
+ gpu->v3.y = gpu->buf[4] >> 16;
+ gpu->color = gpu->buf[0] & 0xffffff;
+
+ gpu_render_flat_triangle(gpu, gpu->v0, gpu->v1, gpu->v2, gpu->color);
+ gpu_render_flat_triangle(gpu, gpu->v1, gpu->v2, gpu->v3, gpu->color);
+
+ gpu->state = GPU_STATE_RECV_CMD;
+ }
+ } break;
+ }
+}
+
+// Monochrome Opaque Quadrilateral
+void gpu_cmd_30(psx_gpu_t* gpu) {+ switch (gpu->state) {+ case GPU_STATE_RECV_CMD: {+ gpu->state = GPU_STATE_RECV_ARGS;
+ gpu->cmd_args_remaining = 5;
+ } break;
+
+ case GPU_STATE_RECV_ARGS: {+ if (!gpu->cmd_args_remaining) {+ gpu->state = GPU_STATE_RECV_DATA;
+
+ gpu->v0.c = gpu->buf[0] & 0xffffff;
+ gpu->v0.x = gpu->buf[1] & 0xffff;
+ gpu->v0.y = gpu->buf[1] >> 16;
+ gpu->v1.c = gpu->buf[2] & 0xffffff;
+ gpu->v1.x = gpu->buf[3] & 0xffff;
+ gpu->v1.y = gpu->buf[3] >> 16;
+ gpu->v2.c = gpu->buf[4] & 0xffffff;
+ gpu->v2.x = gpu->buf[5] & 0xffff;
+ gpu->v2.y = gpu->buf[5] >> 16;
+
+ gpu_render_shaded_triangle(gpu, gpu->v0, gpu->v1, gpu->v2);
+
+ gpu->state = GPU_STATE_RECV_CMD;
+ }
+ } break;
+ }
+}
+
+// Monochrome Opaque Quadrilateral
+void gpu_cmd_38(psx_gpu_t* gpu) {+ switch (gpu->state) {+ case GPU_STATE_RECV_CMD: {+ gpu->state = GPU_STATE_RECV_ARGS;
+ gpu->cmd_args_remaining = 7;
+ } break;
+
+ case GPU_STATE_RECV_ARGS: {+ if (!gpu->cmd_args_remaining) {+ gpu->state = GPU_STATE_RECV_DATA;
+
+ gpu->v0.c = gpu->buf[0] & 0xffffff;
+ gpu->v0.x = gpu->buf[1] & 0xffff;
+ gpu->v0.y = gpu->buf[1] >> 16;
+ gpu->v1.c = gpu->buf[2] & 0xffffff;
+ gpu->v1.x = gpu->buf[3] & 0xffff;
+ gpu->v1.y = gpu->buf[3] >> 16;
+ gpu->v2.c = gpu->buf[4] & 0xffffff;
+ gpu->v2.x = gpu->buf[5] & 0xffff;
+ gpu->v2.y = gpu->buf[5] >> 16;
+ gpu->v3.c = gpu->buf[6] & 0xffffff;
+ gpu->v3.x = gpu->buf[7] & 0xffff;
+ gpu->v3.y = gpu->buf[7] >> 16;
+
+ gpu_render_shaded_triangle(gpu, gpu->v0, gpu->v1, gpu->v2);
+ gpu_render_shaded_triangle(gpu, gpu->v1, gpu->v2, gpu->v3);
+
+ gpu->state = GPU_STATE_RECV_CMD;
+ }
+ } break;
+ }
+}
+
+// Monochrome Opaque Quadrilateral
+void gpu_cmd_3c(psx_gpu_t* gpu) {+ switch (gpu->state) {+ case GPU_STATE_RECV_CMD: {+ gpu->state = GPU_STATE_RECV_ARGS;
+ gpu->cmd_args_remaining = 11;
+ } break;
+
+ case GPU_STATE_RECV_ARGS: {+ if (!gpu->cmd_args_remaining) {+ gpu->state = GPU_STATE_RECV_DATA;
+
+ uint32_t texp = gpu->buf[5] >> 16;
+ gpu->color = gpu->buf[0] & 0xffffff;
+ gpu->pal = gpu->buf[2] >> 16;
+ gpu->v0.tx = gpu->buf[2] & 0xff;
+ gpu->v0.ty = (gpu->buf[2] >> 8) & 0xff;
+ gpu->v1.tx = gpu->buf[5] & 0xff;
+ gpu->v1.ty = (gpu->buf[5] >> 8) & 0xff;
+ gpu->v2.tx = gpu->buf[8] & 0xff;
+ gpu->v2.ty = (gpu->buf[8] >> 8) & 0xff;
+ gpu->v3.tx = gpu->buf[11] & 0xff;
+ gpu->v3.ty = (gpu->buf[11] >> 8) & 0xff;
+ gpu->v0.x = gpu->buf[1] & 0xffff;
+ gpu->v0.y = gpu->buf[1] >> 16;
+ gpu->v1.x = gpu->buf[4] & 0xffff;
+ gpu->v1.y = gpu->buf[4] >> 16;
+ gpu->v2.x = gpu->buf[7] & 0xffff;
+ gpu->v2.y = gpu->buf[7] >> 16;
+ gpu->v3.x = gpu->buf[10] & 0xffff;
+ gpu->v3.y = gpu->buf[10] >> 16;
+
+ uint16_t clutx = (gpu->pal & 0x3f) << 4;
+ uint16_t cluty = (gpu->pal >> 6) & 0x1ff;
+ uint16_t tpx = (texp & 0xf) << 6;
+ uint16_t tpy = (texp & 0x10) << 4;
+ uint16_t depth = (texp >> 7) & 0x3;
+
+ gpu_render_textured_triangle(gpu, gpu->v0, gpu->v1, gpu->v2, tpx, tpy, clutx, cluty, depth);
+ gpu_render_textured_triangle(gpu, gpu->v1, gpu->v2, gpu->v3, tpx, tpy, clutx, cluty, depth);
+
+ gpu->state = GPU_STATE_RECV_CMD;
+ }
+ } break;
+ }
+}
+
+// Monochrome Opaque Quadrilateral
+void gpu_cmd_2c(psx_gpu_t* gpu) {+ switch (gpu->state) {+ case GPU_STATE_RECV_CMD: {+ gpu->state = GPU_STATE_RECV_ARGS;
+ gpu->cmd_args_remaining = 8;
+ } break;
+
+ case GPU_STATE_RECV_ARGS: {+ if (!gpu->cmd_args_remaining) {+ gpu->state = GPU_STATE_RECV_DATA;
+
+ uint32_t texp = gpu->buf[4] >> 16;
+ gpu->color = gpu->buf[0] & 0xffffff;
+ gpu->pal = gpu->buf[2] >> 16;
+ gpu->v0.tx = gpu->buf[2] & 0xff;
+ gpu->v0.ty = (gpu->buf[2] >> 8) & 0xff;
+ gpu->v1.tx = gpu->buf[4] & 0xff;
+ gpu->v1.ty = (gpu->buf[4] >> 8) & 0xff;
+ gpu->v2.tx = gpu->buf[6] & 0xff;
+ gpu->v2.ty = (gpu->buf[6] >> 8) & 0xff;
+ gpu->v3.tx = gpu->buf[8] & 0xff;
+ gpu->v3.ty = (gpu->buf[8] >> 8) & 0xff;
+ gpu->v0.x = gpu->buf[1] & 0xffff;
+ gpu->v0.y = gpu->buf[1] >> 16;
+ gpu->v1.x = gpu->buf[3] & 0xffff;
+ gpu->v1.y = gpu->buf[3] >> 16;
+ gpu->v2.x = gpu->buf[5] & 0xffff;
+ gpu->v2.y = gpu->buf[5] >> 16;
+ gpu->v3.x = gpu->buf[7] & 0xffff;
+ gpu->v3.y = gpu->buf[7] >> 16;
+
+ uint16_t clutx = (gpu->pal & 0x3f) << 4;
+ uint16_t cluty = (gpu->pal >> 6) & 0x1ff;
+ uint16_t tpx = (texp & 0xf) << 6;
+ uint16_t tpy = (texp & 0x10) << 4;
+ uint16_t depth = (texp >> 7) & 0x3;
+
+ gpu_render_textured_triangle(gpu, gpu->v0, gpu->v1, gpu->v2, tpx, tpy, clutx, cluty, depth);
+ gpu_render_textured_triangle(gpu, gpu->v1, gpu->v2, gpu->v3, tpx, tpy, clutx, cluty, depth);
+
+ gpu->state = GPU_STATE_RECV_CMD;
+ }
+ } break;
+ }
+}
+
+// Monochrome Opaque Quadrilateral
+void gpu_cmd_24(psx_gpu_t* gpu) {+ switch (gpu->state) {+ case GPU_STATE_RECV_CMD: {+ gpu->state = GPU_STATE_RECV_ARGS;
+ gpu->cmd_args_remaining = 6;
+ } break;
+
+ case GPU_STATE_RECV_ARGS: {+ if (!gpu->cmd_args_remaining) {+ gpu->state = GPU_STATE_RECV_DATA;
+
+ uint32_t texp = gpu->buf[4] >> 16;
+ gpu->color = gpu->buf[0] & 0xffffff;
+ gpu->pal = gpu->buf[2] >> 16;
+ gpu->v0.tx = gpu->buf[2] & 0xff;
+ gpu->v0.ty = (gpu->buf[2] >> 8) & 0xff;
+ gpu->v1.tx = gpu->buf[4] & 0xff;
+ gpu->v1.ty = (gpu->buf[4] >> 8) & 0xff;
+ gpu->v2.tx = gpu->buf[6] & 0xff;
+ gpu->v2.ty = (gpu->buf[6] >> 8) & 0xff;
+ gpu->v0.x = gpu->buf[1] & 0xffff;
+ gpu->v0.y = gpu->buf[1] >> 16;
+ gpu->v1.x = gpu->buf[3] & 0xffff;
+ gpu->v1.y = gpu->buf[3] >> 16;
+ gpu->v2.x = gpu->buf[5] & 0xffff;
+ gpu->v2.y = gpu->buf[5] >> 16;
+
+ uint16_t clutx = (gpu->pal & 0x3f) << 4;
+ uint16_t cluty = (gpu->pal >> 6) & 0x1ff;
+ uint16_t tpx = (texp & 0xf) << 6;
+ uint16_t tpy = (texp & 0x10) << 4;
+ uint16_t depth = (texp >> 7) & 0x3;
+
+ gpu_render_textured_triangle(gpu, gpu->v0, gpu->v1, gpu->v2, tpx, tpy, clutx, cluty, depth);
+ gpu_render_textured_triangle(gpu, gpu->v1, gpu->v2, gpu->v3, tpx, tpy, clutx, cluty, depth);
+
+ gpu->state = GPU_STATE_RECV_CMD;
+ }
+ } break;
+ }
+}
+
+// Monochrome Opaque Quadrilateral
+void gpu_cmd_2d(psx_gpu_t* gpu) {+ switch (gpu->state) {+ case GPU_STATE_RECV_CMD: {+ gpu->state = GPU_STATE_RECV_ARGS;
+ gpu->cmd_args_remaining = 8;
+ } break;
+
+ case GPU_STATE_RECV_ARGS: {+ if (!gpu->cmd_args_remaining) {+ gpu->state = GPU_STATE_RECV_DATA;
+
+ uint32_t texp = gpu->buf[4] >> 16;
+ gpu->color = gpu->buf[0] & 0xffffff;
+ gpu->pal = gpu->buf[2] >> 16;
+ gpu->v0.tx = gpu->buf[2] & 0xff;
+ gpu->v0.ty = (gpu->buf[2] >> 8) & 0xff;
+ gpu->v1.tx = gpu->buf[4] & 0xff;
+ gpu->v1.ty = (gpu->buf[4] >> 8) & 0xff;
+ gpu->v2.tx = gpu->buf[6] & 0xff;
+ gpu->v2.ty = (gpu->buf[6] >> 8) & 0xff;
+ gpu->v3.tx = gpu->buf[8] & 0xff;
+ gpu->v3.ty = (gpu->buf[8] >> 8) & 0xff;
+ gpu->v0.x = gpu->buf[1] & 0xffff;
+ gpu->v0.y = gpu->buf[1] >> 16;
+ gpu->v1.x = gpu->buf[3] & 0xffff;
+ gpu->v1.y = gpu->buf[3] >> 16;
+ gpu->v2.x = gpu->buf[5] & 0xffff;
+ gpu->v2.y = gpu->buf[5] >> 16;
+ gpu->v3.x = gpu->buf[7] & 0xffff;
+ gpu->v3.y = gpu->buf[7] >> 16;
+
+ uint16_t clutx = (gpu->pal & 0x3f) << 4;
+ uint16_t cluty = (gpu->pal >> 6) & 0x1ff;
+ uint16_t tpx = (texp & 0xf) << 6;
+ uint16_t tpy = (texp & 0x10) << 4;
+ uint16_t depth = (texp >> 7) & 0x3;
+
+ gpu_render_textured_triangle(gpu, gpu->v0, gpu->v1, gpu->v2, tpx, tpy, clutx, cluty, depth);
+ gpu_render_textured_triangle(gpu, gpu->v1, gpu->v2, gpu->v3, tpx, tpy, clutx, cluty, depth);
+
+ gpu->state = GPU_STATE_RECV_CMD;
+ }
+ } break;
+ }
+}
+
+void gpu_cmd_64(psx_gpu_t* gpu) {+ switch (gpu->state) {+ case GPU_STATE_RECV_CMD: {+ gpu->state = GPU_STATE_RECV_ARGS;
+ gpu->cmd_args_remaining = 3;
+ } break;
+
+ case GPU_STATE_RECV_ARGS: {+ if (!gpu->cmd_args_remaining) {+ gpu->state = GPU_STATE_RECV_DATA;
+
+ gpu->color = gpu->buf[0] & 0xffffff;
+ gpu->v0.x = gpu->buf[1] & 0xffff;
+ gpu->v0.y = gpu->buf[1] >> 16;
+ gpu->v0.tx = gpu->buf[2] & 0xff;
+ gpu->v0.ty = (gpu->buf[2] >> 8) & 0xff;
+ gpu->pal = gpu->buf[2] >> 16;
+
+ uint32_t w = gpu->buf[3] & 0xffff;
+ uint32_t h = gpu->buf[3] >> 16;
+ uint16_t clutx = (gpu->pal & 0x3f) << 4;
+ uint16_t cluty = (gpu->pal >> 6) & 0x1ff;
+
+ gpu_render_textured_rectangle(gpu, gpu->v0, w, h, clutx, cluty, gpu->color);
+
+ gpu->state = GPU_STATE_RECV_CMD;
+ }
+ } break;
+ }
+}
+
+void gpu_cmd_7c(psx_gpu_t* gpu) {+ switch (gpu->state) {+ case GPU_STATE_RECV_CMD: {+ gpu->state = GPU_STATE_RECV_ARGS;
+ gpu->cmd_args_remaining = 2;
+ } break;
+
+ case GPU_STATE_RECV_ARGS: {+ if (!gpu->cmd_args_remaining) {+ gpu->state = GPU_STATE_RECV_DATA;
+
+ gpu->color = gpu->buf[0] & 0xffffff;
+ gpu->v0.x = gpu->buf[1] & 0xffff;
+ gpu->v0.y = gpu->buf[1] >> 16;
+ gpu->v0.tx = gpu->buf[2] & 0xff;
+ gpu->v0.ty = (gpu->buf[2] >> 8) & 0xff;
+ gpu->pal = gpu->buf[2] >> 16;
+
+ uint32_t w = 16;
+ uint32_t h = 16;
+ uint16_t clutx = (gpu->pal & 0x3f) << 4;
+ uint16_t cluty = (gpu->pal >> 6) & 0x1ff;
+
+ gpu_render_textured_rectangle(gpu, gpu->v0, w, h, clutx, cluty, gpu->color);
+
+ gpu->state = GPU_STATE_RECV_CMD;
+ }
+ } break;
+ }
+}
+
+void gpu_cmd_74(psx_gpu_t* gpu) {+ switch (gpu->state) {+ case GPU_STATE_RECV_CMD: {+ gpu->state = GPU_STATE_RECV_ARGS;
+ gpu->cmd_args_remaining = 2;
+ } break;
+
+ case GPU_STATE_RECV_ARGS: {+ if (!gpu->cmd_args_remaining) {+ gpu->state = GPU_STATE_RECV_DATA;
+
+ gpu->color = gpu->buf[0] & 0xffffff;
+ gpu->v0.x = gpu->buf[1] & 0xffff;
+ gpu->v0.y = gpu->buf[1] >> 16;
+ gpu->v0.tx = gpu->buf[2] & 0xff;
+ gpu->v0.ty = (gpu->buf[2] >> 8) & 0xff;
+ gpu->pal = gpu->buf[2] >> 16;
+
+ uint32_t w = 8;
+ uint32_t h = 8;
+ uint16_t clutx = (gpu->pal & 0x3f) << 4;
+ uint16_t cluty = (gpu->pal >> 6) & 0x1ff;
+
+ gpu_render_textured_rectangle(gpu, gpu->v0, w, h, clutx, cluty, gpu->color);
+
+ gpu->state = GPU_STATE_RECV_CMD;
+ }
+ } break;
+ }
+}
+
+void gpu_cmd_60(psx_gpu_t* gpu) {+ switch (gpu->state) {+ case GPU_STATE_RECV_CMD: {+ gpu->state = GPU_STATE_RECV_ARGS;
+ gpu->cmd_args_remaining = 2;
+ } break;
+
+ case GPU_STATE_RECV_ARGS: {+ if (!gpu->cmd_args_remaining) {+ gpu->state = GPU_STATE_RECV_DATA;
+
+ gpu->color = gpu->buf[0] & 0xffffff;
+ gpu->v0.x = gpu->buf[1] & 0xffff;
+ gpu->v0.y = gpu->buf[1] >> 16;
+ gpu->xsiz = gpu->buf[2] & 0xffff;
+ gpu->ysiz = gpu->buf[2] >> 16;
+
+ gpu->v0.x += gpu->off_x;
+ gpu->v0.y += gpu->off_y;
+
+ gpu_render_flat_rectangle(gpu, gpu->v0, gpu->xsiz, gpu->ysiz, BGR555(gpu->color));
+
+ gpu->state = GPU_STATE_RECV_CMD;
+ }
+ } break;
+ }
+}
+
+void gpu_cmd_68(psx_gpu_t* gpu) {+ switch (gpu->state) {+ case GPU_STATE_RECV_CMD: {+ gpu->state = GPU_STATE_RECV_ARGS;
+ gpu->cmd_args_remaining = 1;
+ } break;
+
+ case GPU_STATE_RECV_ARGS: {+ if (!gpu->cmd_args_remaining) {+ gpu->state = GPU_STATE_RECV_DATA;
+
+ gpu->color = gpu->buf[0] & 0xffffff;
+ gpu->v0.x = gpu->buf[1] & 0xffff;
+ gpu->v0.y = gpu->buf[1] >> 16;
+
+ gpu->v0.x += gpu->off_x;
+ gpu->v0.y += gpu->off_y;
+
+ gpu->vram[gpu->v0.x + (gpu->v0.y * 1024)] = BGR555(gpu->color);
+
+ gpu->state = GPU_STATE_RECV_CMD;
+ }
+ } break;
+ }
+}
+
+void gpu_cmd_40(psx_gpu_t* gpu) {+ switch (gpu->state) {+ case GPU_STATE_RECV_CMD: {+ gpu->state = GPU_STATE_RECV_ARGS;
+ gpu->cmd_args_remaining = 2;
+ } break;
+
+ case GPU_STATE_RECV_ARGS: {+ if (!gpu->cmd_args_remaining) {+ gpu->color = gpu->buf[0] & 0xffffff;
+ gpu->v0.x = gpu->buf[1] & 0xffff;
+ gpu->v0.y = gpu->buf[1] >> 16;
+ gpu->v1.x = gpu->buf[2] & 0xffff;
+ gpu->v1.y = gpu->buf[2] >> 16;
+
+ gpu_render_flat_line(gpu, gpu->v0, gpu->v1, BGR555(gpu->color));
+
+ gpu->state = GPU_STATE_RECV_CMD;
+ }
+ } break;
+ }
+}
+
+void gpu_cmd_c0(psx_gpu_t* gpu) {+ switch (gpu->state) {+ case GPU_STATE_RECV_CMD: {+ gpu->state = GPU_STATE_RECV_ARGS;
+ gpu->cmd_args_remaining = 2;
+ } break;
+
+ case GPU_STATE_RECV_ARGS: {+ if (!gpu->cmd_args_remaining) {+ gpu->c0_xcnt = 0;
+ gpu->c0_ycnt = 0;
+ uint32_t c0_xpos = gpu->buf[1] & 0xffff;
+ uint32_t c0_ypos = gpu->buf[1] >> 16;
+ gpu->c0_xsiz = gpu->buf[2] & 0xffff;
+ gpu->c0_ysiz = gpu->buf[2] >> 16;
+ c0_xpos = c0_xpos & 0x3ff;
+ c0_ypos = c0_ypos & 0x1ff;
+ gpu->c0_xsiz = ((gpu->c0_xsiz - 1) & 0x3ff) + 1;
+ gpu->c0_ysiz = ((gpu->c0_ysiz - 1) & 0x1ff) + 1;
+ gpu->c0_tsiz = ((gpu->c0_xsiz * gpu->c0_ysiz) + 1) & 0xfffffffe;
+ gpu->c0_addr = c0_xpos + (c0_ypos * 1024);
+
+ gpu->state = GPU_STATE_RECV_CMD;
+ }
+ } break;
+ }
+}
+
+void gpu_cmd_02(psx_gpu_t* gpu) {+ switch (gpu->state) {+ case GPU_STATE_RECV_CMD: {+ gpu->state = GPU_STATE_RECV_ARGS;
+ gpu->cmd_args_remaining = 2;
+ } break;
+
+ case GPU_STATE_RECV_ARGS: {+ if (!gpu->cmd_args_remaining) {+ gpu->state = GPU_STATE_RECV_DATA;
+
+ gpu->color = gpu->buf[0] & 0xffffff;
+ gpu->v0.x = gpu->buf[1] & 0xffff;
+ gpu->v0.y = gpu->buf[1] >> 16;
+ gpu->xsiz = gpu->buf[2] & 0xffff;
+ gpu->ysiz = gpu->buf[2] >> 16;
+
+ gpu->v0.x = (gpu->v0.x & 0x3f0);
+ gpu->v0.y = gpu->v0.y & 0x1ff;
+ gpu->xsiz = (((gpu->xsiz & 0x3ff) + 0x0f) & 0xfffffff0);
+ gpu->ysiz = gpu->ysiz & 0x1ff;
+
+ uint16_t color = BGR555(gpu->color);
+
+ // printf("02 draw=(%u,%u-%u,%u) v0=(%u,%u) siz=(%u,%u)\n",+ // gpu->draw_x1,
+ // gpu->draw_y1,
+ // gpu->draw_x2,
+ // gpu->draw_y2,
+ // gpu->v0.x,
+ // gpu->v0.y,
+ // gpu->xsiz,
+ // gpu->ysiz
+ // );
+
+ for (int y = gpu->v0.y; y < (gpu->v0.y + gpu->ysiz); y++) {+ for (int x = gpu->v0.x; x < (gpu->v0.x + gpu->xsiz); x++) {+ // This shouldn't be needed
+ // int bc = (x >= gpu->draw_x1) && (x <= gpu->draw_x2) &&
+ // (y >= gpu->draw_y1) && (y <= gpu->draw_y2);
+
+ // if (!bc)
+ // continue;
+
+ if ((x < 1024) && (y < 512) && (x >= 0) && (y >= 0))
+ gpu->vram[x + (y * 1024)] = color;
+ }
+ }
+
+ gpu->state = GPU_STATE_RECV_CMD;
+ }
+ } break;
+ }
+}
+
+void gpu_cmd_80(psx_gpu_t* gpu) {+ switch (gpu->state) {+ case GPU_STATE_RECV_CMD: {+ gpu->state = GPU_STATE_RECV_ARGS;
+ gpu->cmd_args_remaining = 3;
+ } break;
+
+ case GPU_STATE_RECV_ARGS: {+ if (!gpu->cmd_args_remaining) {+ gpu->state = GPU_STATE_RECV_DATA;
+
+ uint32_t srcx = gpu->buf[1] & 0xffff;
+ uint32_t srcy = gpu->buf[1] >> 16;
+ uint32_t dstx = gpu->buf[2] & 0xffff;
+ uint32_t dsty = gpu->buf[2] >> 16;
+ uint32_t xsiz = gpu->buf[3] & 0xffff;
+ uint32_t ysiz = gpu->buf[3] >> 16;
+
+ for (int y = 0; y < ysiz; y++) {+ for (int x = 0; x < xsiz; x++) {+ int dstb = ((dstx + x) < 1024) && ((dsty + y) < 512);
+ int srcb = ((srcx + x) < 1024) && ((srcy + y) < 512);
+
+ if (dstb && srcb)
+ gpu->vram[(dstx + x) + (dsty + y) * 1024] = gpu->vram[(srcx + x) + (srcy + y) * 1024];
+ }
+ }
+
+ gpu->state = GPU_STATE_RECV_CMD;
+ }
+ } break;
+ }
+}
+
+void psx_gpu_update_cmd(psx_gpu_t* gpu) {+ int type = (gpu->buf[0] >> 29) & 7;
+
+ switch (type) {+ case 1: gpu_poly(gpu); return;
+ case 2: gpu_line(gpu); return;
+ case 3: gpu_rect(gpu); return;
+ }
+
+ switch (gpu->buf[0] >> 24) {+ case 0x00: /* nop */ break;
+ case 0x01: /* Cache clear */ break;
+ case 0x02: gpu_cmd_02(gpu); break;
+ case 0x24: gpu_cmd_24(gpu); break;
+ case 0x25: gpu_cmd_24(gpu); break;
+ case 0x26: gpu_cmd_24(gpu); break;
+ case 0x27: gpu_cmd_24(gpu); break;
+ case 0x28: gpu_cmd_28(gpu); break;
+ case 0x2a: gpu_cmd_28(gpu); break;
+ case 0x2c: gpu_cmd_2d(gpu); break;
+ case 0x2d: gpu_cmd_2d(gpu); break;
+ case 0x2e: gpu_cmd_2d(gpu); break;
+ case 0x2f: gpu_cmd_2d(gpu); break;
+ case 0x30: gpu_cmd_30(gpu); break;
+ case 0x32: gpu_cmd_30(gpu); break;
+ case 0x38: gpu_cmd_38(gpu); break;
+ case 0x3c: gpu_cmd_3c(gpu); break;
+ case 0x3e: gpu_cmd_3c(gpu); break;
+ case 0x40: gpu_cmd_40(gpu); break;
+ case 0x60: gpu_cmd_60(gpu); break;
+ case 0x62: gpu_cmd_60(gpu); break;
+ case 0x64: gpu_cmd_64(gpu); break;
+ case 0x65: gpu_cmd_64(gpu); break;
+ case 0x66: gpu_cmd_64(gpu); break;
+ case 0x67: gpu_cmd_64(gpu); break;
+ case 0x68: gpu_cmd_68(gpu); break;
+ case 0x74: gpu_cmd_74(gpu); break;
+ case 0x75: gpu_cmd_74(gpu); break;
+ case 0x76: gpu_cmd_74(gpu); break;
+ case 0x77: gpu_cmd_74(gpu); break;
+ case 0x7c: gpu_cmd_7c(gpu); break;
+ case 0x7d: gpu_cmd_7c(gpu); break;
+ case 0x7e: gpu_cmd_7c(gpu); break;
+ case 0x7f: gpu_cmd_7c(gpu); break;
+ case 0x80: gpu_cmd_80(gpu); break;
+ case 0xa0: gpu_cmd_a0(gpu); break;
+ case 0xc0: gpu_cmd_c0(gpu); break;
+ case 0xe1: {+ gpu->gpustat &= 0xfffff800;
+ gpu->gpustat |= gpu->buf[0] & 0x7ff;
+ gpu->texp_x = (gpu->gpustat & 0xf) << 6;
+ gpu->texp_y = (gpu->gpustat & 0x10) << 4;
+ gpu->texp_d = (gpu->gpustat >> 7) & 0x3;
+ } break;
+ case 0xe2: {+ gpu->texw_mx = ((gpu->buf[0] >> 0 ) & 0x1f) << 3;
+ gpu->texw_my = ((gpu->buf[0] >> 5 ) & 0x1f) << 3;
+ gpu->texw_ox = ((gpu->buf[0] >> 10) & 0x1f) << 3;
+ gpu->texw_oy = ((gpu->buf[0] >> 15) & 0x1f) << 3;
+ } break;
+ case 0xe3: {+ gpu->draw_x1 = (gpu->buf[0] >> 0 ) & 0x3ff;
+ gpu->draw_y1 = (gpu->buf[0] >> 10) & 0x1ff;
+ } break;
+ case 0xe4: {+ gpu->draw_x2 = (gpu->buf[0] >> 0 ) & 0x3ff;
+ gpu->draw_y2 = (gpu->buf[0] >> 10) & 0x1ff;
+ } break;
+ case 0xe5: {+ gpu->off_x = ((int32_t)(((gpu->buf[0] >> 0 ) & 0x7ff) << 21)) >> 21;
+ gpu->off_y = ((int32_t)(((gpu->buf[0] >> 11) & 0x7ff) << 21)) >> 21;
+ } break;
+ case 0xe6: {+ /* To-do: Implement mask bit thing */
+ } break;
+ default: {+ // log_set_quiet(0);
+ // log_fatal("Unhandled GP0(%02Xh)", gpu->buf[0] >> 24);+ // log_set_quiet(1);
+
+ // exit(1);
+ } break;
+ }
+}
+
+void psx_gpu_write32(psx_gpu_t* gpu, uint32_t offset, uint32_t value) {+ switch (offset) {+ // GP0
+ case 0x00: {+ switch (gpu->state) {+ case GPU_STATE_RECV_CMD: {+ gpu->buf_index = 0;
+ gpu->buf[gpu->buf_index++] = value;
+
+ psx_gpu_update_cmd(gpu);
+ } break;
+
+ case GPU_STATE_RECV_ARGS: {+ gpu->buf[gpu->buf_index++] = value;
+ gpu->cmd_args_remaining--;
+
+ psx_gpu_update_cmd(gpu);
+ } break;
+
+ case GPU_STATE_RECV_DATA: {+ gpu->recv_data = value;
+
+ psx_gpu_update_cmd(gpu);
+ } break;
+ }
+
+ return;
+ } break;
+
+ // GP1
+ case 0x04: {+ uint8_t cmd = value >> 24;
+
+ switch (cmd) {+ // Display enable
+ case 0x03: {+ gpu->gpustat &= ~0x00800000;
+ gpu->gpustat |= (value << 23) & 0x00800000;
+ } break;
+ case 0x04: {+ } break;
+ case 0x05: {+ gpu->disp_x = value & 0x3ff;
+ gpu->disp_y = (value >> 10) & 0x1ff;
+ } break;
+ case 0x06: {+ gpu->disp_x1 = value & 0xfff;
+ gpu->disp_x2 = (value >> 12) & 0xfff;
+ } break;
+ case 0x07: {+ gpu->disp_y1 = value & 0x1ff;
+ gpu->disp_y2 = (value >> 10) & 0x1ff;
+ } break;
+ case 0x08:
+ gpu->display_mode = value & 0xffffff;
+
+ if (gpu->event_cb_table[GPU_EVENT_DMODE])
+ gpu->event_cb_table[GPU_EVENT_DMODE](gpu);
+ break;
+
+ case 0x10: {+ gpu->gp1_10h_req = value & 7;
+ } break;
+ }
+
print("GP1(%02Xh) args=%06x\n", value >> 24, value & 0xffffff);-
- return;
- } break;
- }
-
+
+ return;
+ } break;
+ }
+
print("Unhandled 32-bit GPU write at offset %08x (%08x)\n", offset, value);}
@@ -1878,108 +1878,108 @@
USED(gpu);
printf("Unhandled 8-bit GPU write at offset %08x (%02x)\n", offset, value);}
-
-void psx_gpu_set_event_callback(psx_gpu_t* gpu, int event, psx_gpu_event_callback_t cb) {
- gpu->event_cb_table[event] = cb;
-}
-
-void psx_gpu_set_udata(psx_gpu_t* gpu, int index, void* udata) {
- gpu->udata[index] = udata;
-}
-
-#define GPU_CYCLES_PER_HDRAW_NTSC 2560.0f
-#define GPU_CYCLES_PER_SCANL_NTSC 3413.0f
-#define GPU_SCANS_PER_VDRAW_NTSC 240
-#define GPU_SCANS_PER_FRAME_NTSC 263
-#define GPU_CYCLES_PER_SCANL_PAL 3406.0f
-#define GPU_SCANS_PER_FRAME_PAL 314
-
-void gpu_hblank_event(psx_gpu_t* gpu) {
- if (gpu->line < GPU_SCANS_PER_VDRAW_NTSC) {
- if (gpu->line & 1) {
- gpu->gpustat |= 1 << 31;
- } else {
- gpu->gpustat &= ~(1 << 31);
- }
-
- // HACK!! More games are fine with this
- // but others, like Dead or Alive, will refuse
- // to boot because this frequency is not fast
- // enough. Sending T2 IRQs every line fixes DoA
- // but breaks a bunch of games, so I'll keep this
- // like this until I actually fix the timers
- // Games that seem to care about T2 timing:
- // - Street Fighter Alpha 2
- // - Dead or Alive
- // - NBA Jam
- // - Doom
- // - Devil Dice
- // - Zanac x Zanac
- // - Soukyugurentai
- // - Mortal Kombat
- // - PaRappa the Rapper
- // - In The Hunt
- // - Crash Bandicoot
- // - Jackie Chan Stuntmaster
- // - etc.
- // Masking with 7 breaks Street Fighter Alpha 2. The game
- // just stops sending commands to the CDROM while on
- // Player Select. It probably uses T2 IRQs to time
- // GetlocP commands, if the timer is too slow it will
- // break.
- // if (!(gpu->line & 7))
- // psx_ic_irq(gpu->ic, IC_SPU);
- // psx_ic_irq(gpu->ic, IC_SPU);
- } else {
- gpu->gpustat &= ~(1 << 31);
- }
-
- gpu->line++;
-
- if (gpu->line == GPU_SCANS_PER_VDRAW_NTSC) {
- if (gpu->event_cb_table[GPU_EVENT_VBLANK])
- gpu->event_cb_table[GPU_EVENT_VBLANK](gpu);
-
- psx_ic_irq(gpu->ic, IC_VBLANK);
- } else if (gpu->line == GPU_SCANS_PER_FRAME_NTSC) {
- if (gpu->event_cb_table[GPU_EVENT_VBLANK_END])
- gpu->event_cb_table[GPU_EVENT_VBLANK_END](gpu);
-
- gpu->line = 0;
- }
-}
-
-void psx_gpu_update(psx_gpu_t* gpu, int cyc) {
- int prev_hblank = (gpu->cycles >= GPU_CYCLES_PER_HDRAW_NTSC) &&
- (gpu->cycles <= GPU_CYCLES_PER_SCANL_NTSC);
-
- // Convert CPU (~33.8 MHz) cycles to GPU (~53.7 MHz) cycles
- gpu->cycles += (float)cyc * (PSX_GPU_CLOCK_FREQ_NTSC / PSX_CPU_FREQ);
-
- int curr_hblank = (gpu->cycles >= GPU_CYCLES_PER_HDRAW_NTSC) &&
- (gpu->cycles <= GPU_CYCLES_PER_SCANL_NTSC);
-
- if (curr_hblank && !prev_hblank) {
- if (gpu->event_cb_table[GPU_EVENT_HBLANK])
- gpu->event_cb_table[GPU_EVENT_HBLANK](gpu);
-
- gpu_hblank_event(gpu);
- } else if (prev_hblank && !curr_hblank) {
- if (gpu->event_cb_table[GPU_EVENT_HBLANK_END])
- gpu->event_cb_table[GPU_EVENT_HBLANK_END](gpu);
-
- gpu->cycles -= (float)GPU_CYCLES_PER_SCANL_NTSC;
- }
-}
-
-void* psx_gpu_get_display_buffer(psx_gpu_t* gpu) {
- if (gpu->gpustat & 0x800000)
- return gpu->empty;
-
- return gpu->vram + (gpu->disp_x + (gpu->disp_y * 1024));
-}
-
-void psx_gpu_destroy(psx_gpu_t* gpu) {
- free(gpu->vram);
- free(gpu);
-}
+
+void psx_gpu_set_event_callback(psx_gpu_t* gpu, int event, psx_gpu_event_callback_t cb) {+ gpu->event_cb_table[event] = cb;
+}
+
+void psx_gpu_set_udata(psx_gpu_t* gpu, int index, void* udata) {+ gpu->udata[index] = udata;
+}
+
+#define GPU_CYCLES_PER_HDRAW_NTSC 2560.0f
+#define GPU_CYCLES_PER_SCANL_NTSC 3413.0f
+#define GPU_SCANS_PER_VDRAW_NTSC 240
+#define GPU_SCANS_PER_FRAME_NTSC 263
+#define GPU_CYCLES_PER_SCANL_PAL 3406.0f
+#define GPU_SCANS_PER_FRAME_PAL 314
+
+void gpu_hblank_event(psx_gpu_t* gpu) {+ if (gpu->line < GPU_SCANS_PER_VDRAW_NTSC) {+ if (gpu->line & 1) {+ gpu->gpustat |= 1 << 31;
+ } else {+ gpu->gpustat &= ~(1 << 31);
+ }
+
+ // HACK!! More games are fine with this
+ // but others, like Dead or Alive, will refuse
+ // to boot because this frequency is not fast
+ // enough. Sending T2 IRQs every line fixes DoA
+ // but breaks a bunch of games, so I'll keep this
+ // like this until I actually fix the timers
+ // Games that seem to care about T2 timing:
+ // - Street Fighter Alpha 2
+ // - Dead or Alive
+ // - NBA Jam
+ // - Doom
+ // - Devil Dice
+ // - Zanac x Zanac
+ // - Soukyugurentai
+ // - Mortal Kombat
+ // - PaRappa the Rapper
+ // - In The Hunt
+ // - Crash Bandicoot
+ // - Jackie Chan Stuntmaster
+ // - etc.
+ // Masking with 7 breaks Street Fighter Alpha 2. The game
+ // just stops sending commands to the CDROM while on
+ // Player Select. It probably uses T2 IRQs to time
+ // GetlocP commands, if the timer is too slow it will
+ // break.
+ // if (!(gpu->line & 7))
+ // psx_ic_irq(gpu->ic, IC_SPU);
+ // psx_ic_irq(gpu->ic, IC_SPU);
+ } else {+ gpu->gpustat &= ~(1 << 31);
+ }
+
+ gpu->line++;
+
+ if (gpu->line == GPU_SCANS_PER_VDRAW_NTSC) {+ if (gpu->event_cb_table[GPU_EVENT_VBLANK])
+ gpu->event_cb_table[GPU_EVENT_VBLANK](gpu);
+
+ psx_ic_irq(gpu->ic, IC_VBLANK);
+ } else if (gpu->line == GPU_SCANS_PER_FRAME_NTSC) {+ if (gpu->event_cb_table[GPU_EVENT_VBLANK_END])
+ gpu->event_cb_table[GPU_EVENT_VBLANK_END](gpu);
+
+ gpu->line = 0;
+ }
+}
+
+void psx_gpu_update(psx_gpu_t* gpu, int cyc) {+ int prev_hblank = (gpu->cycles >= GPU_CYCLES_PER_HDRAW_NTSC) &&
+ (gpu->cycles <= GPU_CYCLES_PER_SCANL_NTSC);
+
+ // Convert CPU (~33.8 MHz) cycles to GPU (~53.7 MHz) cycles
+ gpu->cycles += (float)cyc * (PSX_GPU_CLOCK_FREQ_NTSC / PSX_CPU_FREQ);
+
+ int curr_hblank = (gpu->cycles >= GPU_CYCLES_PER_HDRAW_NTSC) &&
+ (gpu->cycles <= GPU_CYCLES_PER_SCANL_NTSC);
+
+ if (curr_hblank && !prev_hblank) {+ if (gpu->event_cb_table[GPU_EVENT_HBLANK])
+ gpu->event_cb_table[GPU_EVENT_HBLANK](gpu);
+
+ gpu_hblank_event(gpu);
+ } else if (prev_hblank && !curr_hblank) {+ if (gpu->event_cb_table[GPU_EVENT_HBLANK_END])
+ gpu->event_cb_table[GPU_EVENT_HBLANK_END](gpu);
+
+ gpu->cycles -= (float)GPU_CYCLES_PER_SCANL_NTSC;
+ }
+}
+
+void* psx_gpu_get_display_buffer(psx_gpu_t* gpu) {+ if (gpu->gpustat & 0x800000)
+ return gpu->empty;
+
+ return gpu->vram + (gpu->disp_x + (gpu->disp_y * 1024));
+}
+
+void psx_gpu_destroy(psx_gpu_t* gpu) {+ free(gpu->vram);
+ free(gpu);
+}
--- a/psx/dev/gpu.h
+++ b/psx/dev/gpu.h
@@ -1,174 +1,174 @@
#ifndef PSX_DEV_GPU_H
-#define PSX_DEV_GPU_H
-
-#include "p9.h"
-
-#include "dev/ic.h"
-
-#define PSX_GPU_BEGIN 0x1f801810
-#define PSX_GPU_SIZE 0x8
-#define PSX_GPU_END 0x1f801814
-
-#define PSX_GPU_FB_WIDTH 1024
-#define PSX_GPU_FB_HEIGHT 512
-
-// Use this when updating your texture
-#define PSX_GPU_FB_STRIDE 2048
-
-// 0x100000 * 2
-#define PSX_GPU_VRAM_SIZE (0x200000)
-
-#define PSX_GPU_CLOCK_NTSC 53693175 // 53.693175 MHz
-#define PSX_GPU_CLOCK_FREQ_NTSC 53.693175f // 53.693175 MHz
-#define PSX_GPU_CLOCK_FREQ_PAL 53.203425f // 53.203425 MHz
-
-enum {
- GPU_EVENT_DMODE,
- GPU_EVENT_VBLANK,
- GPU_EVENT_VBLANK_END,
- GPU_EVENT_HBLANK,
- GPU_EVENT_HBLANK_END,
- GPU_EVENT_VBLANK_TIMER
-};
-
-enum {
- GPU_STATE_RECV_CMD,
- GPU_STATE_RECV_ARGS,
- GPU_STATE_RECV_DATA
-};
-
-struct psx_gpu_t;
-
-typedef struct psx_gpu_t psx_gpu_t;
-
-typedef void (*psx_gpu_cmd_t)(psx_gpu_t*);
-typedef void (*psx_gpu_event_callback_t)(psx_gpu_t*);
-
-enum {
- RS_VARIABLE,
- RS_1X1,
- RS_8X8,
- RS_16X16
-};
-
-enum {
- RA_RAW = 0x01,
- RA_TRANSP = 0x02,
- RA_TEXTURED = 0x04
-};
-
-enum {
- PA_RAW = 0x01,
- PA_TRANSP = 0x02,
- PA_TEXTURED = 0x04,
- PA_QUAD = 0x08,
- PA_SHADED = 0x10
-};
-
-typedef struct {
- int16_t x, y;
- uint32_t c;
- uint8_t tx, ty;
-} vertex_t;
-
-typedef struct {
- uint8_t attrib;
- vertex_t v[4];
- uint16_t clut, texp;
-} poly_data_t;
-
-typedef struct {
- uint8_t attrib;
- vertex_t v0;
- uint16_t clut;
- uint16_t width, height;
-} rect_data_t;
-
-struct psx_gpu_t {
- uint32_t bus_delay;
- uint32_t io_base, io_size;
-
- void* udata[4];
-
- uint16_t* vram;
- uint16_t* empty;
- int display_enable;
-
- // State data
- uint32_t buf[16];
- uint32_t recv_data;
- int buf_index;
- int cmd_args_remaining;
- int cmd_data_remaining;
- int line_done;
- vertex_t prev_line_vertex;
-
- // Command counters
- uint32_t color;
- uint32_t xpos, ypos;
- uint32_t xsiz, ysiz;
- uint32_t tsiz;
- uint32_t addr;
- uint32_t xcnt, ycnt;
- vertex_t v0, v1, v2, v3;
- uint32_t pal, texp;
- uint32_t c0_xcnt, c0_ycnt;
- uint32_t c0_addr;
- int c0_xsiz, c0_ysiz;
- int c0_tsiz;
- int gp1_10h_req;
-
- // GPU state
- uint32_t state;
-
- uint32_t display_mode;
- uint32_t gpuread;
- uint32_t gpustat;
-
- // Drawing area
- uint32_t draw_x1, draw_y1;
- uint32_t draw_x2, draw_y2;
-
- // Drawing offset
- int32_t off_x, off_y;
-
- // Texture Window
- uint32_t texw_mx, texw_my;
- uint32_t texw_ox, texw_oy;
-
- // CLUT offset
- uint32_t clut_x, clut_y;
-
- // Texture page
- uint32_t texp_x, texp_y;
- uint32_t texp_d;
-
- // Display area
- uint32_t disp_x, disp_y;
- uint32_t disp_x1, disp_x2;
- uint32_t disp_y1, disp_y2;
-
- // Timing and IRQs
- float cycles;
- int line;
-
- psx_ic_t* ic;
-
- psx_gpu_event_callback_t event_cb_table[8];
-};
-
-psx_gpu_t* psx_gpu_create(void);
-void psx_gpu_init(psx_gpu_t*, psx_ic_t*);
-uint32_t psx_gpu_read32(psx_gpu_t*, uint32_t);
-uint16_t psx_gpu_read16(psx_gpu_t*, uint32_t);
-uint8_t psx_gpu_read8(psx_gpu_t*, uint32_t);
-void psx_gpu_write32(psx_gpu_t*, uint32_t, uint32_t);
-void psx_gpu_write16(psx_gpu_t*, uint32_t, uint16_t);
-void psx_gpu_write8(psx_gpu_t*, uint32_t, uint8_t);
-void psx_gpu_destroy(psx_gpu_t*);
-void psx_gpu_set_udata(psx_gpu_t*, int, void*);
-void psx_gpu_set_event_callback(psx_gpu_t*, int, psx_gpu_event_callback_t);
-void* psx_gpu_get_display_buffer(psx_gpu_t*);
-void psx_gpu_update(psx_gpu_t*, int);
-
+#define PSX_DEV_GPU_H
+
+#include "p9.h"
+
+#include "dev/ic.h"
+
+#define PSX_GPU_BEGIN 0x1f801810
+#define PSX_GPU_SIZE 0x8
+#define PSX_GPU_END 0x1f801814
+
+#define PSX_GPU_FB_WIDTH 1024
+#define PSX_GPU_FB_HEIGHT 512
+
+// Use this when updating your texture
+#define PSX_GPU_FB_STRIDE 2048
+
+// 0x100000 * 2
+#define PSX_GPU_VRAM_SIZE (0x200000)
+
+#define PSX_GPU_CLOCK_NTSC 53693175 // 53.693175 MHz
+#define PSX_GPU_CLOCK_FREQ_NTSC 53.693175f // 53.693175 MHz
+#define PSX_GPU_CLOCK_FREQ_PAL 53.203425f // 53.203425 MHz
+
+enum {+ GPU_EVENT_DMODE,
+ GPU_EVENT_VBLANK,
+ GPU_EVENT_VBLANK_END,
+ GPU_EVENT_HBLANK,
+ GPU_EVENT_HBLANK_END,
+ GPU_EVENT_VBLANK_TIMER
+};
+
+enum {+ GPU_STATE_RECV_CMD,
+ GPU_STATE_RECV_ARGS,
+ GPU_STATE_RECV_DATA
+};
+
+struct psx_gpu_t;
+
+typedef struct psx_gpu_t psx_gpu_t;
+
+typedef void (*psx_gpu_cmd_t)(psx_gpu_t*);
+typedef void (*psx_gpu_event_callback_t)(psx_gpu_t*);
+
+enum {+ RS_VARIABLE,
+ RS_1X1,
+ RS_8X8,
+ RS_16X16
+};
+
+enum {+ RA_RAW = 0x01,
+ RA_TRANSP = 0x02,
+ RA_TEXTURED = 0x04
+};
+
+enum {+ PA_RAW = 0x01,
+ PA_TRANSP = 0x02,
+ PA_TEXTURED = 0x04,
+ PA_QUAD = 0x08,
+ PA_SHADED = 0x10
+};
+
+typedef struct {+ int16_t x, y;
+ uint32_t c;
+ uint8_t tx, ty;
+} vertex_t;
+
+typedef struct {+ uint8_t attrib;
+ vertex_t v[4];
+ uint16_t clut, texp;
+} poly_data_t;
+
+typedef struct {+ uint8_t attrib;
+ vertex_t v0;
+ uint16_t clut;
+ uint16_t width, height;
+} rect_data_t;
+
+struct psx_gpu_t {+ uint32_t bus_delay;
+ uint32_t io_base, io_size;
+
+ void* udata[4];
+
+ uint16_t* vram;
+ uint16_t* empty;
+ int display_enable;
+
+ // State data
+ uint32_t buf[16];
+ uint32_t recv_data;
+ int buf_index;
+ int cmd_args_remaining;
+ int cmd_data_remaining;
+ int line_done;
+ vertex_t prev_line_vertex;
+
+ // Command counters
+ uint32_t color;
+ uint32_t xpos, ypos;
+ uint32_t xsiz, ysiz;
+ uint32_t tsiz;
+ uint32_t addr;
+ uint32_t xcnt, ycnt;
+ vertex_t v0, v1, v2, v3;
+ uint32_t pal, texp;
+ uint32_t c0_xcnt, c0_ycnt;
+ uint32_t c0_addr;
+ int c0_xsiz, c0_ysiz;
+ int c0_tsiz;
+ int gp1_10h_req;
+
+ // GPU state
+ uint32_t state;
+
+ uint32_t display_mode;
+ uint32_t gpuread;
+ uint32_t gpustat;
+
+ // Drawing area
+ uint32_t draw_x1, draw_y1;
+ uint32_t draw_x2, draw_y2;
+
+ // Drawing offset
+ int32_t off_x, off_y;
+
+ // Texture Window
+ uint32_t texw_mx, texw_my;
+ uint32_t texw_ox, texw_oy;
+
+ // CLUT offset
+ uint32_t clut_x, clut_y;
+
+ // Texture page
+ uint32_t texp_x, texp_y;
+ uint32_t texp_d;
+
+ // Display area
+ uint32_t disp_x, disp_y;
+ uint32_t disp_x1, disp_x2;
+ uint32_t disp_y1, disp_y2;
+
+ // Timing and IRQs
+ float cycles;
+ int line;
+
+ psx_ic_t* ic;
+
+ psx_gpu_event_callback_t event_cb_table[8];
+};
+
+psx_gpu_t* psx_gpu_create(void);
+void psx_gpu_init(psx_gpu_t*, psx_ic_t*);
+uint32_t psx_gpu_read32(psx_gpu_t*, uint32_t);
+uint16_t psx_gpu_read16(psx_gpu_t*, uint32_t);
+uint8_t psx_gpu_read8(psx_gpu_t*, uint32_t);
+void psx_gpu_write32(psx_gpu_t*, uint32_t, uint32_t);
+void psx_gpu_write16(psx_gpu_t*, uint32_t, uint16_t);
+void psx_gpu_write8(psx_gpu_t*, uint32_t, uint8_t);
+void psx_gpu_destroy(psx_gpu_t*);
+void psx_gpu_set_udata(psx_gpu_t*, int, void*);
+void psx_gpu_set_event_callback(psx_gpu_t*, int, psx_gpu_event_callback_t);
+void* psx_gpu_get_display_buffer(psx_gpu_t*);
+void psx_gpu_update(psx_gpu_t*, int);
+
#endif
\ No newline at end of file
--- a/psx/dev/ic.c
+++ b/psx/dev/ic.c
@@ -1,123 +1,123 @@
-#include "p9.h"
-
-#include "dev/ic.h"
-
-#include "log.h"
-
-psx_ic_t* psx_ic_create(void) {
- return (psx_ic_t*)malloc(sizeof(psx_ic_t));
-}
-
-void psx_ic_init(psx_ic_t* ic, psx_cpu_t* cpu) {
- memset(ic, 0, sizeof(psx_ic_t));
-
- ic->io_base = PSX_IC_BEGIN;
- ic->io_size = PSX_IC_SIZE;
-
- ic->stat = 0x00000000;
- ic->mask = 0x00000000;
-
- ic->cpu = cpu;
-}
-
-uint32_t psx_ic_read32(psx_ic_t* ic, uint32_t offset) {
- switch (offset) {
- case 0x00: return ic->stat;
- case 0x04: return ic->mask;
- }
-
- log_fatal("Unhandled 32-bit IC read at offset %08x", offset);
-
- return 0x0;
-}
-
-uint16_t psx_ic_read16(psx_ic_t* ic, uint32_t offset) {
- switch (offset) {
- case 0x00: return (ic->stat >> 0 ) & 0xffff;
- case 0x02: return (ic->stat >> 16) & 0xffff;
- case 0x04: return (ic->mask >> 0 ) & 0xffff;
- case 0x06: return (ic->mask >> 16) & 0xffff;
- }
-
- return 0x0;
-}
-
-uint8_t psx_ic_read8(psx_ic_t* ic, uint32_t offset) {
- switch (offset) {
- case 0x00: return (ic->stat >> 0 ) & 0xff;
- case 0x01: return (ic->stat >> 8 ) & 0xff;
- case 0x02: return (ic->stat >> 16) & 0xff;
- case 0x03: return (ic->stat >> 24) & 0xff;
- case 0x04: return (ic->mask >> 0 ) & 0xff;
- case 0x05: return (ic->mask >> 8 ) & 0xff;
- case 0x06: return (ic->mask >> 16) & 0xff;
- case 0x07: return (ic->mask >> 24) & 0xff;
- }
-
- return 0x0;
-}
-
-void psx_ic_write32(psx_ic_t* ic, uint32_t offset, uint32_t value) {
- switch (offset) {
- case 0x00: ic->stat &= value; break;
- case 0x04: ic->mask = value; break;
-
- default: {
- log_fatal("Unhandled 32-bit IC write at offset %08x (%08x)", offset, value);
- } break;
- }
-
- // Emulate acknowledge
- if (!(ic->stat & ic->mask)) {
- ic->cpu->cop0_r[COP0_CAUSE] &= ~SR_IM2;
- } else {
- psx_cpu_set_irq_pending(ic->cpu);
- }
-}
-
-void psx_ic_write16(psx_ic_t* ic, uint32_t offset, uint16_t value) {
- switch (offset) {
- case 0x00: ic->stat &= ((uint32_t)value) << 0 ; break;
- case 0x02: ic->stat &= ((uint32_t)value) << 16; break;
- case 0x04: ic->mask = ((uint32_t)value) << 0 ; break;
- case 0x06: ic->mask = ((uint32_t)value) << 16; break;
- }
-
- // Emulate acknowledge
- if (!(ic->stat & ic->mask)) {
- ic->cpu->cop0_r[COP0_CAUSE] &= ~SR_IM2;
- } else {
- psx_cpu_set_irq_pending(ic->cpu);
- }
-}
-
-void psx_ic_write8(psx_ic_t* ic, uint32_t offset, uint8_t value) {
- switch (offset) {
- case 0x00: ic->stat &= ((uint32_t)value) << 0 ; break;
- case 0x01: ic->stat &= ((uint32_t)value) << 8 ; break;
- case 0x02: ic->stat &= ((uint32_t)value) << 16; break;
- case 0x03: ic->stat &= ((uint32_t)value) << 24; break;
- case 0x04: ic->mask = ((uint32_t)value) << 0 ; break;
- case 0x05: ic->mask = ((uint32_t)value) << 8 ; break;
- case 0x06: ic->mask = ((uint32_t)value) << 16; break;
- case 0x07: ic->mask = ((uint32_t)value) << 24; break;
- }
-
- // Emulate acknowledge
- if (!(ic->stat & ic->mask)) {
- ic->cpu->cop0_r[COP0_CAUSE] &= ~SR_IM2;
- } else {
- psx_cpu_set_irq_pending(ic->cpu);
- }
-}
-
-void psx_ic_irq(psx_ic_t* ic, int id) {
- ic->stat |= id;
-
- if (ic->mask & ic->stat)
- psx_cpu_set_irq_pending(ic->cpu);
-}
-
-void psx_ic_destroy(psx_ic_t* ic) {
- free(ic);
+#include "p9.h"
+
+#include "dev/ic.h"
+
+#include "log.h"
+
+psx_ic_t* psx_ic_create(void) {+ return (psx_ic_t*)malloc(sizeof(psx_ic_t));
+}
+
+void psx_ic_init(psx_ic_t* ic, psx_cpu_t* cpu) {+ memset(ic, 0, sizeof(psx_ic_t));
+
+ ic->io_base = PSX_IC_BEGIN;
+ ic->io_size = PSX_IC_SIZE;
+
+ ic->stat = 0x00000000;
+ ic->mask = 0x00000000;
+
+ ic->cpu = cpu;
+}
+
+uint32_t psx_ic_read32(psx_ic_t* ic, uint32_t offset) {+ switch (offset) {+ case 0x00: return ic->stat;
+ case 0x04: return ic->mask;
+ }
+
+ log_fatal("Unhandled 32-bit IC read at offset %08x", offset);+
+ return 0x0;
+}
+
+uint16_t psx_ic_read16(psx_ic_t* ic, uint32_t offset) {+ switch (offset) {+ case 0x00: return (ic->stat >> 0 ) & 0xffff;
+ case 0x02: return (ic->stat >> 16) & 0xffff;
+ case 0x04: return (ic->mask >> 0 ) & 0xffff;
+ case 0x06: return (ic->mask >> 16) & 0xffff;
+ }
+
+ return 0x0;
+}
+
+uint8_t psx_ic_read8(psx_ic_t* ic, uint32_t offset) {+ switch (offset) {+ case 0x00: return (ic->stat >> 0 ) & 0xff;
+ case 0x01: return (ic->stat >> 8 ) & 0xff;
+ case 0x02: return (ic->stat >> 16) & 0xff;
+ case 0x03: return (ic->stat >> 24) & 0xff;
+ case 0x04: return (ic->mask >> 0 ) & 0xff;
+ case 0x05: return (ic->mask >> 8 ) & 0xff;
+ case 0x06: return (ic->mask >> 16) & 0xff;
+ case 0x07: return (ic->mask >> 24) & 0xff;
+ }
+
+ return 0x0;
+}
+
+void psx_ic_write32(psx_ic_t* ic, uint32_t offset, uint32_t value) {+ switch (offset) {+ case 0x00: ic->stat &= value; break;
+ case 0x04: ic->mask = value; break;
+
+ default: {+ log_fatal("Unhandled 32-bit IC write at offset %08x (%08x)", offset, value);+ } break;
+ }
+
+ // Emulate acknowledge
+ if (!(ic->stat & ic->mask)) {+ ic->cpu->cop0_r[COP0_CAUSE] &= ~SR_IM2;
+ } else {+ psx_cpu_set_irq_pending(ic->cpu);
+ }
+}
+
+void psx_ic_write16(psx_ic_t* ic, uint32_t offset, uint16_t value) {+ switch (offset) {+ case 0x00: ic->stat &= ((uint32_t)value) << 0 ; break;
+ case 0x02: ic->stat &= ((uint32_t)value) << 16; break;
+ case 0x04: ic->mask = ((uint32_t)value) << 0 ; break;
+ case 0x06: ic->mask = ((uint32_t)value) << 16; break;
+ }
+
+ // Emulate acknowledge
+ if (!(ic->stat & ic->mask)) {+ ic->cpu->cop0_r[COP0_CAUSE] &= ~SR_IM2;
+ } else {+ psx_cpu_set_irq_pending(ic->cpu);
+ }
+}
+
+void psx_ic_write8(psx_ic_t* ic, uint32_t offset, uint8_t value) {+ switch (offset) {+ case 0x00: ic->stat &= ((uint32_t)value) << 0 ; break;
+ case 0x01: ic->stat &= ((uint32_t)value) << 8 ; break;
+ case 0x02: ic->stat &= ((uint32_t)value) << 16; break;
+ case 0x03: ic->stat &= ((uint32_t)value) << 24; break;
+ case 0x04: ic->mask = ((uint32_t)value) << 0 ; break;
+ case 0x05: ic->mask = ((uint32_t)value) << 8 ; break;
+ case 0x06: ic->mask = ((uint32_t)value) << 16; break;
+ case 0x07: ic->mask = ((uint32_t)value) << 24; break;
+ }
+
+ // Emulate acknowledge
+ if (!(ic->stat & ic->mask)) {+ ic->cpu->cop0_r[COP0_CAUSE] &= ~SR_IM2;
+ } else {+ psx_cpu_set_irq_pending(ic->cpu);
+ }
+}
+
+void psx_ic_irq(psx_ic_t* ic, int id) {+ ic->stat |= id;
+
+ if (ic->mask & ic->stat)
+ psx_cpu_set_irq_pending(ic->cpu);
+}
+
+void psx_ic_destroy(psx_ic_t* ic) {+ free(ic);
}
\ No newline at end of file
--- a/psx/dev/ic.h
+++ b/psx/dev/ic.h
@@ -1,48 +1,48 @@
#ifndef PSX_DEV_IC_H
-#define PSX_DEV_IC_H
-
-#include "p9.h"
-
-#include "cpu.h"
-
-#define PSX_IC_BEGIN 0x1f801070
-#define PSX_IC_SIZE 0x8
-#define PSX_IC_END 0x1F801077
-
-/*
- 0 IRQ0 VBLANK (PAL=50Hz, NTSC=60Hz)
- 1 IRQ1 GPU Can be requested via GP0(1Fh) command (rarely used)
- 2 IRQ2 CDROM
- 3 IRQ3 DMA
- 4 IRQ4 TMR0 Timer 0 aka Root Counter 0 (Sysclk or Dotclk)
- 5 IRQ5 TMR1 Timer 1 aka Root Counter 1 (Sysclk or H-blank)
- 6 IRQ6 TMR2 Timer 2 aka Root Counter 2 (Sysclk or Sysclk/8)
- 7 IRQ7 Controller and Memory Card - Byte Received Interrupt
- 8 IRQ8 SIO
- 9 IRQ9 SPU
- 10 IRQ10 Controller - Lightpen Interrupt (reportedly also PIO...?)
- 11-15 Not used (always zero)
- 16-31 Garbage
-*/
-enum {
- IC_VBLANK = 0x001,
- IC_GPU = 0x002,
- IC_CDROM = 0x004,
- IC_DMA = 0x008,
- IC_TIMER0 = 0x010,
- IC_TIMER1 = 0x020,
- IC_TIMER2 = 0x040,
- IC_JOY = 0x080,
- IC_SIO = 0x100,
- IC_SPU = 0x200,
- IC_LP_PIO = 0x400
-};
-
-/*
- 1F801070h 2 I_STAT - Interrupt status register
- 1F801074h 2 I_MASK - Interrupt mask register
-*/
-
+#define PSX_DEV_IC_H
+
+#include "p9.h"
+
+#include "cpu.h"
+
+#define PSX_IC_BEGIN 0x1f801070
+#define PSX_IC_SIZE 0x8
+#define PSX_IC_END 0x1F801077
+
+/*
+ 0 IRQ0 VBLANK (PAL=50Hz, NTSC=60Hz)
+ 1 IRQ1 GPU Can be requested via GP0(1Fh) command (rarely used)
+ 2 IRQ2 CDROM
+ 3 IRQ3 DMA
+ 4 IRQ4 TMR0 Timer 0 aka Root Counter 0 (Sysclk or Dotclk)
+ 5 IRQ5 TMR1 Timer 1 aka Root Counter 1 (Sysclk or H-blank)
+ 6 IRQ6 TMR2 Timer 2 aka Root Counter 2 (Sysclk or Sysclk/8)
+ 7 IRQ7 Controller and Memory Card - Byte Received Interrupt
+ 8 IRQ8 SIO
+ 9 IRQ9 SPU
+ 10 IRQ10 Controller - Lightpen Interrupt (reportedly also PIO...?)
+ 11-15 Not used (always zero)
+ 16-31 Garbage
+*/
+enum {+ IC_VBLANK = 0x001,
+ IC_GPU = 0x002,
+ IC_CDROM = 0x004,
+ IC_DMA = 0x008,
+ IC_TIMER0 = 0x010,
+ IC_TIMER1 = 0x020,
+ IC_TIMER2 = 0x040,
+ IC_JOY = 0x080,
+ IC_SIO = 0x100,
+ IC_SPU = 0x200,
+ IC_LP_PIO = 0x400
+};
+
+/*
+ 1F801070h 2 I_STAT - Interrupt status register
+ 1F801074h 2 I_MASK - Interrupt mask register
+*/
+
struct psx_ic_t {uint32_t bus_delay;
uint32_t io_base, io_size;
@@ -54,16 +54,16 @@
};
typedef struct psx_ic_t psx_ic_t;
-
-psx_ic_t* psx_ic_create(void);
-void psx_ic_init(psx_ic_t*, psx_cpu_t*);
-uint32_t psx_ic_read32(psx_ic_t*, uint32_t);
-uint16_t psx_ic_read16(psx_ic_t*, uint32_t);
-uint8_t psx_ic_read8(psx_ic_t*, uint32_t);
-void psx_ic_write32(psx_ic_t*, uint32_t, uint32_t);
-void psx_ic_write16(psx_ic_t*, uint32_t, uint16_t);
-void psx_ic_write8(psx_ic_t*, uint32_t, uint8_t);
-void psx_ic_irq(psx_ic_t*, int);
-void psx_ic_destroy(psx_ic_t*);
-
+
+psx_ic_t* psx_ic_create(void);
+void psx_ic_init(psx_ic_t*, psx_cpu_t*);
+uint32_t psx_ic_read32(psx_ic_t*, uint32_t);
+uint16_t psx_ic_read16(psx_ic_t*, uint32_t);
+uint8_t psx_ic_read8(psx_ic_t*, uint32_t);
+void psx_ic_write32(psx_ic_t*, uint32_t, uint32_t);
+void psx_ic_write16(psx_ic_t*, uint32_t, uint16_t);
+void psx_ic_write8(psx_ic_t*, uint32_t, uint8_t);
+void psx_ic_irq(psx_ic_t*, int);
+void psx_ic_destroy(psx_ic_t*);
+
#endif
--- a/psx/dev/input.c
+++ b/psx/dev/input.c
@@ -1,31 +1,31 @@
#include "dev/input.h"
#include "p9.h"
-
-psx_input_t* psx_input_create(void) {
- return (psx_input_t*)malloc(sizeof(psx_input_t));
-}
-
-void psx_input_init(psx_input_t* input) {
- memset(input, 0, sizeof(psx_input_t));
-}
-
-void psx_input_set_write_func(psx_input_t* input, psx_input_write_t write_func) {
- input->write_func = write_func;
-}
-
-void psx_input_set_read_func(psx_input_t* input, psx_input_read_t read_func) {
- input->read_func = read_func;
-}
-
-void psx_input_set_on_button_press_func(psx_input_t* input, psx_input_on_button_press_t on_button_press_func) {
- input->on_button_press_func = on_button_press_func;
-}
-
-void psx_input_set_on_button_release_func(psx_input_t* input, psx_input_on_button_release_t on_button_release_func) {
- input->on_button_release_func = on_button_release_func;
-}
-
+
+psx_input_t* psx_input_create(void) {+ return (psx_input_t*)malloc(sizeof(psx_input_t));
+}
+
+void psx_input_init(psx_input_t* input) {+ memset(input, 0, sizeof(psx_input_t));
+}
+
+void psx_input_set_write_func(psx_input_t* input, psx_input_write_t write_func) {+ input->write_func = write_func;
+}
+
+void psx_input_set_read_func(psx_input_t* input, psx_input_read_t read_func) {+ input->read_func = read_func;
+}
+
+void psx_input_set_on_button_press_func(psx_input_t* input, psx_input_on_button_press_t on_button_press_func) {+ input->on_button_press_func = on_button_press_func;
+}
+
+void psx_input_set_on_button_release_func(psx_input_t* input, psx_input_on_button_release_t on_button_release_func) {+ input->on_button_release_func = on_button_release_func;
+}
+
void psx_input_set_on_analog_change_func(psx_input_t* input, psx_input_on_analog_change_t on_analog_change_func) {input->on_analog_change_func = on_analog_change_func;
}
--- a/psx/dev/input.h
+++ b/psx/dev/input.h
@@ -1,38 +1,38 @@
#ifndef PSX_DEV_INPUT_H
-#define PSX_DEV_INPUT_H
-
-#include "p9.h"
-
-struct psx_input_t;
-
-typedef struct psx_input_t psx_input_t;
-
-typedef void (*psx_input_write_t)(void*, uint16_t);
-typedef uint32_t (*psx_input_read_t)(void*);
-typedef void (*psx_input_on_button_press_t)(void*, uint32_t);
-typedef void (*psx_input_on_button_release_t)(void*, uint32_t);
-typedef void (*psx_input_on_analog_change_t)(void*, uint32_t, uint16_t);
-typedef int (*psx_input_query_fifo_t)(void*);
-
-struct psx_input_t {
- void* udata;
-
- psx_input_write_t write_func;
- psx_input_read_t read_func;
- psx_input_on_button_press_t on_button_press_func;
- psx_input_on_button_release_t on_button_release_func;
- psx_input_on_analog_change_t on_analog_change_func;
- psx_input_query_fifo_t query_fifo_func;
-};
-
-psx_input_t* psx_input_create(void);
-void psx_input_init(psx_input_t*);
-void psx_input_set_write_func(psx_input_t*, psx_input_write_t);
-void psx_input_set_read_func(psx_input_t*, psx_input_read_t);
-void psx_input_set_on_button_press_func(psx_input_t*, psx_input_on_button_press_t);
-void psx_input_set_on_button_release_func(psx_input_t*, psx_input_on_button_release_t);
-void psx_input_set_on_analog_change_func(psx_input_t*, psx_input_on_analog_change_t);
-void psx_input_set_query_fifo_func(psx_input_t*, psx_input_query_fifo_t);
-void psx_input_destroy(psx_input_t*);
-
+#define PSX_DEV_INPUT_H
+
+#include "p9.h"
+
+struct psx_input_t;
+
+typedef struct psx_input_t psx_input_t;
+
+typedef void (*psx_input_write_t)(void*, uint16_t);
+typedef uint32_t (*psx_input_read_t)(void*);
+typedef void (*psx_input_on_button_press_t)(void*, uint32_t);
+typedef void (*psx_input_on_button_release_t)(void*, uint32_t);
+typedef void (*psx_input_on_analog_change_t)(void*, uint32_t, uint16_t);
+typedef int (*psx_input_query_fifo_t)(void*);
+
+struct psx_input_t {+ void* udata;
+
+ psx_input_write_t write_func;
+ psx_input_read_t read_func;
+ psx_input_on_button_press_t on_button_press_func;
+ psx_input_on_button_release_t on_button_release_func;
+ psx_input_on_analog_change_t on_analog_change_func;
+ psx_input_query_fifo_t query_fifo_func;
+};
+
+psx_input_t* psx_input_create(void);
+void psx_input_init(psx_input_t*);
+void psx_input_set_write_func(psx_input_t*, psx_input_write_t);
+void psx_input_set_read_func(psx_input_t*, psx_input_read_t);
+void psx_input_set_on_button_press_func(psx_input_t*, psx_input_on_button_press_t);
+void psx_input_set_on_button_release_func(psx_input_t*, psx_input_on_button_release_t);
+void psx_input_set_on_analog_change_func(psx_input_t*, psx_input_on_analog_change_t);
+void psx_input_set_query_fifo_func(psx_input_t*, psx_input_query_fifo_t);
+void psx_input_destroy(psx_input_t*);
+
#endif
\ No newline at end of file
--- a/psx/dev/mc1.c
+++ b/psx/dev/mc1.c
@@ -1,27 +1,27 @@
-#include "p9.h"
-
-#include "dev/mc1.h"
-#include "log.h"
-
-/*
- 0-3 Write Delay (00h..0Fh=01h..10h Cycles)
- 4-7 Read Delay (00h..0Fh=01h..10h Cycles)
- 8 Recovery Period (0=No, 1=Yes, uses COM0 timings)
- 9 Hold Period (0=No, 1=Yes, uses COM1 timings)
- 10 Floating Period (0=No, 1=Yes, uses COM2 timings)
- 11 Pre-strobe Period (0=No, 1=Yes, uses COM3 timings)
- 12 Data Bus-width (0=8bits, 1=16bits)
- 13 Auto Increment (0=No, 1=Yes)
- 14-15 Unknown (R/W)
- 16-20 Memory Window Size (1 SHL N bytes) (0..1Fh = 1 byte ... 2 gigabytes)
- 21-23 Unknown (always zero)
- 24-27 DMA timing override
- 28 Address error flag. Write 1 to it to clear it.
- 29 DMA timing select (0=use normal timings, 1=use bits 24-27)
- 30 Wide DMA (0=use bit 12, 1=override to full 32 bits)
- 31 Wait (1=wait on external device before being ready)
-*/
-
+#include "p9.h"
+
+#include "dev/mc1.h"
+#include "log.h"
+
+/*
+ 0-3 Write Delay (00h..0Fh=01h..10h Cycles)
+ 4-7 Read Delay (00h..0Fh=01h..10h Cycles)
+ 8 Recovery Period (0=No, 1=Yes, uses COM0 timings)
+ 9 Hold Period (0=No, 1=Yes, uses COM1 timings)
+ 10 Floating Period (0=No, 1=Yes, uses COM2 timings)
+ 11 Pre-strobe Period (0=No, 1=Yes, uses COM3 timings)
+ 12 Data Bus-width (0=8bits, 1=16bits)
+ 13 Auto Increment (0=No, 1=Yes)
+ 14-15 Unknown (R/W)
+ 16-20 Memory Window Size (1 SHL N bytes) (0..1Fh = 1 byte ... 2 gigabytes)
+ 21-23 Unknown (always zero)
+ 24-27 DMA timing override
+ 28 Address error flag. Write 1 to it to clear it.
+ 29 DMA timing select (0=use normal timings, 1=use bits 24-27)
+ 30 Wide DMA (0=use bit 12, 1=override to full 32 bits)
+ 31 Wait (1=wait on external device before being ready)
+*/
+
static uint32_t
mc1_default_delay(psx_mc1_t* mc1)
{@@ -30,105 +30,105 @@
}
#define DEFAULT_DLY mc1_default_delay(mc1)
-
-// #define WRITE_DLY(dev) ((mc1-> ## dev ## _delay & 0xf) + 1)
-// #define READ_DLY(dev) (((mc1-> ## dev ## _delay >> 4) & 0xf) + 1)
-// #define USE_COM0(dev) (mc1-> ## dev ## _delay >> 8)
-// #define USE_COM1(dev) (mc1-> ## dev ## _delay >> 9)
-// #define USE_COM2(dev) (mc1-> ## dev ## _delay >> 10)
-// #define USE_COM3(dev) (mc1-> ## dev ## _delay >> 11)
-
-// #define COM0_DLY (mc1->com_delay )
-
-// psx_access_delay_t mc1_get_com_delay(int uc0, int uc1, int uc2, int uc3) {
-// int fst = 0, seq = 0, min = 0;
-// }
-
-// #define COM_DLY(dev)
-
-psx_mc1_t* psx_mc1_create(void) {
- return (psx_mc1_t*)malloc(sizeof(psx_mc1_t));
-}
-
-/*
- 1F801000h 4 Expansion 1 Base Address (usually 1F000000h)
- 1F801004h 4 Expansion 2 Base Address (usually 1F802000h)
- 1F801008h 4 Expansion 1 Delay/Size (usually 0013243Fh; 512Kbytes 8bit-bus)
- 1F80100Ch 4 Expansion 3 Delay/Size (usually 00003022h; 1 byte)
- 1F801010h 4 BIOS ROM Delay/Size (usually 0013243Fh; 512Kbytes 8bit-bus)
- 1F801014h 4 SPU_DELAY Delay/Size (usually 200931E1h)
- 1F801018h 4 CDROM_DELAY Delay/Size (usually 00020843h or 00020943h)
- 1F80101Ch 4 Expansion 2 Delay/Size (usually 00070777h; 128-bytes 8bit-bus)
- 1F801020h 4 COM_DELAY / COMMON_DELAY (00031125h or 0000132Ch or 00001325h)
-*/
-void psx_mc1_init(psx_mc1_t* mc1) {
- memset(mc1, 0, sizeof(psx_mc1_t));
-
- mc1->io_base = PSX_MC1_BEGIN;
- mc1->io_size = PSX_MC1_SIZE;
-
- mc1->exp1_base = 0x1f000000;
- mc1->exp2_base = 0x1f802000;
- mc1->exp1_delay = 0x0013243f;
- mc1->exp3_delay = 0x00003022;
- mc1->bios_delay = 0x0013243f;
- mc1->spu_delay = 0x200931e1;
- mc1->cdrom_delay = 0x00020843;
- mc1->exp2_delay = 0x00070777;
- mc1->com_delay = 0x00031125;
-}
-
-uint32_t psx_mc1_read32(psx_mc1_t* mc1, uint32_t offset) {
- switch (offset) {
- case 0x00: return mc1->exp1_base;
- case 0x04: return mc1->exp2_base;
- case 0x08: return mc1->exp1_delay;
- case 0x0c: return mc1->exp3_delay;
- case 0x10: return mc1->bios_delay;
- case 0x14: return mc1->spu_delay;
- case 0x18: return mc1->cdrom_delay;
- case 0x1c: return mc1->exp2_delay;
- case 0x20: return mc1->com_delay;
- }
-
- log_warn("Unhandled 32-bit MC1 read at offset %08x", offset);
-
- return 0x0;
-}
-
+
+// #define WRITE_DLY(dev) ((mc1-> ## dev ## _delay & 0xf) + 1)
+// #define READ_DLY(dev) (((mc1-> ## dev ## _delay >> 4) & 0xf) + 1)
+// #define USE_COM0(dev) (mc1-> ## dev ## _delay >> 8)
+// #define USE_COM1(dev) (mc1-> ## dev ## _delay >> 9)
+// #define USE_COM2(dev) (mc1-> ## dev ## _delay >> 10)
+// #define USE_COM3(dev) (mc1-> ## dev ## _delay >> 11)
+
+// #define COM0_DLY (mc1->com_delay )
+
+// psx_access_delay_t mc1_get_com_delay(int uc0, int uc1, int uc2, int uc3) {+// int fst = 0, seq = 0, min = 0;
+// }
+
+// #define COM_DLY(dev)
+
+psx_mc1_t* psx_mc1_create(void) {+ return (psx_mc1_t*)malloc(sizeof(psx_mc1_t));
+}
+
+/*
+ 1F801000h 4 Expansion 1 Base Address (usually 1F000000h)
+ 1F801004h 4 Expansion 2 Base Address (usually 1F802000h)
+ 1F801008h 4 Expansion 1 Delay/Size (usually 0013243Fh; 512Kbytes 8bit-bus)
+ 1F80100Ch 4 Expansion 3 Delay/Size (usually 00003022h; 1 byte)
+ 1F801010h 4 BIOS ROM Delay/Size (usually 0013243Fh; 512Kbytes 8bit-bus)
+ 1F801014h 4 SPU_DELAY Delay/Size (usually 200931E1h)
+ 1F801018h 4 CDROM_DELAY Delay/Size (usually 00020843h or 00020943h)
+ 1F80101Ch 4 Expansion 2 Delay/Size (usually 00070777h; 128-bytes 8bit-bus)
+ 1F801020h 4 COM_DELAY / COMMON_DELAY (00031125h or 0000132Ch or 00001325h)
+*/
+void psx_mc1_init(psx_mc1_t* mc1) {+ memset(mc1, 0, sizeof(psx_mc1_t));
+
+ mc1->io_base = PSX_MC1_BEGIN;
+ mc1->io_size = PSX_MC1_SIZE;
+
+ mc1->exp1_base = 0x1f000000;
+ mc1->exp2_base = 0x1f802000;
+ mc1->exp1_delay = 0x0013243f;
+ mc1->exp3_delay = 0x00003022;
+ mc1->bios_delay = 0x0013243f;
+ mc1->spu_delay = 0x200931e1;
+ mc1->cdrom_delay = 0x00020843;
+ mc1->exp2_delay = 0x00070777;
+ mc1->com_delay = 0x00031125;
+}
+
+uint32_t psx_mc1_read32(psx_mc1_t* mc1, uint32_t offset) {+ switch (offset) {+ case 0x00: return mc1->exp1_base;
+ case 0x04: return mc1->exp2_base;
+ case 0x08: return mc1->exp1_delay;
+ case 0x0c: return mc1->exp3_delay;
+ case 0x10: return mc1->bios_delay;
+ case 0x14: return mc1->spu_delay;
+ case 0x18: return mc1->cdrom_delay;
+ case 0x1c: return mc1->exp2_delay;
+ case 0x20: return mc1->com_delay;
+ }
+
+ log_warn("Unhandled 32-bit MC1 read at offset %08x", offset);+
+ return 0x0;
+}
+
uint16_t psx_mc1_read16(psx_mc1_t* mc1, uint32_t offset) {USED(mc1);
log_warn("Unhandled 16-bit MC1 read at offset %08x", offset);-
- return 0x0;
-}
-
+
+ return 0x0;
+}
+
uint8_t psx_mc1_read8(psx_mc1_t* mc1, uint32_t offset) {USED(mc1);
log_warn("Unhandled 8-bit MC1 read at offset %08x", offset);-
- return 0x0;
-}
-
-void psx_mc1_write32(psx_mc1_t* mc1, uint32_t offset, uint32_t value) {
- switch (offset) {
- case 0x00: mc1->exp1_base = value; break;
- case 0x04: mc1->exp2_base = value; break;
- case 0x08: mc1->exp1_delay = value; break;
- case 0x0c: mc1->exp3_delay = value; break;
- case 0x10: mc1->bios_delay = value; break;
- case 0x14: mc1->spu_delay = value; break;
- case 0x18: mc1->cdrom_delay = value; break;
- case 0x1c: mc1->exp2_delay = value; break;
- case 0x20: mc1->com_delay = value; break;
-
- default: {
- log_warn("Unhandled 32-bit MC1 write at offset %08x (%08x)", offset, value);
- } break;
- }
-}
-
-void psx_mc1_write16(psx_mc1_t* mc1, uint32_t offset, uint16_t value) {+
+ return 0x0;
+}
+
+void psx_mc1_write32(psx_mc1_t* mc1, uint32_t offset, uint32_t value) {+ switch (offset) {+ case 0x00: mc1->exp1_base = value; break;
+ case 0x04: mc1->exp2_base = value; break;
+ case 0x08: mc1->exp1_delay = value; break;
+ case 0x0c: mc1->exp3_delay = value; break;
+ case 0x10: mc1->bios_delay = value; break;
+ case 0x14: mc1->spu_delay = value; break;
+ case 0x18: mc1->cdrom_delay = value; break;
+ case 0x1c: mc1->exp2_delay = value; break;
+ case 0x20: mc1->com_delay = value; break;
+
+ default: {+ log_warn("Unhandled 32-bit MC1 write at offset %08x (%08x)", offset, value);+ } break;
+ }
+}
+
+void psx_mc1_write16(psx_mc1_t* mc1, uint32_t offset, uint16_t value) {USED(mc1);
log_warn("Unhandled 16-bit MC1 write at offset %08x (%04x)", offset, value);}
@@ -137,121 +137,121 @@
USED(mc1);
log_warn("Unhandled 8-bit MC1 write at offset %08x (%02x)", offset, value);}
-
-uint32_t psx_mc1_get_bios_read_delay(psx_mc1_t* mc1) {
- return DEFAULT_DLY;
-}
-
-uint32_t psx_mc1_get_ram_read_delay(psx_mc1_t* mc1) {
- return DEFAULT_DLY;
-}
-
-uint32_t psx_mc1_get_dma_read_delay(psx_mc1_t* mc1) {
- return DEFAULT_DLY;
-}
-
-uint32_t psx_mc1_get_exp1_read_delay(psx_mc1_t* mc1) {
- return DEFAULT_DLY;
-}
-
-uint32_t psx_mc1_get_mc1_read_delay(psx_mc1_t* mc1) {
- return DEFAULT_DLY;
-}
-
-uint32_t psx_mc1_get_mc2_read_delay(psx_mc1_t* mc1) {
- return DEFAULT_DLY;
-}
-
-uint32_t psx_mc1_get_mc3_read_delay(psx_mc1_t* mc1) {
- return DEFAULT_DLY;
-}
-
-uint32_t psx_mc1_get_ic_read_delay(psx_mc1_t* mc1) {
- return DEFAULT_DLY;
-}
-
+
+uint32_t psx_mc1_get_bios_read_delay(psx_mc1_t* mc1) {+ return DEFAULT_DLY;
+}
+
+uint32_t psx_mc1_get_ram_read_delay(psx_mc1_t* mc1) {+ return DEFAULT_DLY;
+}
+
+uint32_t psx_mc1_get_dma_read_delay(psx_mc1_t* mc1) {+ return DEFAULT_DLY;
+}
+
+uint32_t psx_mc1_get_exp1_read_delay(psx_mc1_t* mc1) {+ return DEFAULT_DLY;
+}
+
+uint32_t psx_mc1_get_mc1_read_delay(psx_mc1_t* mc1) {+ return DEFAULT_DLY;
+}
+
+uint32_t psx_mc1_get_mc2_read_delay(psx_mc1_t* mc1) {+ return DEFAULT_DLY;
+}
+
+uint32_t psx_mc1_get_mc3_read_delay(psx_mc1_t* mc1) {+ return DEFAULT_DLY;
+}
+
+uint32_t psx_mc1_get_ic_read_delay(psx_mc1_t* mc1) {+ return DEFAULT_DLY;
+}
+
uint32_t psx_mc1_get_scratchpad_read_delay(psx_mc1_t* mc1) {USED(mc1);
return 1;
}
-
-uint32_t psx_mc1_get_gpu_read_delay(psx_mc1_t* mc1) {
- return DEFAULT_DLY;
-}
-
-uint32_t psx_mc1_get_spu_read_delay(psx_mc1_t* mc1) {
- return DEFAULT_DLY;
-}
-
-uint32_t psx_mc1_get_timer_read_delay(psx_mc1_t* mc1) {
- return DEFAULT_DLY;
-}
-
-uint32_t psx_mc1_get_cdrom_read_delay(psx_mc1_t* mc1) {
- return DEFAULT_DLY;
-}
-
-uint32_t psx_mc1_get_pad_read_delay(psx_mc1_t* mc1) {
- return DEFAULT_DLY;
-}
-
-uint32_t psx_mc1_get_bios_write_delay(psx_mc1_t* mc1) {
- return DEFAULT_DLY;
-}
-
-uint32_t psx_mc1_get_ram_write_delay(psx_mc1_t* mc1) {
- return DEFAULT_DLY;
-}
-
-uint32_t psx_mc1_get_dma_write_delay(psx_mc1_t* mc1) {
- return DEFAULT_DLY;
-}
-
-uint32_t psx_mc1_get_exp1_write_delay(psx_mc1_t* mc1) {
- return DEFAULT_DLY;
-}
-
-uint32_t psx_mc1_get_mc1_write_delay(psx_mc1_t* mc1) {
- return DEFAULT_DLY;
-}
-
-uint32_t psx_mc1_get_mc2_write_delay(psx_mc1_t* mc1) {
- return DEFAULT_DLY;
-}
-
-uint32_t psx_mc1_get_mc3_write_delay(psx_mc1_t* mc1) {
- return DEFAULT_DLY;
-}
-
-uint32_t psx_mc1_get_ic_write_delay(psx_mc1_t* mc1) {
- return DEFAULT_DLY;
-}
-
+
+uint32_t psx_mc1_get_gpu_read_delay(psx_mc1_t* mc1) {+ return DEFAULT_DLY;
+}
+
+uint32_t psx_mc1_get_spu_read_delay(psx_mc1_t* mc1) {+ return DEFAULT_DLY;
+}
+
+uint32_t psx_mc1_get_timer_read_delay(psx_mc1_t* mc1) {+ return DEFAULT_DLY;
+}
+
+uint32_t psx_mc1_get_cdrom_read_delay(psx_mc1_t* mc1) {+ return DEFAULT_DLY;
+}
+
+uint32_t psx_mc1_get_pad_read_delay(psx_mc1_t* mc1) {+ return DEFAULT_DLY;
+}
+
+uint32_t psx_mc1_get_bios_write_delay(psx_mc1_t* mc1) {+ return DEFAULT_DLY;
+}
+
+uint32_t psx_mc1_get_ram_write_delay(psx_mc1_t* mc1) {+ return DEFAULT_DLY;
+}
+
+uint32_t psx_mc1_get_dma_write_delay(psx_mc1_t* mc1) {+ return DEFAULT_DLY;
+}
+
+uint32_t psx_mc1_get_exp1_write_delay(psx_mc1_t* mc1) {+ return DEFAULT_DLY;
+}
+
+uint32_t psx_mc1_get_mc1_write_delay(psx_mc1_t* mc1) {+ return DEFAULT_DLY;
+}
+
+uint32_t psx_mc1_get_mc2_write_delay(psx_mc1_t* mc1) {+ return DEFAULT_DLY;
+}
+
+uint32_t psx_mc1_get_mc3_write_delay(psx_mc1_t* mc1) {+ return DEFAULT_DLY;
+}
+
+uint32_t psx_mc1_get_ic_write_delay(psx_mc1_t* mc1) {+ return DEFAULT_DLY;
+}
+
uint32_t psx_mc1_get_scratchpad_write_delay(psx_mc1_t* mc1) {USED(mc1);
return 1;
}
-
-uint32_t psx_mc1_get_gpu_write_delay(psx_mc1_t* mc1) {
- return DEFAULT_DLY;
-}
-
-uint32_t psx_mc1_get_spu_write_delay(psx_mc1_t* mc1) {
- return DEFAULT_DLY;
-}
-
-uint32_t psx_mc1_get_timer_write_delay(psx_mc1_t* mc1) {
- return DEFAULT_DLY;
-}
-
-uint32_t psx_mc1_get_cdrom_write_delay(psx_mc1_t* mc1) {
- return DEFAULT_DLY;
-}
-
-uint32_t psx_mc1_get_pad_write_delay(psx_mc1_t* mc1) {
- return DEFAULT_DLY;
-}
-
-void psx_mc1_destroy(psx_mc1_t* mc1) {
- free(mc1);
+
+uint32_t psx_mc1_get_gpu_write_delay(psx_mc1_t* mc1) {+ return DEFAULT_DLY;
+}
+
+uint32_t psx_mc1_get_spu_write_delay(psx_mc1_t* mc1) {+ return DEFAULT_DLY;
+}
+
+uint32_t psx_mc1_get_timer_write_delay(psx_mc1_t* mc1) {+ return DEFAULT_DLY;
+}
+
+uint32_t psx_mc1_get_cdrom_write_delay(psx_mc1_t* mc1) {+ return DEFAULT_DLY;
+}
+
+uint32_t psx_mc1_get_pad_write_delay(psx_mc1_t* mc1) {+ return DEFAULT_DLY;
+}
+
+void psx_mc1_destroy(psx_mc1_t* mc1) {+ free(mc1);
}
--- a/psx/dev/mc1.h
+++ b/psx/dev/mc1.h
@@ -1,21 +1,21 @@
#ifndef PSX_DEV_MC1_H
-#define PSX_DEV_MC1_H
-
-#include "p9.h"
-
-#define PSX_MC1_BEGIN 0x1f801000
-#define PSX_MC1_SIZE 0x24
-#define PSX_MC1_END 0x1f801023
-
+#define PSX_DEV_MC1_H
+
+#include "p9.h"
+
+#define PSX_MC1_BEGIN 0x1f801000
+#define PSX_MC1_SIZE 0x24
+#define PSX_MC1_END 0x1f801023
+
struct psx_mc1_t {uint32_t bus_delay;
uint32_t io_base, io_size;
-
- uint32_t exp1_base;
- uint32_t exp2_base;
- uint32_t exp1_delay;
- uint32_t exp3_delay;
- uint32_t bios_delay;
+
+ uint32_t exp1_base;
+ uint32_t exp2_base;
+ uint32_t exp1_delay;
+ uint32_t exp3_delay;
+ uint32_t bios_delay;
uint32_t spu_delay;
uint32_t cdrom_delay;
uint32_t exp2_delay;
@@ -23,49 +23,49 @@
};
typedef struct psx_mc1_t psx_mc1_t;
-
-typedef struct {
- int fst;
- int seq;
-} psx_access_delay_t;
-
-psx_mc1_t* psx_mc1_create(void);
-void psx_mc1_init(psx_mc1_t*);
-uint32_t psx_mc1_read32(psx_mc1_t*, uint32_t);
-uint16_t psx_mc1_read16(psx_mc1_t*, uint32_t);
-uint8_t psx_mc1_read8(psx_mc1_t*, uint32_t);
-void psx_mc1_write32(psx_mc1_t*, uint32_t, uint32_t);
-void psx_mc1_write16(psx_mc1_t*, uint32_t, uint16_t);
-void psx_mc1_write8(psx_mc1_t*, uint32_t, uint8_t);
-void psx_mc1_destroy(psx_mc1_t*);
-uint32_t psx_mc1_get_bios_read_delay(psx_mc1_t*);
-uint32_t psx_mc1_get_ram_read_delay(psx_mc1_t*);
-uint32_t psx_mc1_get_dma_read_delay(psx_mc1_t*);
-uint32_t psx_mc1_get_exp1_read_delay(psx_mc1_t*);
-uint32_t psx_mc1_get_mc1_read_delay(psx_mc1_t*);
-uint32_t psx_mc1_get_mc2_read_delay(psx_mc1_t*);
-uint32_t psx_mc1_get_mc3_read_delay(psx_mc1_t*);
-uint32_t psx_mc1_get_ic_read_delay(psx_mc1_t*);
-uint32_t psx_mc1_get_scratchpad_read_delay(psx_mc1_t*);
-uint32_t psx_mc1_get_gpu_read_delay(psx_mc1_t*);
-uint32_t psx_mc1_get_spu_read_delay(psx_mc1_t*);
-uint32_t psx_mc1_get_timer_read_delay(psx_mc1_t*);
-uint32_t psx_mc1_get_cdrom_read_delay(psx_mc1_t*);
-uint32_t psx_mc1_get_pad_read_delay(psx_mc1_t*);
-
-uint32_t psx_mc1_get_bios_write_delay(psx_mc1_t*);
-uint32_t psx_mc1_get_ram_write_delay(psx_mc1_t*);
-uint32_t psx_mc1_get_dma_write_delay(psx_mc1_t*);
-uint32_t psx_mc1_get_exp1_write_delay(psx_mc1_t*);
-uint32_t psx_mc1_get_mc1_write_delay(psx_mc1_t*);
-uint32_t psx_mc1_get_mc2_write_delay(psx_mc1_t*);
-uint32_t psx_mc1_get_mc3_write_delay(psx_mc1_t*);
-uint32_t psx_mc1_get_ic_write_delay(psx_mc1_t*);
-uint32_t psx_mc1_get_scratchpad_write_delay(psx_mc1_t*);
-uint32_t psx_mc1_get_gpu_write_delay(psx_mc1_t*);
-uint32_t psx_mc1_get_spu_write_delay(psx_mc1_t*);
-uint32_t psx_mc1_get_timer_write_delay(psx_mc1_t*);
-uint32_t psx_mc1_get_cdrom_write_delay(psx_mc1_t*);
-uint32_t psx_mc1_get_pad_write_delay(psx_mc1_t*);
-
+
+typedef struct {+ int fst;
+ int seq;
+} psx_access_delay_t;
+
+psx_mc1_t* psx_mc1_create(void);
+void psx_mc1_init(psx_mc1_t*);
+uint32_t psx_mc1_read32(psx_mc1_t*, uint32_t);
+uint16_t psx_mc1_read16(psx_mc1_t*, uint32_t);
+uint8_t psx_mc1_read8(psx_mc1_t*, uint32_t);
+void psx_mc1_write32(psx_mc1_t*, uint32_t, uint32_t);
+void psx_mc1_write16(psx_mc1_t*, uint32_t, uint16_t);
+void psx_mc1_write8(psx_mc1_t*, uint32_t, uint8_t);
+void psx_mc1_destroy(psx_mc1_t*);
+uint32_t psx_mc1_get_bios_read_delay(psx_mc1_t*);
+uint32_t psx_mc1_get_ram_read_delay(psx_mc1_t*);
+uint32_t psx_mc1_get_dma_read_delay(psx_mc1_t*);
+uint32_t psx_mc1_get_exp1_read_delay(psx_mc1_t*);
+uint32_t psx_mc1_get_mc1_read_delay(psx_mc1_t*);
+uint32_t psx_mc1_get_mc2_read_delay(psx_mc1_t*);
+uint32_t psx_mc1_get_mc3_read_delay(psx_mc1_t*);
+uint32_t psx_mc1_get_ic_read_delay(psx_mc1_t*);
+uint32_t psx_mc1_get_scratchpad_read_delay(psx_mc1_t*);
+uint32_t psx_mc1_get_gpu_read_delay(psx_mc1_t*);
+uint32_t psx_mc1_get_spu_read_delay(psx_mc1_t*);
+uint32_t psx_mc1_get_timer_read_delay(psx_mc1_t*);
+uint32_t psx_mc1_get_cdrom_read_delay(psx_mc1_t*);
+uint32_t psx_mc1_get_pad_read_delay(psx_mc1_t*);
+
+uint32_t psx_mc1_get_bios_write_delay(psx_mc1_t*);
+uint32_t psx_mc1_get_ram_write_delay(psx_mc1_t*);
+uint32_t psx_mc1_get_dma_write_delay(psx_mc1_t*);
+uint32_t psx_mc1_get_exp1_write_delay(psx_mc1_t*);
+uint32_t psx_mc1_get_mc1_write_delay(psx_mc1_t*);
+uint32_t psx_mc1_get_mc2_write_delay(psx_mc1_t*);
+uint32_t psx_mc1_get_mc3_write_delay(psx_mc1_t*);
+uint32_t psx_mc1_get_ic_write_delay(psx_mc1_t*);
+uint32_t psx_mc1_get_scratchpad_write_delay(psx_mc1_t*);
+uint32_t psx_mc1_get_gpu_write_delay(psx_mc1_t*);
+uint32_t psx_mc1_get_spu_write_delay(psx_mc1_t*);
+uint32_t psx_mc1_get_timer_write_delay(psx_mc1_t*);
+uint32_t psx_mc1_get_cdrom_write_delay(psx_mc1_t*);
+uint32_t psx_mc1_get_pad_write_delay(psx_mc1_t*);
+
#endif
--- a/psx/dev/mc2.c
+++ b/psx/dev/mc2.c
@@ -1,59 +1,59 @@
-#include "p9.h"
-
-#include "dev/mc2.h"
-#include "log.h"
-
-psx_mc2_t* psx_mc2_create(void) {
- return (psx_mc2_t*)malloc(sizeof(psx_mc2_t));
-}
-
-/*
- 1F801060h 4/2 RAM_SIZE (usually 00000B88h; 2MB RAM mirrored in first 8MB)
-*/
-void psx_mc2_init(psx_mc2_t* mc2) {
- memset(mc2, 0, sizeof(psx_mc2_t));
-
- mc2->io_base = PSX_MC2_BEGIN;
- mc2->io_size = PSX_MC2_SIZE;
-
- mc2->ram_size = 0x00000b88;
-}
-
-uint32_t psx_mc2_read32(psx_mc2_t* mc2, uint32_t offset) {
- switch (offset) {
- case 0x00: return mc2->ram_size;
- }
-
- log_warn("Unhandled 32-bit MC2 read at offset %08x", offset);
-
- return 0x0;
-}
-
+#include "p9.h"
+
+#include "dev/mc2.h"
+#include "log.h"
+
+psx_mc2_t* psx_mc2_create(void) {+ return (psx_mc2_t*)malloc(sizeof(psx_mc2_t));
+}
+
+/*
+ 1F801060h 4/2 RAM_SIZE (usually 00000B88h; 2MB RAM mirrored in first 8MB)
+*/
+void psx_mc2_init(psx_mc2_t* mc2) {+ memset(mc2, 0, sizeof(psx_mc2_t));
+
+ mc2->io_base = PSX_MC2_BEGIN;
+ mc2->io_size = PSX_MC2_SIZE;
+
+ mc2->ram_size = 0x00000b88;
+}
+
+uint32_t psx_mc2_read32(psx_mc2_t* mc2, uint32_t offset) {+ switch (offset) {+ case 0x00: return mc2->ram_size;
+ }
+
+ log_warn("Unhandled 32-bit MC2 read at offset %08x", offset);+
+ return 0x0;
+}
+
uint16_t psx_mc2_read16(psx_mc2_t* mc2, uint32_t offset) {USED(mc2);
log_warn("Unhandled 16-bit MC2 read at offset %08x", offset);-
- return 0x0;
-}
-
+
+ return 0x0;
+}
+
uint8_t psx_mc2_read8(psx_mc2_t* mc2, uint32_t offset) {USED(mc2);
log_warn("Unhandled 8-bit MC2 read at offset %08x", offset);-
- return 0x0;
-}
-
-void psx_mc2_write32(psx_mc2_t* mc2, uint32_t offset, uint32_t value) {
- switch (offset) {
- case 0x00: printf("ram_size write %08x\n", value); mc2->ram_size = value; break;
-
- default: {
- log_warn("Unhandled 32-bit MC2 write at offset %08x (%08x)", offset, value);
- } break;
- }
-}
-
-void psx_mc2_write16(psx_mc2_t* mc2, uint32_t offset, uint16_t value) {+
+ return 0x0;
+}
+
+void psx_mc2_write32(psx_mc2_t* mc2, uint32_t offset, uint32_t value) {+ switch (offset) {+ case 0x00: printf("ram_size write %08x\n", value); mc2->ram_size = value; break;+
+ default: {+ log_warn("Unhandled 32-bit MC2 write at offset %08x (%08x)", offset, value);+ } break;
+ }
+}
+
+void psx_mc2_write16(psx_mc2_t* mc2, uint32_t offset, uint16_t value) {USED(mc2);
log_warn("Unhandled 16-bit MC2 write at offset %08x (%04x)", offset, value);}
@@ -62,7 +62,7 @@
USED(mc2);
log_warn("Unhandled 8-bit MC2 write at offset %08x (%02x)", offset, value);}
-
-void psx_mc2_destroy(psx_mc2_t* mc2) {
- free(mc2);
+
+void psx_mc2_destroy(psx_mc2_t* mc2) {+ free(mc2);
}
--- a/psx/dev/mc2.h
+++ b/psx/dev/mc2.h
@@ -1,12 +1,12 @@
#ifndef PSX_DEV_MC2_H
#define PSX_DEV_MC2_H
-
-#include "p9.h"
-
-#define PSX_MC2_BEGIN 0x1f801060
-#define PSX_MC2_SIZE 0x4
-#define PSX_MC2_END 0x1F801063
-
+
+#include "p9.h"
+
+#define PSX_MC2_BEGIN 0x1f801060
+#define PSX_MC2_SIZE 0x4
+#define PSX_MC2_END 0x1F801063
+
struct psx_mc2_t {uint32_t bus_delay;
uint32_t io_base, io_size;
@@ -15,15 +15,15 @@
};
typedef struct psx_mc2_t psx_mc2_t;
-
-psx_mc2_t* psx_mc2_create(void);
-void psx_mc2_init(psx_mc2_t*);
-uint32_t psx_mc2_read32(psx_mc2_t*, uint32_t);
-uint16_t psx_mc2_read16(psx_mc2_t*, uint32_t);
-uint8_t psx_mc2_read8(psx_mc2_t*, uint32_t);
-void psx_mc2_write32(psx_mc2_t*, uint32_t, uint32_t);
-void psx_mc2_write16(psx_mc2_t*, uint32_t, uint16_t);
-void psx_mc2_write8(psx_mc2_t*, uint32_t, uint8_t);
-void psx_mc2_destroy(psx_mc2_t*);
-
+
+psx_mc2_t* psx_mc2_create(void);
+void psx_mc2_init(psx_mc2_t*);
+uint32_t psx_mc2_read32(psx_mc2_t*, uint32_t);
+uint16_t psx_mc2_read16(psx_mc2_t*, uint32_t);
+uint8_t psx_mc2_read8(psx_mc2_t*, uint32_t);
+void psx_mc2_write32(psx_mc2_t*, uint32_t, uint32_t);
+void psx_mc2_write16(psx_mc2_t*, uint32_t, uint16_t);
+void psx_mc2_write8(psx_mc2_t*, uint32_t, uint8_t);
+void psx_mc2_destroy(psx_mc2_t*);
+
#endif
--- a/psx/dev/mc3.c
+++ b/psx/dev/mc3.c
@@ -1,57 +1,57 @@
-#include "p9.h"
-
-#include "dev/mc3.h"
-#include "log.h"
-
-psx_mc3_t* psx_mc3_create(void) {
- return (psx_mc3_t*)malloc(sizeof(psx_mc3_t));
-}
-
-/*
- FFFE0130h 4 Cache Control
-*/
-void psx_mc3_init(psx_mc3_t* mc3) {
- memset(mc3, 0, sizeof(psx_mc3_t));
-
- mc3->io_base = PSX_MC3_BEGIN;
- mc3->io_size = PSX_MC3_SIZE;
-}
-
-uint32_t psx_mc3_read32(psx_mc3_t* mc3, uint32_t offset) {
- switch (offset) {
- case 0x00: return mc3->cache_control;
- }
-
- log_warn("Unhandled 32-bit MC3 read at offset %08x", offset);
-
- return 0x0;
-}
-
+#include "p9.h"
+
+#include "dev/mc3.h"
+#include "log.h"
+
+psx_mc3_t* psx_mc3_create(void) {+ return (psx_mc3_t*)malloc(sizeof(psx_mc3_t));
+}
+
+/*
+ FFFE0130h 4 Cache Control
+*/
+void psx_mc3_init(psx_mc3_t* mc3) {+ memset(mc3, 0, sizeof(psx_mc3_t));
+
+ mc3->io_base = PSX_MC3_BEGIN;
+ mc3->io_size = PSX_MC3_SIZE;
+}
+
+uint32_t psx_mc3_read32(psx_mc3_t* mc3, uint32_t offset) {+ switch (offset) {+ case 0x00: return mc3->cache_control;
+ }
+
+ log_warn("Unhandled 32-bit MC3 read at offset %08x", offset);+
+ return 0x0;
+}
+
uint16_t psx_mc3_read16(psx_mc3_t* mc3, uint32_t offset) {USED(mc3);
log_warn("Unhandled 16-bit MC3 read at offset %08x", offset);-
- return 0x0;
-}
-
+
+ return 0x0;
+}
+
uint8_t psx_mc3_read8(psx_mc3_t* mc3, uint32_t offset) {USED(mc3);
log_warn("Unhandled 8-bit MC3 read at offset %08x", offset);-
- return 0x0;
-}
-
-void psx_mc3_write32(psx_mc3_t* mc3, uint32_t offset, uint32_t value) {
- switch (offset) {
- case 0x00: mc3->cache_control = value; break;
-
- default: {
- log_warn("Unhandled 32-bit MC3 write at offset %08x (%08x)", offset, value);
- } break;
- }
-}
-
-void psx_mc3_write16(psx_mc3_t* mc3, uint32_t offset, uint16_t value) {+
+ return 0x0;
+}
+
+void psx_mc3_write32(psx_mc3_t* mc3, uint32_t offset, uint32_t value) {+ switch (offset) {+ case 0x00: mc3->cache_control = value; break;
+
+ default: {+ log_warn("Unhandled 32-bit MC3 write at offset %08x (%08x)", offset, value);+ } break;
+ }
+}
+
+void psx_mc3_write16(psx_mc3_t* mc3, uint32_t offset, uint16_t value) {USED(mc3);
log_warn("Unhandled 16-bit MC3 write at offset %08x (%04x)", offset, value);}
@@ -60,7 +60,7 @@
USED(mc3);
log_warn("Unhandled 8-bit MC3 write at offset %08x (%02x)", offset, value);}
-
-void psx_mc3_destroy(psx_mc3_t* mc3) {
- free(mc3);
+
+void psx_mc3_destroy(psx_mc3_t* mc3) {+ free(mc3);
}
--- a/psx/dev/mc3.h
+++ b/psx/dev/mc3.h
@@ -1,12 +1,12 @@
#ifndef PSX_DEV_MC3_H
-#define PSX_DEV_MC3_H
-
-#include "p9.h"
-
-#define PSX_MC3_BEGIN 0xfffe0130
-#define PSX_MC3_SIZE 0x4
-#define PSX_MC3_END 0xfffe0133
-
+#define PSX_DEV_MC3_H
+
+#include "p9.h"
+
+#define PSX_MC3_BEGIN 0xfffe0130
+#define PSX_MC3_SIZE 0x4
+#define PSX_MC3_END 0xfffe0133
+
struct psx_mc3_t {uint32_t bus_delay;
uint32_t io_base, io_size;
@@ -15,15 +15,15 @@
};
typedef struct psx_mc3_t psx_mc3_t;
-
-psx_mc3_t* psx_mc3_create(void);
-void psx_mc3_init(psx_mc3_t*);
-uint32_t psx_mc3_read32(psx_mc3_t*, uint32_t);
-uint16_t psx_mc3_read16(psx_mc3_t*, uint32_t);
-uint8_t psx_mc3_read8(psx_mc3_t*, uint32_t);
-void psx_mc3_write32(psx_mc3_t*, uint32_t, uint32_t);
-void psx_mc3_write16(psx_mc3_t*, uint32_t, uint16_t);
-void psx_mc3_write8(psx_mc3_t*, uint32_t, uint8_t);
-void psx_mc3_destroy(psx_mc3_t*);
-
+
+psx_mc3_t* psx_mc3_create(void);
+void psx_mc3_init(psx_mc3_t*);
+uint32_t psx_mc3_read32(psx_mc3_t*, uint32_t);
+uint16_t psx_mc3_read16(psx_mc3_t*, uint32_t);
+uint8_t psx_mc3_read8(psx_mc3_t*, uint32_t);
+void psx_mc3_write32(psx_mc3_t*, uint32_t, uint32_t);
+void psx_mc3_write16(psx_mc3_t*, uint32_t, uint16_t);
+void psx_mc3_write8(psx_mc3_t*, uint32_t, uint8_t);
+void psx_mc3_destroy(psx_mc3_t*);
+
#endif
--- a/psx/dev/mcd.c
+++ b/psx/dev/mcd.c
@@ -1,41 +1,41 @@
-#include "dev/mcd.h"
-#include "log.h"
-
-#define PATCH1 1 // 1=Fix memory card access.
-
-
-psx_mcd_t* psx_mcd_create(void) {
- return (psx_mcd_t*)malloc(sizeof(psx_mcd_t));
-}
-
-int psx_mcd_init(psx_mcd_t* mcd, const char* path) {
- memset(mcd, 0, sizeof(psx_mcd_t));
-
- mcd->state = MCD_STATE_TX_HIZ;
- mcd->flag = 0x08;
- mcd->path = path;
- mcd->buf = malloc(MCD_MEMORY_SIZE);
- mcd->tx_data_ready = 0;
-
- memset(mcd->buf, 0, MCD_MEMORY_SIZE);
-
- if (!path)
- return 0;
-
- FILE* file = fopen(path, "rb");
-
- if (!file)
- return 1;
-
- if (!fread(mcd->buf, 1, MCD_MEMORY_SIZE, file))
- return 2;
-
- fclose(file);
-
- return 0;
-}
-
-uint8_t psx_mcd_read(psx_mcd_t* mcd) {
+#include "dev/mcd.h"
+#include "log.h"
+
+#define PATCH1 1 // 1=Fix memory card access.
+
+
+psx_mcd_t* psx_mcd_create(void) {+ return (psx_mcd_t*)malloc(sizeof(psx_mcd_t));
+}
+
+int psx_mcd_init(psx_mcd_t* mcd, const char* path) {+ memset(mcd, 0, sizeof(psx_mcd_t));
+
+ mcd->state = MCD_STATE_TX_HIZ;
+ mcd->flag = 0x08;
+ mcd->path = path;
+ mcd->buf = malloc(MCD_MEMORY_SIZE);
+ mcd->tx_data_ready = 0;
+
+ memset(mcd->buf, 0, MCD_MEMORY_SIZE);
+
+ if (!path)
+ return 0;
+
+ FILE* file = fopen(path, "rb");
+
+ if (!file)
+ return 1;
+
+ if (!fread(mcd->buf, 1, MCD_MEMORY_SIZE, file))
+ return 2;
+
+ fclose(file);
+
+ return 0;
+}
+
+uint8_t psx_mcd_read(psx_mcd_t* mcd) { switch (mcd->state) {case MCD_STATE_TX_HIZ: mcd->tx_data = 0xff; break;
case MCD_STATE_TX_FLG:
@@ -48,9 +48,9 @@
mcd->tx_data = mcd->flag; mcd->flag = 0x00; break;
case MCD_STATE_TX_ID1: mcd->tx_data = 0x5a; break;
case MCD_STATE_TX_ID2: {- mcd->tx_data_ready = 1;
- mcd->tx_data = 0x5d;
-
+ mcd->tx_data_ready = 1;
+ mcd->tx_data = 0x5d;
+
switch (mcd->mode) {case 'R': mcd->state = MCD_R_STATE_RX_MSB; break;
case 'W': mcd->state = MCD_W_STATE_RX_MSB; break;
@@ -61,59 +61,59 @@
mcd->state = MCD_STATE_TX_HIZ;
return mcd->tx_data;
}
-
- // printf("mcd read %02x\n", mcd->tx_data);
-
- // log_set_quiet(0);
- // log_fatal("mcd read %02x", mcd->tx_data);
- // log_set_quiet(1);
-
- return mcd->tx_data;
- } break;
-
- // Read states
- case MCD_R_STATE_RX_MSB: mcd->tx_data = 0x00; break;
- case MCD_R_STATE_RX_LSB: mcd->tx_data = mcd->msb; break;
- case MCD_R_STATE_TX_ACK1: mcd->tx_data = 0x5c; break;
- case MCD_R_STATE_TX_ACK2: mcd->tx_data = 0x5d; break;
- case MCD_R_STATE_TX_MSB: mcd->tx_data = mcd->msb; mcd->checksum = mcd->msb; break;
- case MCD_R_STATE_TX_LSB: mcd->tx_data = mcd->lsb; mcd->checksum ^= mcd->lsb;
- mcd->pending_bytes = 128; break;
- case MCD_R_STATE_TX_DATA: {
- --mcd->pending_bytes;
-
- uint8_t data = mcd->buf[mcd->addr++];
-
- mcd->checksum ^= data;
-
- if (!mcd->pending_bytes) {
- mcd->tx_data = data;
-
- break;
- }
-
- // printf("mcd read %02x\n", data);
-
- // log_set_quiet(0);
- // log_fatal("mcd read %02x", data);
- // log_set_quiet(1);
-
- return data;
- } break;
- case MCD_R_STATE_TX_CHK: mcd->tx_data = mcd->checksum; break;
- case MCD_R_STATE_TX_MEB: {
- mcd->tx_data_ready = 0;
- mcd->state = MCD_STATE_TX_HIZ;
-
- // log_set_quiet(0);
- // log_fatal("mcd read %02x", 'G');
- // log_set_quiet(1);
-
- // printf("mcd read %02x\n", 'G');
-
- return 'G';
- } break;
-
+
+ // printf("mcd read %02x\n", mcd->tx_data);+
+ // log_set_quiet(0);
+ // log_fatal("mcd read %02x", mcd->tx_data);+ // log_set_quiet(1);
+
+ return mcd->tx_data;
+ } break;
+
+ // Read states
+ case MCD_R_STATE_RX_MSB: mcd->tx_data = 0x00; break;
+ case MCD_R_STATE_RX_LSB: mcd->tx_data = mcd->msb; break;
+ case MCD_R_STATE_TX_ACK1: mcd->tx_data = 0x5c; break;
+ case MCD_R_STATE_TX_ACK2: mcd->tx_data = 0x5d; break;
+ case MCD_R_STATE_TX_MSB: mcd->tx_data = mcd->msb; mcd->checksum = mcd->msb; break;
+ case MCD_R_STATE_TX_LSB: mcd->tx_data = mcd->lsb; mcd->checksum ^= mcd->lsb;
+ mcd->pending_bytes = 128; break;
+ case MCD_R_STATE_TX_DATA: {+ --mcd->pending_bytes;
+
+ uint8_t data = mcd->buf[mcd->addr++];
+
+ mcd->checksum ^= data;
+
+ if (!mcd->pending_bytes) {+ mcd->tx_data = data;
+
+ break;
+ }
+
+ // printf("mcd read %02x\n", data);+
+ // log_set_quiet(0);
+ // log_fatal("mcd read %02x", data);+ // log_set_quiet(1);
+
+ return data;
+ } break;
+ case MCD_R_STATE_TX_CHK: mcd->tx_data = mcd->checksum; break;
+ case MCD_R_STATE_TX_MEB: {+ mcd->tx_data_ready = 0;
+ mcd->state = MCD_STATE_TX_HIZ;
+
+ // log_set_quiet(0);
+ // log_fatal("mcd read %02x", 'G');+ // log_set_quiet(1);
+
+ // printf("mcd read %02x\n", 'G');+
+ return 'G';
+ } break;
+
/* Write states */
case MCD_W_STATE_RX_MSB: mcd->tx_data = 0x00; break;
case MCD_W_STATE_RX_LSB: mcd->tx_data = mcd->msb;
@@ -120,21 +120,21 @@
mcd->pending_bytes = 128; break;
case MCD_W_STATE_RX_DATA: {--mcd->pending_bytes;
-
- mcd->buf[mcd->addr++] = mcd->rx_data;
-
- if (!mcd->pending_bytes) {
- mcd->tx_data = mcd->rx_data;
-
- break;
- }
-
- // printf("mcd read %02x\n", mcd->rx_data);
-
- // log_set_quiet(0);
- // log_fatal("mcd read %02x", mcd->rx_data);
- // log_set_quiet(1);
-
+
+ mcd->buf[mcd->addr++] = mcd->rx_data;
+
+ if (!mcd->pending_bytes) {+ mcd->tx_data = mcd->rx_data;
+
+ break;
+ }
+
+ // printf("mcd read %02x\n", mcd->rx_data);+
+ // log_set_quiet(0);
+ // log_fatal("mcd read %02x", mcd->rx_data);+ // log_set_quiet(1);
+
return mcd->rx_data;
} break;
case MCD_W_STATE_RX_CHK: mcd->tx_data = mcd->rx_data; break;
@@ -141,71 +141,71 @@
case MCD_W_STATE_RX_CHK2: mcd->tx_data = mcd->rx_data; break;
case MCD_W_STATE_TX_ACK1: mcd->tx_data = 0x5c; break;
case MCD_W_STATE_TX_ACK2: mcd->tx_data = 0x5d; break;
- case MCD_W_STATE_TX_MEB: {
- mcd->tx_data_ready = 0;
- mcd->state = MCD_STATE_TX_HIZ;
-
- // log_set_quiet(0);
- // log_fatal("mcd read %02x", 'G');
- // log_set_quiet(1);
-
- // printf("mcd read %02x\n", 'G');
-
- return 'G';
- } break;
- }
-
- mcd->tx_data_ready = 1;
- mcd->state++;
-
- // log_set_quiet(0);
- // log_fatal("mcd read %02x", mcd->tx_data);
- // log_set_quiet(1);
-
- // printf("mcd read %02x\n", mcd->tx_data);
-
- return mcd->tx_data;
-}
-
+ case MCD_W_STATE_TX_MEB: {+ mcd->tx_data_ready = 0;
+ mcd->state = MCD_STATE_TX_HIZ;
+
+ // log_set_quiet(0);
+ // log_fatal("mcd read %02x", 'G');+ // log_set_quiet(1);
+
+ // printf("mcd read %02x\n", 'G');+
+ return 'G';
+ } break;
+ }
+
+ mcd->tx_data_ready = 1;
+ mcd->state++;
+
+ // log_set_quiet(0);
+ // log_fatal("mcd read %02x", mcd->tx_data);+ // log_set_quiet(1);
+
+ // printf("mcd read %02x\n", mcd->tx_data);+
+ return mcd->tx_data;
+}
+
void psx_mcd_write(psx_mcd_t* mcd, uint8_t data) {- // log_set_quiet(0);
- // log_fatal("mcd write %02x", data);
- // log_set_quiet(1);
-
+ // log_set_quiet(0);
+ // log_fatal("mcd write %02x", data);+ // log_set_quiet(1);
+
mcd->rx_data = data;
-// printf("mcd write %02x\n", data);
-
- switch (mcd->state) {
- case MCD_STATE_TX_FLG: mcd->mode = data; break;
- case MCD_R_STATE_RX_MSB: mcd->msb = data; break;
- case MCD_R_STATE_RX_LSB: {
- mcd->lsb = data;
- mcd->addr = ((mcd->msb << 8) | mcd->lsb) << 7;
- } break;
- case MCD_W_STATE_RX_MSB: mcd->msb = data; break;
- case MCD_W_STATE_RX_LSB: {
- mcd->lsb = data;
- mcd->addr = ((mcd->msb << 8) | mcd->lsb) << 7;
- } break;
- case MCD_W_STATE_RX_DATA: mcd->rx_data = data; break;
- case MCD_W_STATE_RX_CHK: /* Don't care */ break;
- }
-}
-
-int psx_mcd_query(psx_mcd_t* mcd) {
- return mcd->tx_data_ready;
-}
-
-void psx_mcd_reset(psx_mcd_t* mcd) {
- mcd->state = MCD_STATE_TX_HIZ;
-}
-
-void psx_mcd_destroy(psx_mcd_t* mcd) {
- FILE* file = fopen(mcd->path, "wb");
-
- fwrite(mcd->buf, 1, MCD_MEMORY_SIZE, file);
- fclose(file);
-
- free(mcd->buf);
- free(mcd);
-}
+// printf("mcd write %02x\n", data);+
+ switch (mcd->state) {+ case MCD_STATE_TX_FLG: mcd->mode = data; break;
+ case MCD_R_STATE_RX_MSB: mcd->msb = data; break;
+ case MCD_R_STATE_RX_LSB: {+ mcd->lsb = data;
+ mcd->addr = ((mcd->msb << 8) | mcd->lsb) << 7;
+ } break;
+ case MCD_W_STATE_RX_MSB: mcd->msb = data; break;
+ case MCD_W_STATE_RX_LSB: {+ mcd->lsb = data;
+ mcd->addr = ((mcd->msb << 8) | mcd->lsb) << 7;
+ } break;
+ case MCD_W_STATE_RX_DATA: mcd->rx_data = data; break;
+ case MCD_W_STATE_RX_CHK: /* Don't care */ break;
+ }
+}
+
+int psx_mcd_query(psx_mcd_t* mcd) {+ return mcd->tx_data_ready;
+}
+
+void psx_mcd_reset(psx_mcd_t* mcd) {+ mcd->state = MCD_STATE_TX_HIZ;
+}
+
+void psx_mcd_destroy(psx_mcd_t* mcd) {+ FILE* file = fopen(mcd->path, "wb");
+
+ fwrite(mcd->buf, 1, MCD_MEMORY_SIZE, file);
+ fclose(file);
+
+ free(mcd->buf);
+ free(mcd);
+}
--- a/psx/dev/mcd.h
+++ b/psx/dev/mcd.h
@@ -1,24 +1,24 @@
#ifndef PSX_DEV_MCD_H
-#define PSX_DEV_MCD_H
-
-#include "p9.h"
-
-#define MCD_MEMORY_SIZE 0x20000 // 128 KB
-
-enum {
- MCD_STATE_TX_HIZ = 0,
- MCD_STATE_TX_FLG,
- MCD_STATE_TX_ID1,
- MCD_STATE_TX_ID2,
- MCD_R_STATE_RX_MSB,
- MCD_R_STATE_RX_LSB,
- MCD_R_STATE_TX_ACK1,
- MCD_R_STATE_TX_ACK2,
- MCD_R_STATE_TX_MSB,
- MCD_R_STATE_TX_LSB,
- MCD_R_STATE_TX_DATA,
- MCD_R_STATE_TX_CHK,
- MCD_R_STATE_TX_MEB,
+#define PSX_DEV_MCD_H
+
+#include "p9.h"
+
+#define MCD_MEMORY_SIZE 0x20000 // 128 KB
+
+enum {+ MCD_STATE_TX_HIZ = 0,
+ MCD_STATE_TX_FLG,
+ MCD_STATE_TX_ID1,
+ MCD_STATE_TX_ID2,
+ MCD_R_STATE_RX_MSB,
+ MCD_R_STATE_RX_LSB,
+ MCD_R_STATE_TX_ACK1,
+ MCD_R_STATE_TX_ACK2,
+ MCD_R_STATE_TX_MSB,
+ MCD_R_STATE_TX_LSB,
+ MCD_R_STATE_TX_DATA,
+ MCD_R_STATE_TX_CHK,
+ MCD_R_STATE_TX_MEB,
MCD_W_STATE_RX_MSB,
MCD_W_STATE_RX_LSB,
MCD_W_STATE_RX_DATA,
@@ -25,26 +25,26 @@
MCD_W_STATE_RX_CHK,
MCD_W_STATE_RX_CHK2,
MCD_W_STATE_TX_ACK1,
- MCD_W_STATE_TX_ACK2,
- MCD_W_STATE_TX_MEB,
- MCD_S_STATE_TX_ACK1,
- MCD_S_STATE_TX_ACK2,
- MCD_S_STATE_TX_DAT0,
- MCD_S_STATE_TX_DAT1,
- MCD_S_STATE_TX_DAT2,
- MCD_S_STATE_TX_DAT3
-};
-
+ MCD_W_STATE_TX_ACK2,
+ MCD_W_STATE_TX_MEB,
+ MCD_S_STATE_TX_ACK1,
+ MCD_S_STATE_TX_ACK2,
+ MCD_S_STATE_TX_DAT0,
+ MCD_S_STATE_TX_DAT1,
+ MCD_S_STATE_TX_DAT2,
+ MCD_S_STATE_TX_DAT3
+};
+
struct psx_mcd_t {const char* path;
uint8_t* buf;
uint8_t flag;
- uint16_t msb;
- uint16_t lsb;
- uint16_t addr;
- uint8_t rx_data;
- int pending_bytes;
- char mode;
+ uint16_t msb;
+ uint16_t lsb;
+ uint16_t addr;
+ uint8_t rx_data;
+ int pending_bytes;
+ char mode;
int state;
uint8_t tx_data;
int tx_data_ready;
@@ -52,13 +52,13 @@
};
typedef struct psx_mcd_t psx_mcd_t;
-
-psx_mcd_t* psx_mcd_create(void);
-int psx_mcd_init(psx_mcd_t*, const char*);
-uint8_t psx_mcd_read(psx_mcd_t*);
-void psx_mcd_write(psx_mcd_t*, uint8_t);
-int psx_mcd_query(psx_mcd_t*);
-void psx_mcd_reset(psx_mcd_t*);
-void psx_mcd_destroy(psx_mcd_t*);
-
+
+psx_mcd_t* psx_mcd_create(void);
+int psx_mcd_init(psx_mcd_t*, const char*);
+uint8_t psx_mcd_read(psx_mcd_t*);
+void psx_mcd_write(psx_mcd_t*, uint8_t);
+int psx_mcd_query(psx_mcd_t*);
+void psx_mcd_reset(psx_mcd_t*);
+void psx_mcd_destroy(psx_mcd_t*);
+
#endif
--- a/psx/dev/mdec.c
+++ b/psx/dev/mdec.c
@@ -1,338 +1,338 @@
-#include "dev/mdec.h"
-#include "log.h"
-
-#include "p9.h"
-
-int zigzag[] = {
- 0 , 1 , 5 , 6 , 14, 15, 27, 28,
- 2 , 4 , 7 , 13, 16, 26, 29, 42,
- 3 , 8 , 12, 17, 25, 30, 41, 43,
- 9 , 11, 18, 24, 31, 40, 44, 53,
- 10, 19, 23, 32, 39, 45, 52, 54,
- 20, 22, 33, 38, 46, 51, 55, 60,
- 21, 34, 37, 47, 50, 56, 59, 61,
- 35, 36, 48, 49, 57, 58, 62, 63
-};
-
-int zagzig[] = {
- 0, 1, 8, 16, 9, 2, 3, 10,
- 17, 24, 32, 25, 18, 11, 4, 5,
- 12, 19, 26, 33, 40, 48, 41, 34,
- 27, 20, 13, 6, 7, 14, 21, 28,
- 35, 42, 49, 56, 57, 50, 43, 36,
- 29, 22, 15, 23, 30, 37, 44, 51,
- 58, 59, 52, 45, 38, 31, 39, 46,
- 53, 60, 61, 54, 47, 55, 62, 63
-};
-
-float scalezag[] = {
- 0.125000, 0.173380, 0.173380, 0.163320, 0.240485, 0.163320, 0.146984, 0.226532,
- 0.226532, 0.146984, 0.125000, 0.203873, 0.213388, 0.203873, 0.125000, 0.098212,
- 0.173380, 0.192044, 0.192044, 0.173380, 0.098212, 0.067650, 0.136224, 0.163320,
- 0.172835, 0.163320, 0.136224, 0.067650, 0.034487, 0.093833, 0.128320, 0.146984,
- 0.146984, 0.128320, 0.093833, 0.034487, 0.047835, 0.088388, 0.115485, 0.125000,
- 0.115485, 0.088388, 0.047835, 0.045060, 0.079547, 0.098212, 0.098212, 0.079547,
- 0.045060, 0.040553, 0.067650, 0.077165, 0.067650, 0.040553, 0.034487, 0.053152,
- 0.053152, 0.034487, 0.027097, 0.036612, 0.027097, 0.018664, 0.018664, 0.009515
-};
-
-#define EXTS10(v) (((int16_t)((v) << 6)) >> 6)
-#define CLAMP(v, l, h) ((v <= l) ? l : ((v >= h) ? h : v))
-#define MAX(a, b) (a > b ? a : b)
-
-void real_idct(int16_t* blk, int16_t* scale) {
- int16_t buf[64];
-
- int16_t* src = blk;
- int16_t* dst = buf;
-
- for (int pass = 0; pass < 2; pass++) {
- for (int x = 0; x < 8; x++) {
- for (int y = 0; y < 8; y++) {
- int sum = 0;
-
- for (int z = 0; z < 8; z++)
- sum += (int32_t)src[y+z*8] * ((int32_t)scale[x+z*8] / 8);
-
- dst[x+y*8] = (sum + 0xfff) / 0x2000;
- }
- }
-
- int16_t* temp = src;
-
- src = dst;
- dst = temp;
- }
-}
-
-#define IDCT_FUNC(blk, scale) real_idct(blk, scale)
-
-uint16_t* rl_decode_block(int16_t* blk, uint16_t* src, uint8_t* quant, int16_t* scale) {
- int k = 0;
-
- for (int i = 0; i < 64; i++)
- blk[i] = 0;
-
- uint16_t n = *src;
-
- ++src;
-
- while (n == 0xfe00) {
- n = *src;
-
- ++src;
- }
-
- int q_scale = (n >> 10) & 0x3f;
-
- int16_t val = EXTS10(n & 0x3ff) * quant[k];
-
- while (k < 64) {
- if (!q_scale)
- val = EXTS10(n & 0x3ff) * 2;
-
- val = CLAMP(val, -0x400, 0x3ff);
- // val *= scalezag[k]; // For fast IDCT
-
- if (q_scale > 0)
- blk[zagzig[k]] = val;
-
- if (!q_scale)
- blk[k] = val;
-
- n = *src;
-
- if (k == 63)
- break;
-
- ++src;
-
- k += ((n >> 10) & 0x3f) + 1;
-
- val = (EXTS10(n & 0x3ff) * quant[k] * q_scale + 4) / 8;
- }
-
- IDCT_FUNC(blk, scale);
-
- return src;
-}
-
-// for y=0 to 7
-// for x=0 to 7
-// R=[Crblk+((x+xx)/2)+((y+yy)/2)*8], B=[Cbblk+((x+xx)/2)+((y+yy)/2)*8]
-// G=(-0.3437*B)+(-0.7143*R), R=(1.402*R), B=(1.772*B)
-// Y=[Yblk+(x)+(y)*8]
-// R=MinMax(-128,127,(Y+R))
-// G=MinMax(-128,127,(Y+G))
-// B=MinMax(-128,127,(Y+B))
-// if unsigned then BGR=BGR xor 808080h ;aka add 128 to the R,G,B values
-// dst[(x+xx)+(y+yy)*16]=BGR
-// next x
-// next y
-
-void yuv_to_rgb(psx_mdec_t* mdec, uint8_t* buf, int xx, int yy) {
- for (int y = 0; y < 8; y++) {
- for (int x = 0; x < 8; x++) {
- int16_t r = mdec->crblk[((x + xx) >> 1) + ((y + yy) >> 1) * 8];
- int16_t b = mdec->cbblk[((x + xx) >> 1) + ((y + yy) >> 1) * 8];
- int16_t g = (-0.3437 * (float)b) + (-0.7143 * (float)r);
-
- r = (1.402 * (float)r);
- b = (1.772 * (float)b);
-
- int16_t l = mdec->yblk[x + y * 8];
-
- r = CLAMP(l + r, -128, 127);
- g = CLAMP(l + g, -128, 127);
- b = CLAMP(l + b, -128, 127);
-
- if (!mdec->output_signed) {
- r ^= 0x80;
- g ^= 0x80;
- b ^= 0x80;
- }
-
- if (mdec->output_depth == 3) {
- uint16_t r5 = ((uint8_t)r) >> 3;
- uint16_t g5 = ((uint8_t)g) >> 3;
- uint16_t b5 = ((uint8_t)b) >> 3;
-
- uint16_t rgb = (b5 << 10) | (g5 << 5) | r5;
-
- if (mdec->output_bit15)
- rgb |= 0x8000;
-
- buf[0 + ((x + xx) + (y + yy) * 16) * 2] = rgb & 0xff;
- buf[1 + ((x + xx) + (y + yy) * 16) * 2] = rgb >> 8;
- } else {
- buf[0 + ((x + xx) + (y + yy) * 16) * 3] = r & 0xff;
- buf[1 + ((x + xx) + (y + yy) * 16) * 3] = g & 0xff;
- buf[2 + ((x + xx) + (y + yy) * 16) * 3] = b & 0xff;
- }
- }
- }
-}
-
+#include "dev/mdec.h"
+#include "log.h"
+
+#include "p9.h"
+
+int zigzag[] = {+ 0 , 1 , 5 , 6 , 14, 15, 27, 28,
+ 2 , 4 , 7 , 13, 16, 26, 29, 42,
+ 3 , 8 , 12, 17, 25, 30, 41, 43,
+ 9 , 11, 18, 24, 31, 40, 44, 53,
+ 10, 19, 23, 32, 39, 45, 52, 54,
+ 20, 22, 33, 38, 46, 51, 55, 60,
+ 21, 34, 37, 47, 50, 56, 59, 61,
+ 35, 36, 48, 49, 57, 58, 62, 63
+};
+
+int zagzig[] = {+ 0, 1, 8, 16, 9, 2, 3, 10,
+ 17, 24, 32, 25, 18, 11, 4, 5,
+ 12, 19, 26, 33, 40, 48, 41, 34,
+ 27, 20, 13, 6, 7, 14, 21, 28,
+ 35, 42, 49, 56, 57, 50, 43, 36,
+ 29, 22, 15, 23, 30, 37, 44, 51,
+ 58, 59, 52, 45, 38, 31, 39, 46,
+ 53, 60, 61, 54, 47, 55, 62, 63
+};
+
+float scalezag[] = {+ 0.125000, 0.173380, 0.173380, 0.163320, 0.240485, 0.163320, 0.146984, 0.226532,
+ 0.226532, 0.146984, 0.125000, 0.203873, 0.213388, 0.203873, 0.125000, 0.098212,
+ 0.173380, 0.192044, 0.192044, 0.173380, 0.098212, 0.067650, 0.136224, 0.163320,
+ 0.172835, 0.163320, 0.136224, 0.067650, 0.034487, 0.093833, 0.128320, 0.146984,
+ 0.146984, 0.128320, 0.093833, 0.034487, 0.047835, 0.088388, 0.115485, 0.125000,
+ 0.115485, 0.088388, 0.047835, 0.045060, 0.079547, 0.098212, 0.098212, 0.079547,
+ 0.045060, 0.040553, 0.067650, 0.077165, 0.067650, 0.040553, 0.034487, 0.053152,
+ 0.053152, 0.034487, 0.027097, 0.036612, 0.027097, 0.018664, 0.018664, 0.009515
+};
+
+#define EXTS10(v) (((int16_t)((v) << 6)) >> 6)
+#define CLAMP(v, l, h) ((v <= l) ? l : ((v >= h) ? h : v))
+#define MAX(a, b) (a > b ? a : b)
+
+void real_idct(int16_t* blk, int16_t* scale) {+ int16_t buf[64];
+
+ int16_t* src = blk;
+ int16_t* dst = buf;
+
+ for (int pass = 0; pass < 2; pass++) {+ for (int x = 0; x < 8; x++) {+ for (int y = 0; y < 8; y++) {+ int sum = 0;
+
+ for (int z = 0; z < 8; z++)
+ sum += (int32_t)src[y+z*8] * ((int32_t)scale[x+z*8] / 8);
+
+ dst[x+y*8] = (sum + 0xfff) / 0x2000;
+ }
+ }
+
+ int16_t* temp = src;
+
+ src = dst;
+ dst = temp;
+ }
+}
+
+#define IDCT_FUNC(blk, scale) real_idct(blk, scale)
+
+uint16_t* rl_decode_block(int16_t* blk, uint16_t* src, uint8_t* quant, int16_t* scale) {+ int k = 0;
+
+ for (int i = 0; i < 64; i++)
+ blk[i] = 0;
+
+ uint16_t n = *src;
+
+ ++src;
+
+ while (n == 0xfe00) {+ n = *src;
+
+ ++src;
+ }
+
+ int q_scale = (n >> 10) & 0x3f;
+
+ int16_t val = EXTS10(n & 0x3ff) * quant[k];
+
+ while (k < 64) {+ if (!q_scale)
+ val = EXTS10(n & 0x3ff) * 2;
+
+ val = CLAMP(val, -0x400, 0x3ff);
+ // val *= scalezag[k]; // For fast IDCT
+
+ if (q_scale > 0)
+ blk[zagzig[k]] = val;
+
+ if (!q_scale)
+ blk[k] = val;
+
+ n = *src;
+
+ if (k == 63)
+ break;
+
+ ++src;
+
+ k += ((n >> 10) & 0x3f) + 1;
+
+ val = (EXTS10(n & 0x3ff) * quant[k] * q_scale + 4) / 8;
+ }
+
+ IDCT_FUNC(blk, scale);
+
+ return src;
+}
+
+// for y=0 to 7
+// for x=0 to 7
+// R=[Crblk+((x+xx)/2)+((y+yy)/2)*8], B=[Cbblk+((x+xx)/2)+((y+yy)/2)*8]
+// G=(-0.3437*B)+(-0.7143*R), R=(1.402*R), B=(1.772*B)
+// Y=[Yblk+(x)+(y)*8]
+// R=MinMax(-128,127,(Y+R))
+// G=MinMax(-128,127,(Y+G))
+// B=MinMax(-128,127,(Y+B))
+// if unsigned then BGR=BGR xor 808080h ;aka add 128 to the R,G,B values
+// dst[(x+xx)+(y+yy)*16]=BGR
+// next x
+// next y
+
+void yuv_to_rgb(psx_mdec_t* mdec, uint8_t* buf, int xx, int yy) {+ for (int y = 0; y < 8; y++) {+ for (int x = 0; x < 8; x++) {+ int16_t r = mdec->crblk[((x + xx) >> 1) + ((y + yy) >> 1) * 8];
+ int16_t b = mdec->cbblk[((x + xx) >> 1) + ((y + yy) >> 1) * 8];
+ int16_t g = (-0.3437 * (float)b) + (-0.7143 * (float)r);
+
+ r = (1.402 * (float)r);
+ b = (1.772 * (float)b);
+
+ int16_t l = mdec->yblk[x + y * 8];
+
+ r = CLAMP(l + r, -128, 127);
+ g = CLAMP(l + g, -128, 127);
+ b = CLAMP(l + b, -128, 127);
+
+ if (!mdec->output_signed) {+ r ^= 0x80;
+ g ^= 0x80;
+ b ^= 0x80;
+ }
+
+ if (mdec->output_depth == 3) {+ uint16_t r5 = ((uint8_t)r) >> 3;
+ uint16_t g5 = ((uint8_t)g) >> 3;
+ uint16_t b5 = ((uint8_t)b) >> 3;
+
+ uint16_t rgb = (b5 << 10) | (g5 << 5) | r5;
+
+ if (mdec->output_bit15)
+ rgb |= 0x8000;
+
+ buf[0 + ((x + xx) + (y + yy) * 16) * 2] = rgb & 0xff;
+ buf[1 + ((x + xx) + (y + yy) * 16) * 2] = rgb >> 8;
+ } else {+ buf[0 + ((x + xx) + (y + yy) * 16) * 3] = r & 0xff;
+ buf[1 + ((x + xx) + (y + yy) * 16) * 3] = g & 0xff;
+ buf[2 + ((x + xx) + (y + yy) * 16) * 3] = b & 0xff;
+ }
+ }
+ }
+}
+
void mdec_nop(psx_mdec_t* mdec) {USED(mdec);
}
-
-void mdec_decode_macroblock(psx_mdec_t* mdec) {
- if (mdec->output_depth < 2) {
- size_t block_size = (mdec->output_depth == 3) ? 512 : 768;
- size_t size = block_size;
-
- mdec->output = malloc(size);
-
- rl_decode_block(mdec->yblk, (uint16_t*)mdec->input, mdec->y_quant_table, mdec->scale_table);
-
- for (int i = 0; i < 64; i++) {
- int16_t y = mdec->yblk[i] & 0xff;
-
- if (mdec->output_depth == 1) {
- mdec->output[i] = y;
- } else {
- // To-do
- mdec->output[i] = 0;
- }
- }
-
- mdec->output_words_remaining = ((mdec->output_depth == 1) ? 64 : 32) >> 2;
- mdec->output_empty = 0;
- mdec->output_index = 0;
- } else {
- uint16_t* in = (uint16_t*)mdec->input;
-
- size_t block_size = (mdec->output_depth == 3) ? 512 : 768;
- size_t size = block_size;
-
- unsigned long bytes_processed = 0;
-
- int block_count = 1;
-
- while (bytes_processed < mdec->input_size) {
- if (!mdec->output) {
- mdec->output = malloc(block_count * size);
- } else {
- mdec->output = realloc(mdec->output, block_count * size);
- }
-
- in = rl_decode_block(mdec->crblk, in, mdec->uv_quant_table, mdec->scale_table);
- in = rl_decode_block(mdec->cbblk, in, mdec->uv_quant_table, mdec->scale_table);
- in = rl_decode_block(mdec->yblk, in, mdec->y_quant_table, mdec->scale_table);
- yuv_to_rgb(mdec, &mdec->output[(block_count * size) - block_size], 0, 0);
- in = rl_decode_block(mdec->yblk, in, mdec->y_quant_table, mdec->scale_table);
- yuv_to_rgb(mdec, &mdec->output[(block_count * size) - block_size], 8, 0);
- in = rl_decode_block(mdec->yblk, in, mdec->y_quant_table, mdec->scale_table);
- yuv_to_rgb(mdec, &mdec->output[(block_count * size) - block_size], 0, 8);
- in = rl_decode_block(mdec->yblk, in, mdec->y_quant_table, mdec->scale_table);
- yuv_to_rgb(mdec, &mdec->output[(block_count * size) - block_size], 8, 8);
-
- bytes_processed = (uintptr_t)in - (uintptr_t)mdec->input;
-
- ++block_count;
- }
-
- mdec->output_words_remaining = ((block_count - 1) * block_size) >> 2;
- mdec->output_empty = 0;
- mdec->output_index = 0;
-
- // printf("output words remaining: %d (%x) count=%d block_size=%lld size=%lld\n", mdec->output_words_remaining, mdec->output_words_remaining, block_count, block_size, size);
-
- // log_set_quiet(0);
- // log_fatal("Finished decoding %u-bit MDEC data input=(%04x -> %08x)",
- // (mdec->output_depth == 3) ? 15 : 24,
- // mdec->input_size,
- // mdec->output_words_remaining
- // );
- // log_set_quiet(1);
- }
-}
-
-void mdec_set_iqtab(psx_mdec_t* mdec) {
- memcpy(mdec->y_quant_table, mdec->input, 64);
-
- if (mdec->recv_color)
- memcpy(mdec->uv_quant_table, &mdec->input[16], 64);
-}
-
-void mdec_set_scale(psx_mdec_t* mdec) {
- memcpy(mdec->scale_table, mdec->input, 128);
-}
-
-mdec_fn_t g_mdec_cmd_table[] = {
- mdec_nop,
- mdec_decode_macroblock,
- mdec_set_iqtab,
- mdec_set_scale,
- mdec_nop,
- mdec_nop,
- mdec_nop,
- mdec_nop
-};
-
-psx_mdec_t* psx_mdec_create(void) {
- return (psx_mdec_t*)malloc(sizeof(psx_mdec_t));
-}
-
-void psx_mdec_init(psx_mdec_t* mdec) {
- memset(mdec, 0, sizeof(psx_mdec_t));
-
- mdec->io_base = PSX_MDEC_BEGIN;
- mdec->io_size = PSX_MDEC_SIZE;
-
- mdec->state = MDEC_RECV_CMD;
-}
-
-uint32_t psx_mdec_read32(psx_mdec_t* mdec, uint32_t offset) {
- switch (offset) {
- case 0: {
- // printf("mdec data read\n");
- // mdec->output_empty = 1;
- // mdec->output_index = 0;
- // mdec->output_request = 0;
-
- // return 0xaaaaaaaa;
-
- if (mdec->output_words_remaining) {
- --mdec->output_words_remaining;
-
- // log_set_quiet(0);
- // log_fatal("output read %08x", 0);
- // log_set_quiet(1);
-
- return ((uint32_t*)mdec->output)[mdec->output_index++];
- } else {
- // printf("no read words remaining\n");
- mdec->output_empty = 0;
- mdec->output_index = 0;
- mdec->output_request = 0;
-
- return 0xaaaaaaaa;
- }
- } break;
- case 4: {
- //printf("mdec status read\n");
- uint32_t status = 0;
-
- status |= mdec->words_remaining;
- status |= mdec->current_block << 16;
- status |= mdec->output_bit15 << 23;
- status |= mdec->output_signed << 24;
- status |= mdec->output_depth << 25;
- status |= mdec->output_request << 27;
- status |= mdec->input_request << 28;
- status |= mdec->busy << 29;
- status |= mdec->input_full << 30;
- status |= mdec->output_empty << 31;
-
- return status;
- } break;
- }
-
- return 0x0;
-}
-
+
+void mdec_decode_macroblock(psx_mdec_t* mdec) {+ if (mdec->output_depth < 2) {+ size_t block_size = (mdec->output_depth == 3) ? 512 : 768;
+ size_t size = block_size;
+
+ mdec->output = malloc(size);
+
+ rl_decode_block(mdec->yblk, (uint16_t*)mdec->input, mdec->y_quant_table, mdec->scale_table);
+
+ for (int i = 0; i < 64; i++) {+ int16_t y = mdec->yblk[i] & 0xff;
+
+ if (mdec->output_depth == 1) {+ mdec->output[i] = y;
+ } else {+ // To-do
+ mdec->output[i] = 0;
+ }
+ }
+
+ mdec->output_words_remaining = ((mdec->output_depth == 1) ? 64 : 32) >> 2;
+ mdec->output_empty = 0;
+ mdec->output_index = 0;
+ } else {+ uint16_t* in = (uint16_t*)mdec->input;
+
+ size_t block_size = (mdec->output_depth == 3) ? 512 : 768;
+ size_t size = block_size;
+
+ unsigned long bytes_processed = 0;
+
+ int block_count = 1;
+
+ while (bytes_processed < mdec->input_size) {+ if (!mdec->output) {+ mdec->output = malloc(block_count * size);
+ } else {+ mdec->output = realloc(mdec->output, block_count * size);
+ }
+
+ in = rl_decode_block(mdec->crblk, in, mdec->uv_quant_table, mdec->scale_table);
+ in = rl_decode_block(mdec->cbblk, in, mdec->uv_quant_table, mdec->scale_table);
+ in = rl_decode_block(mdec->yblk, in, mdec->y_quant_table, mdec->scale_table);
+ yuv_to_rgb(mdec, &mdec->output[(block_count * size) - block_size], 0, 0);
+ in = rl_decode_block(mdec->yblk, in, mdec->y_quant_table, mdec->scale_table);
+ yuv_to_rgb(mdec, &mdec->output[(block_count * size) - block_size], 8, 0);
+ in = rl_decode_block(mdec->yblk, in, mdec->y_quant_table, mdec->scale_table);
+ yuv_to_rgb(mdec, &mdec->output[(block_count * size) - block_size], 0, 8);
+ in = rl_decode_block(mdec->yblk, in, mdec->y_quant_table, mdec->scale_table);
+ yuv_to_rgb(mdec, &mdec->output[(block_count * size) - block_size], 8, 8);
+
+ bytes_processed = (uintptr_t)in - (uintptr_t)mdec->input;
+
+ ++block_count;
+ }
+
+ mdec->output_words_remaining = ((block_count - 1) * block_size) >> 2;
+ mdec->output_empty = 0;
+ mdec->output_index = 0;
+
+ // printf("output words remaining: %d (%x) count=%d block_size=%lld size=%lld\n", mdec->output_words_remaining, mdec->output_words_remaining, block_count, block_size, size);+
+ // log_set_quiet(0);
+ // log_fatal("Finished decoding %u-bit MDEC data input=(%04x -> %08x)",+ // (mdec->output_depth == 3) ? 15 : 24,
+ // mdec->input_size,
+ // mdec->output_words_remaining
+ // );
+ // log_set_quiet(1);
+ }
+}
+
+void mdec_set_iqtab(psx_mdec_t* mdec) {+ memcpy(mdec->y_quant_table, mdec->input, 64);
+
+ if (mdec->recv_color)
+ memcpy(mdec->uv_quant_table, &mdec->input[16], 64);
+}
+
+void mdec_set_scale(psx_mdec_t* mdec) {+ memcpy(mdec->scale_table, mdec->input, 128);
+}
+
+mdec_fn_t g_mdec_cmd_table[] = {+ mdec_nop,
+ mdec_decode_macroblock,
+ mdec_set_iqtab,
+ mdec_set_scale,
+ mdec_nop,
+ mdec_nop,
+ mdec_nop,
+ mdec_nop
+};
+
+psx_mdec_t* psx_mdec_create(void) {+ return (psx_mdec_t*)malloc(sizeof(psx_mdec_t));
+}
+
+void psx_mdec_init(psx_mdec_t* mdec) {+ memset(mdec, 0, sizeof(psx_mdec_t));
+
+ mdec->io_base = PSX_MDEC_BEGIN;
+ mdec->io_size = PSX_MDEC_SIZE;
+
+ mdec->state = MDEC_RECV_CMD;
+}
+
+uint32_t psx_mdec_read32(psx_mdec_t* mdec, uint32_t offset) {+ switch (offset) {+ case 0: {+ // printf("mdec data read\n");+ // mdec->output_empty = 1;
+ // mdec->output_index = 0;
+ // mdec->output_request = 0;
+
+ // return 0xaaaaaaaa;
+
+ if (mdec->output_words_remaining) {+ --mdec->output_words_remaining;
+
+ // log_set_quiet(0);
+ // log_fatal("output read %08x", 0);+ // log_set_quiet(1);
+
+ return ((uint32_t*)mdec->output)[mdec->output_index++];
+ } else {+ // printf("no read words remaining\n");+ mdec->output_empty = 0;
+ mdec->output_index = 0;
+ mdec->output_request = 0;
+
+ return 0xaaaaaaaa;
+ }
+ } break;
+ case 4: {+ //printf("mdec status read\n");+ uint32_t status = 0;
+
+ status |= mdec->words_remaining;
+ status |= mdec->current_block << 16;
+ status |= mdec->output_bit15 << 23;
+ status |= mdec->output_signed << 24;
+ status |= mdec->output_depth << 25;
+ status |= mdec->output_request << 27;
+ status |= mdec->input_request << 28;
+ status |= mdec->busy << 29;
+ status |= mdec->input_full << 30;
+ status |= mdec->output_empty << 31;
+
+ return status;
+ } break;
+ }
+
+ return 0x0;
+}
+
uint16_t psx_mdec_read16(psx_mdec_t* mdec, uint32_t offset) {USED(mdec);
printf("Unhandled 16-bit MDEC read offset=%08x\n", offset);@@ -348,119 +348,119 @@
exit(1);
return 0;
}
-
-void psx_mdec_write32(psx_mdec_t* mdec, uint32_t offset, uint32_t value) {
- switch (offset) {
- case 0: {
- //printf("mdec data write\n");
- if (mdec->words_remaining) {
- mdec->input[mdec->input_index++] = value;
-
- --mdec->words_remaining;
-
- if (!mdec->words_remaining) {
- //printf("no words remaining\n");
- mdec->output_empty = 0;
- mdec->input_full = 1;
- mdec->input_request = 0;
- mdec->busy = 0;
- mdec->output_request = mdec->enable_dma1;
-
- g_mdec_cmd_table[mdec->cmd >> 29](mdec);
-
- free(mdec->input);
- }
-
- break;
- }
-
- mdec->cmd = value;
- mdec->output_request = 0;
- mdec->output_empty = 1;
- mdec->output_bit15 = (value >> 25) & 1;
- mdec->output_signed = (value >> 26) & 1;
- mdec->output_depth = (value >> 27) & 3;
- mdec->input_index = 0;
- mdec->input_full = 0;
- mdec->busy = 1;
-
- //log_set_quiet(0);
- switch (mdec->cmd >> 29) {
- case MDEC_CMD_NOP: {
- //printf("mdec nop\n");
- mdec->busy = 0;
- mdec->words_remaining = 0;
-
- log_fatal("MDEC %08x: NOP", mdec->cmd);
- } break;
-
- case MDEC_CMD_DECODE: {
- //printf("mdec decode\n");
- mdec->words_remaining = mdec->cmd & 0xffff;
-
- // printf("MDEC %08x: decode macroblock %04x\n",
- // mdec->cmd,
- // mdec->words_remaining
- // );
- } break;
-
- case MDEC_CMD_SET_QT: {
- //printf("mdec setqt\n");
- mdec->recv_color = mdec->cmd & 1;
- mdec->words_remaining = mdec->recv_color ? 32 : 16;
-
- log_fatal("MDEC %08x: set quant tables %04x",
- mdec->cmd,
- mdec->words_remaining
- );
- } break;
-
- case MDEC_CMD_SET_ST: {
- //printf("mdec setst\n");
- mdec->words_remaining = 32;
-
- log_fatal("MDEC %08x: set scale table %04x",
- mdec->cmd,
- mdec->words_remaining
- );
- } break;
- }
- // log_set_quiet(1);
-
- if (mdec->words_remaining) {
- mdec->input_request = 1;
- mdec->input_size = mdec->words_remaining * sizeof(uint32_t);
- mdec->input_full = 0;
- mdec->input_index = 0;
- mdec->input = malloc(mdec->input_size);
- }
- } break;
-
- case 4: {
- //printf("mdec status write\n");
- mdec->enable_dma0 = (value & 0x40000000) != 0;
- mdec->enable_dma1 = (value & 0x20000000) != 0;
-
- // Reset
- if (value & 0x80000000) {
- // status = 80040000h
- mdec->busy = 0;
- mdec->words_remaining = 0;
- mdec->output_bit15 = 0;
- mdec->output_signed = 0;
- mdec->output_depth = 0;
- mdec->input_request = 0;
- mdec->output_request = 0;
- mdec->input_full = 0;
- mdec->output_empty = 1;
- mdec->current_block = 4;
- }
- } break;
- }
-
- // log_fatal("32-bit MDEC write offset=%u, value=%08x", offset, value);
-}
-
+
+void psx_mdec_write32(psx_mdec_t* mdec, uint32_t offset, uint32_t value) {+ switch (offset) {+ case 0: {+ //printf("mdec data write\n");+ if (mdec->words_remaining) {+ mdec->input[mdec->input_index++] = value;
+
+ --mdec->words_remaining;
+
+ if (!mdec->words_remaining) {+ //printf("no words remaining\n");+ mdec->output_empty = 0;
+ mdec->input_full = 1;
+ mdec->input_request = 0;
+ mdec->busy = 0;
+ mdec->output_request = mdec->enable_dma1;
+
+ g_mdec_cmd_table[mdec->cmd >> 29](mdec);
+
+ free(mdec->input);
+ }
+
+ break;
+ }
+
+ mdec->cmd = value;
+ mdec->output_request = 0;
+ mdec->output_empty = 1;
+ mdec->output_bit15 = (value >> 25) & 1;
+ mdec->output_signed = (value >> 26) & 1;
+ mdec->output_depth = (value >> 27) & 3;
+ mdec->input_index = 0;
+ mdec->input_full = 0;
+ mdec->busy = 1;
+
+ //log_set_quiet(0);
+ switch (mdec->cmd >> 29) {+ case MDEC_CMD_NOP: {+ //printf("mdec nop\n");+ mdec->busy = 0;
+ mdec->words_remaining = 0;
+
+ log_fatal("MDEC %08x: NOP", mdec->cmd);+ } break;
+
+ case MDEC_CMD_DECODE: {+ //printf("mdec decode\n");+ mdec->words_remaining = mdec->cmd & 0xffff;
+
+ // printf("MDEC %08x: decode macroblock %04x\n",+ // mdec->cmd,
+ // mdec->words_remaining
+ // );
+ } break;
+
+ case MDEC_CMD_SET_QT: {+ //printf("mdec setqt\n");+ mdec->recv_color = mdec->cmd & 1;
+ mdec->words_remaining = mdec->recv_color ? 32 : 16;
+
+ log_fatal("MDEC %08x: set quant tables %04x",+ mdec->cmd,
+ mdec->words_remaining
+ );
+ } break;
+
+ case MDEC_CMD_SET_ST: {+ //printf("mdec setst\n");+ mdec->words_remaining = 32;
+
+ log_fatal("MDEC %08x: set scale table %04x",+ mdec->cmd,
+ mdec->words_remaining
+ );
+ } break;
+ }
+ // log_set_quiet(1);
+
+ if (mdec->words_remaining) {+ mdec->input_request = 1;
+ mdec->input_size = mdec->words_remaining * sizeof(uint32_t);
+ mdec->input_full = 0;
+ mdec->input_index = 0;
+ mdec->input = malloc(mdec->input_size);
+ }
+ } break;
+
+ case 4: {+ //printf("mdec status write\n");+ mdec->enable_dma0 = (value & 0x40000000) != 0;
+ mdec->enable_dma1 = (value & 0x20000000) != 0;
+
+ // Reset
+ if (value & 0x80000000) {+ // status = 80040000h
+ mdec->busy = 0;
+ mdec->words_remaining = 0;
+ mdec->output_bit15 = 0;
+ mdec->output_signed = 0;
+ mdec->output_depth = 0;
+ mdec->input_request = 0;
+ mdec->output_request = 0;
+ mdec->input_full = 0;
+ mdec->output_empty = 1;
+ mdec->current_block = 4;
+ }
+ } break;
+ }
+
+ // log_fatal("32-bit MDEC write offset=%u, value=%08x", offset, value);+}
+
void psx_mdec_write16(psx_mdec_t* mdec, uint32_t offset, uint16_t value) {USED(mdec);
printf("Unhandled 16-bit MDEC write offset=%08x, value=%04x\n", offset, value);@@ -470,10 +470,10 @@
USED(mdec);
printf("Unhandled 8-bit MDEC write offset=%08x, value=%02x\n", offset, value);}
-
-void psx_mdec_destroy(psx_mdec_t* mdec) {
- free(mdec);
-}
-
-#undef CLAMP
+
+void psx_mdec_destroy(psx_mdec_t* mdec) {+ free(mdec);
+}
+
+#undef CLAMP
#undef MAX
--- a/psx/dev/mdec.h
+++ b/psx/dev/mdec.h
@@ -1,85 +1,85 @@
#ifndef PSX_DEV_MDEC_H
-#define PSX_DEV_MDEC_H
-
-#include "p9.h"
-
-#include "log.h"
-
-#define PSX_MDEC_SIZE 0x8
-#define PSX_MDEC_BEGIN 0x1f801820
-#define PSX_MDEC_END 0x1f801827
-
-#define MDEC_SCALE_TABLE_SIZE 64
-#define MDEC_QUANT_TABLE_SIZE 64
-
-enum {
- MDEC_RECV_CMD,
- MDEC_RECV_BLOCK,
- MDEC_RECV_QUANT,
- MDEC_RECV_QUANT_COLOR,
- MDEC_RECV_SCALE
-};
-
-/*
- 31 Data-Out Fifo Empty (0=No, 1=Empty)
- 30 Data-In Fifo Full (0=No, 1=Full, or Last word received)
- 29 Command Busy (0=Ready, 1=Busy receiving or processing parameters)
- 28 Data-In Request (set when DMA0 enabled and ready to receive data)
- 27 Data-Out Request (set when DMA1 enabled and ready to send data)
- 26-25 Data Output Depth (0=4bit, 1=8bit, 2=24bit, 3=15bit) ;CMD.28-27
- 24 Data Output Signed (0=Unsigned, 1=Signed) ;CMD.26
- 23 Data Output Bit15 (0=Clear, 1=Set) (for 15bit depth only) ;CMD.25
- 22-19 Not used (seems to be always zero)
- 18-16 Current Block (0..3=Y1..Y4, 4=Cr, 5=Cb) (or for mono: always 4=Y)
- 15-0 Number of Parameter Words remaining minus 1 (FFFFh=None) ;CMD.Bit0-15
-*/
-
-enum {
- MDEC_CMD_NOP,
- MDEC_CMD_DECODE,
- MDEC_CMD_SET_QT,
- MDEC_CMD_SET_ST
-};
-
+#define PSX_DEV_MDEC_H
+
+#include "p9.h"
+
+#include "log.h"
+
+#define PSX_MDEC_SIZE 0x8
+#define PSX_MDEC_BEGIN 0x1f801820
+#define PSX_MDEC_END 0x1f801827
+
+#define MDEC_SCALE_TABLE_SIZE 64
+#define MDEC_QUANT_TABLE_SIZE 64
+
+enum {+ MDEC_RECV_CMD,
+ MDEC_RECV_BLOCK,
+ MDEC_RECV_QUANT,
+ MDEC_RECV_QUANT_COLOR,
+ MDEC_RECV_SCALE
+};
+
+/*
+ 31 Data-Out Fifo Empty (0=No, 1=Empty)
+ 30 Data-In Fifo Full (0=No, 1=Full, or Last word received)
+ 29 Command Busy (0=Ready, 1=Busy receiving or processing parameters)
+ 28 Data-In Request (set when DMA0 enabled and ready to receive data)
+ 27 Data-Out Request (set when DMA1 enabled and ready to send data)
+ 26-25 Data Output Depth (0=4bit, 1=8bit, 2=24bit, 3=15bit) ;CMD.28-27
+ 24 Data Output Signed (0=Unsigned, 1=Signed) ;CMD.26
+ 23 Data Output Bit15 (0=Clear, 1=Set) (for 15bit depth only) ;CMD.25
+ 22-19 Not used (seems to be always zero)
+ 18-16 Current Block (0..3=Y1..Y4, 4=Cr, 5=Cb) (or for mono: always 4=Y)
+ 15-0 Number of Parameter Words remaining minus 1 (FFFFh=None) ;CMD.Bit0-15
+*/
+
+enum {+ MDEC_CMD_NOP,
+ MDEC_CMD_DECODE,
+ MDEC_CMD_SET_QT,
+ MDEC_CMD_SET_ST
+};
+
struct psx_mdec_t {uint32_t bus_delay;
uint32_t io_base, io_size;
-
- uint32_t cmd;
-
- int state;
- int data_remaining;
- int index;
-
- uint32_t* input;
- int input_index;
- size_t input_size;
-
- uint8_t* output;
- int output_index;
- uint32_t output_words_remaining;
-
- uint32_t words_remaining;
- int current_block;
- int output_bit15;
- int output_signed;
- int output_depth;
- int input_request;
- int output_request;
- int busy;
- int input_full;
- int output_empty;
-
- int enable_dma0;
- int enable_dma1;
-
- int recv_color;
- uint8_t uv_quant_table[MDEC_QUANT_TABLE_SIZE];
- uint8_t y_quant_table[MDEC_QUANT_TABLE_SIZE];
- int16_t scale_table[MDEC_SCALE_TABLE_SIZE];
-
- int16_t yblk[64];
- int16_t crblk[64];
+
+ uint32_t cmd;
+
+ int state;
+ int data_remaining;
+ int index;
+
+ uint32_t* input;
+ int input_index;
+ size_t input_size;
+
+ uint8_t* output;
+ int output_index;
+ uint32_t output_words_remaining;
+
+ uint32_t words_remaining;
+ int current_block;
+ int output_bit15;
+ int output_signed;
+ int output_depth;
+ int input_request;
+ int output_request;
+ int busy;
+ int input_full;
+ int output_empty;
+
+ int enable_dma0;
+ int enable_dma1;
+
+ int recv_color;
+ uint8_t uv_quant_table[MDEC_QUANT_TABLE_SIZE];
+ uint8_t y_quant_table[MDEC_QUANT_TABLE_SIZE];
+ int16_t scale_table[MDEC_SCALE_TABLE_SIZE];
+
+ int16_t yblk[64];
+ int16_t crblk[64];
int16_t cbblk[64];
uint32_t status;
@@ -86,17 +86,17 @@
};
typedef struct psx_mdec_t psx_mdec_t;
-
-psx_mdec_t* psx_mdec_create(void);
-void psx_mdec_init(psx_mdec_t*);
-uint32_t psx_mdec_read32(psx_mdec_t*, uint32_t);
-uint16_t psx_mdec_read16(psx_mdec_t*, uint32_t);
-uint8_t psx_mdec_read8(psx_mdec_t*, uint32_t);
-void psx_mdec_write32(psx_mdec_t*, uint32_t, uint32_t);
-void psx_mdec_write16(psx_mdec_t*, uint32_t, uint16_t);
-void psx_mdec_write8(psx_mdec_t*, uint32_t, uint8_t);
-void psx_mdec_destroy(psx_mdec_t*);
-
-typedef void (*mdec_fn_t)(psx_mdec_t*);
-
+
+psx_mdec_t* psx_mdec_create(void);
+void psx_mdec_init(psx_mdec_t*);
+uint32_t psx_mdec_read32(psx_mdec_t*, uint32_t);
+uint16_t psx_mdec_read16(psx_mdec_t*, uint32_t);
+uint8_t psx_mdec_read8(psx_mdec_t*, uint32_t);
+void psx_mdec_write32(psx_mdec_t*, uint32_t, uint32_t);
+void psx_mdec_write16(psx_mdec_t*, uint32_t, uint16_t);
+void psx_mdec_write8(psx_mdec_t*, uint32_t, uint8_t);
+void psx_mdec_destroy(psx_mdec_t*);
+
+typedef void (*mdec_fn_t)(psx_mdec_t*);
+
#endif
--- a/psx/dev/pad.c
+++ b/psx/dev/pad.c
@@ -3,340 +3,340 @@
#include "dev/pad.h"
#include "dev/mcd.h"
#include "log.h"
-
-#define JOY_IRQ_DELAY 512
-
-uint32_t pad_read_rx(psx_pad_t* pad) {
- int slot = (pad->ctrl >> 13) & 1;
-
- psx_input_t* joy = pad->joy_slot[slot];
- psx_mcd_t* mcd = pad->mcd_slot[slot];
-
- if (!pad->dest[slot])
- return 0xffffffff;
-
- if (!(pad->ctrl & CTRL_JOUT) && !(pad->ctrl & CTRL_RXEN))
- return 0xffffffff;
-
- switch (pad->dest[slot]) {
- case DEST_JOY: {
- if (!joy) {
- pad->dest[slot] = 0;
-
- return 0xffffffff;
- }
-
- uint8_t data = joy->read_func(joy->udata);
-
- if (!joy->query_fifo_func(joy->udata))
- pad->dest[slot] = 0;
-
- return data;
- } break;
-
- case DEST_MCD: {
- if (!mcd) {
- pad->dest[slot] = 0;
-
- return 0xffffffff;
- }
-
- uint8_t data = psx_mcd_read(mcd);
-
- if (!psx_mcd_query(mcd))
- pad->dest[slot] = 0;
-
- return data;
- } break;
- }
-
- return 0xffffffff;
-}
-
-void pad_write_tx(psx_pad_t* pad, uint16_t data) {
- int slot = (pad->ctrl >> 13) & 1;
-
- psx_input_t* joy = pad->joy_slot[slot];
- psx_mcd_t* mcd = pad->mcd_slot[slot];
-
- if (!(pad->ctrl & CTRL_TXEN))
- return;
-
- if (!pad->dest[slot]) {
- if ((data == DEST_JOY) || (data == DEST_MCD)) {
- pad->dest[slot] = data;
-
- if ((data == DEST_JOY) && !joy)
- return;
-
- if ((data == DEST_MCD) && !mcd)
- return;
-
- if (pad->ctrl & CTRL_ACIE)
- pad->cycles_until_irq = JOY_IRQ_DELAY;
- }
- } else {
- switch (pad->dest[slot]) {
- case DEST_JOY: {
- if (!joy) {
- pad->dest[slot] = 0;
-
- return;
- }
-
- joy->write_func(joy->udata, data);
-
- if (!joy->query_fifo_func(joy->udata))
- pad->dest[slot] = 0;
- } break;
-
- case DEST_MCD: {
- if (!mcd) {
- pad->dest[slot] = 0;
-
- return;
- }
-
- psx_mcd_write(mcd, data);
-
- if (pad->ctrl & CTRL_ACIE) {
- pad->irq_bit = 1;
- pad->cycles_until_irq = 1024;
-
- return;
- }
-
- if (!psx_mcd_query(mcd))
- pad->dest[slot] = 0;
- } break;
- }
-
- if (pad->ctrl & CTRL_ACIE) {
- pad->irq_bit = 1;
- pad->cycles_until_irq = (pad->dest[slot] == DEST_MCD) ? 2048 : JOY_IRQ_DELAY;
- }
- }
-}
-
-uint32_t pad_handle_stat_read(psx_pad_t* pad) {
- return pad->stat | 7;
-}
-
-void pad_handle_ctrl_write(psx_pad_t* pad, uint32_t value) {
- int slot = pad->ctrl & CTRL_SLOT;
-
- pad->ctrl = value;
-
- if (!(pad->ctrl & CTRL_JOUT)) {
- pad->ctrl &= ~CTRL_SLOT;
-
- if (pad->mcd_slot[slot >> 13])
- psx_mcd_reset(pad->mcd_slot[slot >> 13]);
- }
-
- // Reset STAT bits 3, 4, 5, 9
- if (pad->ctrl & CTRL_ACKN) {
- pad->stat &= 0xfdc7;
- pad->ctrl &= ~CTRL_ACKN;
- }
-}
-
-psx_pad_t* psx_pad_create(void) {
- return (psx_pad_t*)malloc(sizeof(psx_pad_t));
-}
-
-void psx_pad_init(psx_pad_t* pad, psx_ic_t* ic) {
- memset(pad, 0, sizeof(psx_pad_t));
-
- pad->ic = ic;
-
- pad->io_base = PSX_PAD_BEGIN;
- pad->io_size = PSX_PAD_SIZE;
-
- pad->joy_slot[0] = NULL;
- pad->joy_slot[1] = NULL;
- pad->mcd_slot[0] = NULL;
- pad->mcd_slot[1] = NULL;
-}
-
-uint32_t psx_pad_read32(psx_pad_t* pad, uint32_t offset) {
- uint32_t v = 0;
-
- switch (offset) {
- case 0: v = pad_read_rx(pad); break;
- case 4: v = pad_handle_stat_read(pad); break;
- case 8: v = pad->mode; break;
- case 10: v = pad->ctrl; break;
- case 14: v = pad->baud; break;
- }
-
- return v;
-}
-
+
+#define JOY_IRQ_DELAY 512
+
+uint32_t pad_read_rx(psx_pad_t* pad) {+ int slot = (pad->ctrl >> 13) & 1;
+
+ psx_input_t* joy = pad->joy_slot[slot];
+ psx_mcd_t* mcd = pad->mcd_slot[slot];
+
+ if (!pad->dest[slot])
+ return 0xffffffff;
+
+ if (!(pad->ctrl & CTRL_JOUT) && !(pad->ctrl & CTRL_RXEN))
+ return 0xffffffff;
+
+ switch (pad->dest[slot]) {+ case DEST_JOY: {+ if (!joy) {+ pad->dest[slot] = 0;
+
+ return 0xffffffff;
+ }
+
+ uint8_t data = joy->read_func(joy->udata);
+
+ if (!joy->query_fifo_func(joy->udata))
+ pad->dest[slot] = 0;
+
+ return data;
+ } break;
+
+ case DEST_MCD: {+ if (!mcd) {+ pad->dest[slot] = 0;
+
+ return 0xffffffff;
+ }
+
+ uint8_t data = psx_mcd_read(mcd);
+
+ if (!psx_mcd_query(mcd))
+ pad->dest[slot] = 0;
+
+ return data;
+ } break;
+ }
+
+ return 0xffffffff;
+}
+
+void pad_write_tx(psx_pad_t* pad, uint16_t data) {+ int slot = (pad->ctrl >> 13) & 1;
+
+ psx_input_t* joy = pad->joy_slot[slot];
+ psx_mcd_t* mcd = pad->mcd_slot[slot];
+
+ if (!(pad->ctrl & CTRL_TXEN))
+ return;
+
+ if (!pad->dest[slot]) {+ if ((data == DEST_JOY) || (data == DEST_MCD)) {+ pad->dest[slot] = data;
+
+ if ((data == DEST_JOY) && !joy)
+ return;
+
+ if ((data == DEST_MCD) && !mcd)
+ return;
+
+ if (pad->ctrl & CTRL_ACIE)
+ pad->cycles_until_irq = JOY_IRQ_DELAY;
+ }
+ } else {+ switch (pad->dest[slot]) {+ case DEST_JOY: {+ if (!joy) {+ pad->dest[slot] = 0;
+
+ return;
+ }
+
+ joy->write_func(joy->udata, data);
+
+ if (!joy->query_fifo_func(joy->udata))
+ pad->dest[slot] = 0;
+ } break;
+
+ case DEST_MCD: {+ if (!mcd) {+ pad->dest[slot] = 0;
+
+ return;
+ }
+
+ psx_mcd_write(mcd, data);
+
+ if (pad->ctrl & CTRL_ACIE) {+ pad->irq_bit = 1;
+ pad->cycles_until_irq = 1024;
+
+ return;
+ }
+
+ if (!psx_mcd_query(mcd))
+ pad->dest[slot] = 0;
+ } break;
+ }
+
+ if (pad->ctrl & CTRL_ACIE) {+ pad->irq_bit = 1;
+ pad->cycles_until_irq = (pad->dest[slot] == DEST_MCD) ? 2048 : JOY_IRQ_DELAY;
+ }
+ }
+}
+
+uint32_t pad_handle_stat_read(psx_pad_t* pad) {+ return pad->stat | 7;
+}
+
+void pad_handle_ctrl_write(psx_pad_t* pad, uint32_t value) {+ int slot = pad->ctrl & CTRL_SLOT;
+
+ pad->ctrl = value;
+
+ if (!(pad->ctrl & CTRL_JOUT)) {+ pad->ctrl &= ~CTRL_SLOT;
+
+ if (pad->mcd_slot[slot >> 13])
+ psx_mcd_reset(pad->mcd_slot[slot >> 13]);
+ }
+
+ // Reset STAT bits 3, 4, 5, 9
+ if (pad->ctrl & CTRL_ACKN) {+ pad->stat &= 0xfdc7;
+ pad->ctrl &= ~CTRL_ACKN;
+ }
+}
+
+psx_pad_t* psx_pad_create(void) {+ return (psx_pad_t*)malloc(sizeof(psx_pad_t));
+}
+
+void psx_pad_init(psx_pad_t* pad, psx_ic_t* ic) {+ memset(pad, 0, sizeof(psx_pad_t));
+
+ pad->ic = ic;
+
+ pad->io_base = PSX_PAD_BEGIN;
+ pad->io_size = PSX_PAD_SIZE;
+
+ pad->joy_slot[0] = NULL;
+ pad->joy_slot[1] = NULL;
+ pad->mcd_slot[0] = NULL;
+ pad->mcd_slot[1] = NULL;
+}
+
+uint32_t psx_pad_read32(psx_pad_t* pad, uint32_t offset) {+ uint32_t v = 0;
+
+ switch (offset) {+ case 0: v = pad_read_rx(pad); break;
+ case 4: v = pad_handle_stat_read(pad); break;
+ case 8: v = pad->mode; break;
+ case 10: v = pad->ctrl; break;
+ case 14: v = pad->baud; break;
+ }
+
+ return v;
+}
+
uint16_t psx_pad_read16(psx_pad_t* pad, uint32_t offset) {- uint32_t v = 0;
-
- switch (offset) {
- case 0: v = pad_read_rx(pad) & 0xffff; break;
- case 4: v = pad_handle_stat_read(pad) & 0xffff; break;
- case 8: v = pad->mode; break;
- case 10: v = pad->ctrl & 0xffff; break;
- case 14: v = pad->baud; break;
+ uint32_t v = 0;
+
+ switch (offset) {+ case 0: v = pad_read_rx(pad) & 0xffff; break;
+ case 4: v = pad_handle_stat_read(pad) & 0xffff; break;
+ case 8: v = pad->mode; break;
+ case 10: v = pad->ctrl & 0xffff; break;
+ case 14: v = pad->baud; break;
}
return v;
}
-
-uint8_t psx_pad_read8(psx_pad_t* pad, uint32_t offset) {
- uint32_t v = 0;
-
- switch (offset) {
- case 0: v = pad_read_rx(pad) & 0xff; break;
- case 4: v = pad_handle_stat_read(pad) & 0xff; break;
- case 8: v = pad->mode; break;
- case 10: v = pad->ctrl & 0xff; break;
- case 14: v = pad->baud; break;
- }
-
- // if (offset <= 0xa)
- // printf("slot=%d dest=%02x pad_read8(%02x) -> %02x\n",
- // (pad->ctrl & CTRL_SLOT) >> 13,
- // pad->dest[(pad->ctrl & CTRL_SLOT) >> 13],
- // offset,
- // v
- // );
-
- return v;
-}
-
-void psx_pad_write32(psx_pad_t* pad, uint32_t offset, uint32_t value) {
- switch (offset) {
- case 0: pad_write_tx(pad, value); return;
- case 8: pad->mode = value & 0xffff; return;
- case 10: pad_handle_ctrl_write(pad, value); return;
- case 14: pad->baud = value & 0xffff; return;
- }
-
- printf("Unhandled 32-bit PAD write at offset %08x (%08x)", offset, value);
-}
-
-void psx_pad_write16(psx_pad_t* pad, uint32_t offset, uint16_t value) {
- switch (offset) {
- case 0: pad_write_tx(pad, value); return;
- case 8: pad->mode = value; return;
- case 10: pad_handle_ctrl_write(pad, value); return;
- case 14: pad->baud = value; return;
- }
-
- printf("Unhandled 16-bit PAD write at offset %08x (%04x)", offset, value);
-}
-
-void psx_pad_write8(psx_pad_t* pad, uint32_t offset, uint8_t value) {
- // if (offset <= 0xa)
- // printf("slot=%d dest=%02x pad_write8(%02x) -> %02x\n",
- // (pad->ctrl & CTRL_SLOT) >> 13,
- // pad->dest[(pad->ctrl & CTRL_SLOT) >> 13],
- // offset,
- // value
- // );
-
- switch (offset) {
- case 0: pad_write_tx(pad, value); return;
- case 8: pad->mode = value; return;
- case 10: pad_handle_ctrl_write(pad, value); return;
- case 14: pad->baud = value; return;
- }
-
- printf("Unhandled 8-bit PAD write at offset %08x (%02x)", offset, value);
-}
-
-void psx_pad_button_press(psx_pad_t* pad, int slot, uint32_t data) {
- psx_input_t* selected_slot = pad->joy_slot[slot];
-
- if (selected_slot)
- selected_slot->on_button_press_func(selected_slot->udata, data);
-}
-
-void psx_pad_button_release(psx_pad_t* pad, int slot, uint32_t data) {
- psx_input_t* selected_slot = pad->joy_slot[slot];
-
- if (selected_slot)
- selected_slot->on_button_release_func(selected_slot->udata, data);
-}
-
-void psx_pad_analog_change(psx_pad_t* pad, int slot, uint32_t stick, uint16_t data) {
- psx_input_t* selected_slot = pad->joy_slot[slot];
-
- if (selected_slot)
- selected_slot->on_analog_change_func(selected_slot->udata, stick, data);
-}
-
-void psx_pad_attach_joy(psx_pad_t* pad, int slot, psx_input_t* input) {
- if (pad->joy_slot[slot])
- psx_pad_detach_joy(pad, slot);
-
- pad->joy_slot[slot] = input;
-}
-
-void psx_pad_detach_joy(psx_pad_t* pad, int slot) {
- if (!pad->joy_slot[slot])
- return;
-
- psx_input_destroy(pad->joy_slot[slot]);
-
- pad->joy_slot[slot] = NULL;
-}
-
+
+uint8_t psx_pad_read8(psx_pad_t* pad, uint32_t offset) {+ uint32_t v = 0;
+
+ switch (offset) {+ case 0: v = pad_read_rx(pad) & 0xff; break;
+ case 4: v = pad_handle_stat_read(pad) & 0xff; break;
+ case 8: v = pad->mode; break;
+ case 10: v = pad->ctrl & 0xff; break;
+ case 14: v = pad->baud; break;
+ }
+
+ // if (offset <= 0xa)
+ // printf("slot=%d dest=%02x pad_read8(%02x) -> %02x\n",+ // (pad->ctrl & CTRL_SLOT) >> 13,
+ // pad->dest[(pad->ctrl & CTRL_SLOT) >> 13],
+ // offset,
+ // v
+ // );
+
+ return v;
+}
+
+void psx_pad_write32(psx_pad_t* pad, uint32_t offset, uint32_t value) {+ switch (offset) {+ case 0: pad_write_tx(pad, value); return;
+ case 8: pad->mode = value & 0xffff; return;
+ case 10: pad_handle_ctrl_write(pad, value); return;
+ case 14: pad->baud = value & 0xffff; return;
+ }
+
+ printf("Unhandled 32-bit PAD write at offset %08x (%08x)", offset, value);+}
+
+void psx_pad_write16(psx_pad_t* pad, uint32_t offset, uint16_t value) {+ switch (offset) {+ case 0: pad_write_tx(pad, value); return;
+ case 8: pad->mode = value; return;
+ case 10: pad_handle_ctrl_write(pad, value); return;
+ case 14: pad->baud = value; return;
+ }
+
+ printf("Unhandled 16-bit PAD write at offset %08x (%04x)", offset, value);+}
+
+void psx_pad_write8(psx_pad_t* pad, uint32_t offset, uint8_t value) {+ // if (offset <= 0xa)
+ // printf("slot=%d dest=%02x pad_write8(%02x) -> %02x\n",+ // (pad->ctrl & CTRL_SLOT) >> 13,
+ // pad->dest[(pad->ctrl & CTRL_SLOT) >> 13],
+ // offset,
+ // value
+ // );
+
+ switch (offset) {+ case 0: pad_write_tx(pad, value); return;
+ case 8: pad->mode = value; return;
+ case 10: pad_handle_ctrl_write(pad, value); return;
+ case 14: pad->baud = value; return;
+ }
+
+ printf("Unhandled 8-bit PAD write at offset %08x (%02x)", offset, value);+}
+
+void psx_pad_button_press(psx_pad_t* pad, int slot, uint32_t data) {+ psx_input_t* selected_slot = pad->joy_slot[slot];
+
+ if (selected_slot)
+ selected_slot->on_button_press_func(selected_slot->udata, data);
+}
+
+void psx_pad_button_release(psx_pad_t* pad, int slot, uint32_t data) {+ psx_input_t* selected_slot = pad->joy_slot[slot];
+
+ if (selected_slot)
+ selected_slot->on_button_release_func(selected_slot->udata, data);
+}
+
+void psx_pad_analog_change(psx_pad_t* pad, int slot, uint32_t stick, uint16_t data) {+ psx_input_t* selected_slot = pad->joy_slot[slot];
+
+ if (selected_slot)
+ selected_slot->on_analog_change_func(selected_slot->udata, stick, data);
+}
+
+void psx_pad_attach_joy(psx_pad_t* pad, int slot, psx_input_t* input) {+ if (pad->joy_slot[slot])
+ psx_pad_detach_joy(pad, slot);
+
+ pad->joy_slot[slot] = input;
+}
+
+void psx_pad_detach_joy(psx_pad_t* pad, int slot) {+ if (!pad->joy_slot[slot])
+ return;
+
+ psx_input_destroy(pad->joy_slot[slot]);
+
+ pad->joy_slot[slot] = NULL;
+}
+
int psx_pad_attach_mcd(psx_pad_t* pad, int slot, const char* path) {if (pad->mcd_slot[slot])
psx_pad_detach_mcd(pad, slot);
-
- psx_mcd_t* mcd = psx_mcd_create();
-
- int r = psx_mcd_init(mcd, path);
-
- if (r) {
- psx_pad_detach_mcd(pad, slot);
-
- return r;
- }
-
- pad->mcd_slot[slot] = mcd;
-
- return 0;
-}
-
-void psx_pad_detach_mcd(psx_pad_t* pad, int slot) {
- if (!pad->mcd_slot[slot])
- return;
-
- psx_mcd_destroy(pad->mcd_slot[slot]);
-
- pad->mcd_slot[slot] = NULL;
-}
-
-void psx_pad_update(psx_pad_t* pad, int cyc) {
- if (pad->cycles_until_irq) {
- pad->cycles_until_irq -= cyc;
-
- if (pad->cycles_until_irq <= 0) {
- psx_ic_irq(pad->ic, IC_JOY);
-
- if (pad->irq_bit) {
- pad->stat |= STAT_IRQ7;
- pad->irq_bit = 0;
- }
-
- pad->cycles_until_irq = 0;
- }
- }
-}
-
-void psx_pad_destroy(psx_pad_t* pad) {
- psx_pad_detach_joy(pad, 0);
- psx_pad_detach_joy(pad, 1);
- psx_pad_detach_mcd(pad, 0);
- psx_pad_detach_mcd(pad, 1);
-
- free(pad);
+
+ psx_mcd_t* mcd = psx_mcd_create();
+
+ int r = psx_mcd_init(mcd, path);
+
+ if (r) {+ psx_pad_detach_mcd(pad, slot);
+
+ return r;
+ }
+
+ pad->mcd_slot[slot] = mcd;
+
+ return 0;
+}
+
+void psx_pad_detach_mcd(psx_pad_t* pad, int slot) {+ if (!pad->mcd_slot[slot])
+ return;
+
+ psx_mcd_destroy(pad->mcd_slot[slot]);
+
+ pad->mcd_slot[slot] = NULL;
+}
+
+void psx_pad_update(psx_pad_t* pad, int cyc) {+ if (pad->cycles_until_irq) {+ pad->cycles_until_irq -= cyc;
+
+ if (pad->cycles_until_irq <= 0) {+ psx_ic_irq(pad->ic, IC_JOY);
+
+ if (pad->irq_bit) {+ pad->stat |= STAT_IRQ7;
+ pad->irq_bit = 0;
+ }
+
+ pad->cycles_until_irq = 0;
+ }
+ }
+}
+
+void psx_pad_destroy(psx_pad_t* pad) {+ psx_pad_detach_joy(pad, 0);
+ psx_pad_detach_joy(pad, 1);
+ psx_pad_detach_mcd(pad, 0);
+ psx_pad_detach_mcd(pad, 1);
+
+ free(pad);
}
--- a/psx/dev/pad.h
+++ b/psx/dev/pad.h
@@ -1,8 +1,8 @@
#ifndef PSX_DEV_PAD_H
-#define PSX_DEV_PAD_H
-
-#include "p9.h"
-
+#define PSX_DEV_PAD_H
+
+#include "p9.h"
+
#include "dev/ic.h"
#include "dev/input.h"
@@ -9,113 +9,113 @@
#include "input/sda.h"
typedef struct psx_mcd_t psx_mcd_t;
-
-#define PSX_PAD_BEGIN 0x1f801040
-#define PSX_PAD_SIZE 0x10
-#define PSX_PAD_END 0x1f80104f
-
-/*
- 0 TX Ready Flag 1 (1=Ready/Started)
- 1 RX FIFO Not Empty (0=Empty, 1=Not Empty)
- 2 TX Ready Flag 2 (1=Ready/Finished)
- 3 RX Parity Error (0=No, 1=Error; Wrong Parity, when enabled) (sticky)
- 4 Unknown (zero) (unlike SIO, this isn't RX FIFO Overrun flag)
- 5 Unknown (zero) (for SIO this would be RX Bad Stop Bit)
- 6 Unknown (zero) (for SIO this would be RX Input Level AFTER Stop bit)
- 7 /ACK Input Level (0=High, 1=Low)
- 8 Unknown (zero) (for SIO this would be CTS Input Level)
- 9 Interrupt Request (0=None, 1=IRQ7) (See JOY_CTRL.Bit4,10-12) (sticky)
- 10 Unknown (always zero)
- 11-31 Baudrate Timer (21bit timer, decrementing at 33MHz)
-*/
-
-#define STAT_TXR1 0x0001
-#define STAT_RXNE 0x0002
-#define STAT_TXR2 0x0004
-#define STAT_RXPE 0x0008
-#define STAT_UNK4 0x0010
-#define STAT_UNK5 0x0020
-#define STAT_UNK6 0x0040
-#define STAT_ACKL 0x0080
-#define STAT_UNK8 0x0100
-#define STAT_IRQ7 0x0200
-
-/*
- 0 TX Enable (TXEN) (0=Disable, 1=Enable)
- 1 /JOYn Output (0=High, 1=Low/Select) (/JOYn as defined in Bit13)
- 2 RX Enable (RXEN) (0=Normal, when /JOYn=Low, 1=Force Enable Once)
- 3 Unknown? (read/write-able) (for SIO, this would be TX Output Level)
- 4 Acknowledge (0=No change, 1=Reset JOY_STAT.Bits 3,9) (W)
- 5 Unknown? (read/write-able) (for SIO, this would be RTS Output Level)
- 6 Reset (0=No change, 1=Reset most JOY_registers to zero) (W)
- 7 Not used (always zero) (unlike SIO, no matter of FACTOR)
- 8-9 RX Interrupt Mode (0..3 = IRQ when RX FIFO contains 1,2,4,8 bytes)
- 10 TX Interrupt Enable (0=Disable, 1=Enable) ;when JOY_STAT.0-or-2 ;Ready
- 11 RX Interrupt Enable (0=Disable, 1=Enable) ;when N bytes in RX FIFO
- 12 ACK Interrupt Enable (0=Disable, 1=Enable) ;when JOY_STAT.7 ;/ACK=LOW
- 13 Desired Slot Number (0=/JOY1, 1=/JOY2) (set to LOW when Bit1=1)
- 14-15 Not used (always zero)
-*/
-
-#define CTRL_TXEN 0x0001
-#define CTRL_JOUT 0x0002
-#define CTRL_RXEN 0x0004
-#define CTRL_UNK3 0x0008
-#define CTRL_ACKN 0x0010
-#define CTRL_UNK5 0x0020
-#define CTRL_REST 0x0040
-#define CTRL_NUS7 0x0080
-#define CTRL_RXIM 0x0300
-#define CTRL_TXIE 0x0400
-#define CTRL_RXIE 0x0800
-#define CTRL_ACIE 0x1000
-#define CTRL_SLOT 0x2000
-
-enum {
- DEST_JOY = 0x01,
- DEST_MCD = 0x81
-};
-
-enum {
- PAD_CONTROLLER_SDA,
- PAD_CONTROLLER_MOUSE,
- PAD_CONTROLLER_NAMCO_VOLUME,
- PAD_CONTROLLER_SANKYO_NASUKA,
- PAD_WHEEL_NEGCON,
- PAD_WHEEL_MADCATZ,
- PAD_WHEEL_MADCATZ_MC2
-};
-
-/*
- To-do: Design API to interface any type of controller.
-
- Possible names:
- - psx_im (Input Method)
- - psx_controller
- - psx_input
-
- Private API should contain a way to get the ID of
- this controller, public API should contain the following
- functions: (WIP)
- - _write(data)
- - _read()
- _ _on_button_press(id)
- - _on_button_release(id)
- - _on_analog_change(id)
-*/
-
+
+#define PSX_PAD_BEGIN 0x1f801040
+#define PSX_PAD_SIZE 0x10
+#define PSX_PAD_END 0x1f80104f
+
+/*
+ 0 TX Ready Flag 1 (1=Ready/Started)
+ 1 RX FIFO Not Empty (0=Empty, 1=Not Empty)
+ 2 TX Ready Flag 2 (1=Ready/Finished)
+ 3 RX Parity Error (0=No, 1=Error; Wrong Parity, when enabled) (sticky)
+ 4 Unknown (zero) (unlike SIO, this isn't RX FIFO Overrun flag)
+ 5 Unknown (zero) (for SIO this would be RX Bad Stop Bit)
+ 6 Unknown (zero) (for SIO this would be RX Input Level AFTER Stop bit)
+ 7 /ACK Input Level (0=High, 1=Low)
+ 8 Unknown (zero) (for SIO this would be CTS Input Level)
+ 9 Interrupt Request (0=None, 1=IRQ7) (See JOY_CTRL.Bit4,10-12) (sticky)
+ 10 Unknown (always zero)
+ 11-31 Baudrate Timer (21bit timer, decrementing at 33MHz)
+*/
+
+#define STAT_TXR1 0x0001
+#define STAT_RXNE 0x0002
+#define STAT_TXR2 0x0004
+#define STAT_RXPE 0x0008
+#define STAT_UNK4 0x0010
+#define STAT_UNK5 0x0020
+#define STAT_UNK6 0x0040
+#define STAT_ACKL 0x0080
+#define STAT_UNK8 0x0100
+#define STAT_IRQ7 0x0200
+
+/*
+ 0 TX Enable (TXEN) (0=Disable, 1=Enable)
+ 1 /JOYn Output (0=High, 1=Low/Select) (/JOYn as defined in Bit13)
+ 2 RX Enable (RXEN) (0=Normal, when /JOYn=Low, 1=Force Enable Once)
+ 3 Unknown? (read/write-able) (for SIO, this would be TX Output Level)
+ 4 Acknowledge (0=No change, 1=Reset JOY_STAT.Bits 3,9) (W)
+ 5 Unknown? (read/write-able) (for SIO, this would be RTS Output Level)
+ 6 Reset (0=No change, 1=Reset most JOY_registers to zero) (W)
+ 7 Not used (always zero) (unlike SIO, no matter of FACTOR)
+ 8-9 RX Interrupt Mode (0..3 = IRQ when RX FIFO contains 1,2,4,8 bytes)
+ 10 TX Interrupt Enable (0=Disable, 1=Enable) ;when JOY_STAT.0-or-2 ;Ready
+ 11 RX Interrupt Enable (0=Disable, 1=Enable) ;when N bytes in RX FIFO
+ 12 ACK Interrupt Enable (0=Disable, 1=Enable) ;when JOY_STAT.7 ;/ACK=LOW
+ 13 Desired Slot Number (0=/JOY1, 1=/JOY2) (set to LOW when Bit1=1)
+ 14-15 Not used (always zero)
+*/
+
+#define CTRL_TXEN 0x0001
+#define CTRL_JOUT 0x0002
+#define CTRL_RXEN 0x0004
+#define CTRL_UNK3 0x0008
+#define CTRL_ACKN 0x0010
+#define CTRL_UNK5 0x0020
+#define CTRL_REST 0x0040
+#define CTRL_NUS7 0x0080
+#define CTRL_RXIM 0x0300
+#define CTRL_TXIE 0x0400
+#define CTRL_RXIE 0x0800
+#define CTRL_ACIE 0x1000
+#define CTRL_SLOT 0x2000
+
+enum {+ DEST_JOY = 0x01,
+ DEST_MCD = 0x81
+};
+
+enum {+ PAD_CONTROLLER_SDA,
+ PAD_CONTROLLER_MOUSE,
+ PAD_CONTROLLER_NAMCO_VOLUME,
+ PAD_CONTROLLER_SANKYO_NASUKA,
+ PAD_WHEEL_NEGCON,
+ PAD_WHEEL_MADCATZ,
+ PAD_WHEEL_MADCATZ_MC2
+};
+
+/*
+ To-do: Design API to interface any type of controller.
+
+ Possible names:
+ - psx_im (Input Method)
+ - psx_controller
+ - psx_input
+
+ Private API should contain a way to get the ID of
+ this controller, public API should contain the following
+ functions: (WIP)
+ - _write(data)
+ - _read()
+ _ _on_button_press(id)
+ - _on_button_release(id)
+ - _on_analog_change(id)
+*/
+
struct psx_pad_t {uint32_t bus_delay;
uint32_t io_base, io_size;
-
- psx_ic_t* ic;
- psx_input_t* joy_slot[2];
- psx_mcd_t* mcd_slot[2];
-
- int enable_once;
- int cycles_until_irq;
- int cycle_counter;
- int dest[2];
+
+ psx_ic_t* ic;
+ psx_input_t* joy_slot[2];
+ psx_mcd_t* mcd_slot[2];
+
+ int enable_once;
+ int cycles_until_irq;
+ int cycle_counter;
+ int dest[2];
int irq_bit;
uint16_t mode, ctrl, baud, stat;
@@ -122,23 +122,23 @@
};
typedef struct psx_pad_t psx_pad_t;
-
-psx_pad_t* psx_pad_create(void);
-void psx_pad_init(psx_pad_t*, psx_ic_t*);
-uint32_t psx_pad_read32(psx_pad_t*, uint32_t);
-uint16_t psx_pad_read16(psx_pad_t*, uint32_t);
-uint8_t psx_pad_read8(psx_pad_t*, uint32_t);
-void psx_pad_write32(psx_pad_t*, uint32_t, uint32_t);
-void psx_pad_write16(psx_pad_t*, uint32_t, uint16_t);
-void psx_pad_write8(psx_pad_t*, uint32_t, uint8_t);
-void psx_pad_destroy(psx_pad_t*);
-void psx_pad_button_press(psx_pad_t*, int, uint32_t);
-void psx_pad_button_release(psx_pad_t*, int, uint32_t);
-void psx_pad_analog_change(psx_pad_t*, int, uint32_t, uint16_t);
-void psx_pad_attach_joy(psx_pad_t*, int, psx_input_t*);
-void psx_pad_detach_joy(psx_pad_t*, int);
-int psx_pad_attach_mcd(psx_pad_t*, int, const char*);
-void psx_pad_detach_mcd(psx_pad_t*, int);
-void psx_pad_update(psx_pad_t*, int);
-
+
+psx_pad_t* psx_pad_create(void);
+void psx_pad_init(psx_pad_t*, psx_ic_t*);
+uint32_t psx_pad_read32(psx_pad_t*, uint32_t);
+uint16_t psx_pad_read16(psx_pad_t*, uint32_t);
+uint8_t psx_pad_read8(psx_pad_t*, uint32_t);
+void psx_pad_write32(psx_pad_t*, uint32_t, uint32_t);
+void psx_pad_write16(psx_pad_t*, uint32_t, uint16_t);
+void psx_pad_write8(psx_pad_t*, uint32_t, uint8_t);
+void psx_pad_destroy(psx_pad_t*);
+void psx_pad_button_press(psx_pad_t*, int, uint32_t);
+void psx_pad_button_release(psx_pad_t*, int, uint32_t);
+void psx_pad_analog_change(psx_pad_t*, int, uint32_t, uint16_t);
+void psx_pad_attach_joy(psx_pad_t*, int, psx_input_t*);
+void psx_pad_detach_joy(psx_pad_t*, int);
+int psx_pad_attach_mcd(psx_pad_t*, int, const char*);
+void psx_pad_detach_mcd(psx_pad_t*, int);
+void psx_pad_update(psx_pad_t*, int);
+
#endif
--- a/psx/dev/ram.c
+++ b/psx/dev/ram.c
@@ -3,77 +3,77 @@
#include "dev/mc2.h"
#include "p9.h"
-
-psx_ram_t* psx_ram_create(void) {
- return (psx_ram_t*)malloc(sizeof(psx_ram_t));
-}
-
-void psx_ram_init(psx_ram_t* ram, psx_mc2_t* mc2, int size) {
- memset(ram, 0, sizeof(psx_ram_t));
-
- ram->io_base = PSX_RAM_BEGIN;
- ram->io_size = PSX_RAM_SIZE;
-
- ram->mc2 = mc2;
- ram->buf = (uint8_t*)malloc(size);
- ram->size = size;
-
- // Size has to be a multiple of 2MB, default to 2MB
- if (size & 0x1ffff)
- size = RAM_SIZE_2MB;
-
- memset(ram->buf, RAM_INIT_FILL, size);
-}
-
-uint32_t psx_ram_read32(psx_ram_t* ram, uint32_t offset) {
- if (((ram->mc2->ram_size >> 9) & 7) == 3)
- if (offset >= 0x400000)
- return 0xffffffff;
-
- offset &= ram->size - 1;
-
- return *((uint32_t*)(ram->buf + offset));
-}
-
-uint16_t psx_ram_read16(psx_ram_t* ram, uint32_t offset) {
- if (((ram->mc2->ram_size >> 9) & 7) == 3)
- if (offset >= 0x400000)
- return 0xffff;
-
- offset &= ram->size - 1;
-
- return *((uint16_t*)(ram->buf + offset));
-}
-
-uint8_t psx_ram_read8(psx_ram_t* ram, uint32_t offset) {
- if (((ram->mc2->ram_size >> 9) & 7) == 3)
- if (offset >= 0x400000)
- return 0xff;
-
- offset &= ram->size - 1;
-
- return ram->buf[offset];
-}
-
-void psx_ram_write32(psx_ram_t* ram, uint32_t offset, uint32_t value) {
- offset &= ram->size - 1;
-
- *((uint32_t*)(ram->buf + offset)) = value;
-}
-
-void psx_ram_write16(psx_ram_t* ram, uint32_t offset, uint16_t value) {
- offset &= ram->size - 1;
-
- *((uint16_t*)(ram->buf + offset)) = value;
-}
-
-void psx_ram_write8(psx_ram_t* ram, uint32_t offset, uint8_t value) {
- offset &= ram->size - 1;
-
- ram->buf[offset] = value;
-}
-
-void psx_ram_destroy(psx_ram_t* ram) {
- free(ram->buf);
- free(ram);
+
+psx_ram_t* psx_ram_create(void) {+ return (psx_ram_t*)malloc(sizeof(psx_ram_t));
+}
+
+void psx_ram_init(psx_ram_t* ram, psx_mc2_t* mc2, int size) {+ memset(ram, 0, sizeof(psx_ram_t));
+
+ ram->io_base = PSX_RAM_BEGIN;
+ ram->io_size = PSX_RAM_SIZE;
+
+ ram->mc2 = mc2;
+ ram->buf = (uint8_t*)malloc(size);
+ ram->size = size;
+
+ // Size has to be a multiple of 2MB, default to 2MB
+ if (size & 0x1ffff)
+ size = RAM_SIZE_2MB;
+
+ memset(ram->buf, RAM_INIT_FILL, size);
+}
+
+uint32_t psx_ram_read32(psx_ram_t* ram, uint32_t offset) {+ if (((ram->mc2->ram_size >> 9) & 7) == 3)
+ if (offset >= 0x400000)
+ return 0xffffffff;
+
+ offset &= ram->size - 1;
+
+ return *((uint32_t*)(ram->buf + offset));
+}
+
+uint16_t psx_ram_read16(psx_ram_t* ram, uint32_t offset) {+ if (((ram->mc2->ram_size >> 9) & 7) == 3)
+ if (offset >= 0x400000)
+ return 0xffff;
+
+ offset &= ram->size - 1;
+
+ return *((uint16_t*)(ram->buf + offset));
+}
+
+uint8_t psx_ram_read8(psx_ram_t* ram, uint32_t offset) {+ if (((ram->mc2->ram_size >> 9) & 7) == 3)
+ if (offset >= 0x400000)
+ return 0xff;
+
+ offset &= ram->size - 1;
+
+ return ram->buf[offset];
+}
+
+void psx_ram_write32(psx_ram_t* ram, uint32_t offset, uint32_t value) {+ offset &= ram->size - 1;
+
+ *((uint32_t*)(ram->buf + offset)) = value;
+}
+
+void psx_ram_write16(psx_ram_t* ram, uint32_t offset, uint16_t value) {+ offset &= ram->size - 1;
+
+ *((uint16_t*)(ram->buf + offset)) = value;
+}
+
+void psx_ram_write8(psx_ram_t* ram, uint32_t offset, uint8_t value) {+ offset &= ram->size - 1;
+
+ ram->buf[offset] = value;
+}
+
+void psx_ram_destroy(psx_ram_t* ram) {+ free(ram->buf);
+ free(ram);
}
--- a/psx/dev/ram.h
+++ b/psx/dev/ram.h
@@ -1,28 +1,28 @@
#ifndef PSX_DEV_RAM_H
#define PSX_DEV_RAM_H
-
+
#include "p9.h"
#include "log.h"
typedef struct psx_mc2_t psx_mc2_t;
-
-#define PSX_RAM_SIZE 0x800000 // 8MB window
-#define PSX_RAM_BEGIN 0x00000000
-//#define PSX_RAM_END 0x001fffff
-#define PSX_RAM_END 0x1effffff
-#define RAM_INIT_FILL 0
-
-#define RAM_SIZE_2MB 0x200000
-#define RAM_SIZE_4MB 0x400000
-#define RAM_SIZE_8MB 0x800000
-
+
+#define PSX_RAM_SIZE 0x800000 // 8MB window
+#define PSX_RAM_BEGIN 0x00000000
+//#define PSX_RAM_END 0x001fffff
+#define PSX_RAM_END 0x1effffff
+#define RAM_INIT_FILL 0
+
+#define RAM_SIZE_2MB 0x200000
+#define RAM_SIZE_4MB 0x400000
+#define RAM_SIZE_8MB 0x800000
+
struct psx_ram_t {uint32_t bus_delay;
uint32_t io_base, io_size;
-
+
uintptr size;
-
+
psx_mc2_t* mc2;
uint8_t* buf;
@@ -29,15 +29,15 @@
};
typedef struct psx_ram_t psx_ram_t;
-
-psx_ram_t* psx_ram_create(void);
-void psx_ram_init(psx_ram_t*, psx_mc2_t*, int size);
-uint32_t psx_ram_read32(psx_ram_t*, uint32_t);
-uint16_t psx_ram_read16(psx_ram_t*, uint32_t);
-uint8_t psx_ram_read8(psx_ram_t*, uint32_t);
-void psx_ram_write32(psx_ram_t*, uint32_t, uint32_t);
-void psx_ram_write16(psx_ram_t*, uint32_t, uint16_t);
-void psx_ram_write8(psx_ram_t*, uint32_t, uint8_t);
-void psx_ram_destroy(psx_ram_t*);
-
+
+psx_ram_t* psx_ram_create(void);
+void psx_ram_init(psx_ram_t*, psx_mc2_t*, int size);
+uint32_t psx_ram_read32(psx_ram_t*, uint32_t);
+uint16_t psx_ram_read16(psx_ram_t*, uint32_t);
+uint8_t psx_ram_read8(psx_ram_t*, uint32_t);
+void psx_ram_write32(psx_ram_t*, uint32_t, uint32_t);
+void psx_ram_write16(psx_ram_t*, uint32_t, uint16_t);
+void psx_ram_write8(psx_ram_t*, uint32_t, uint8_t);
+void psx_ram_destroy(psx_ram_t*);
+
#endif
--- a/psx/dev/scratchpad.c
+++ b/psx/dev/scratchpad.c
@@ -1,46 +1,46 @@
-#include "p9.h"
-
-#include "log.h"
-#include "dev/scratchpad.h"
-
-psx_scratchpad_t* psx_scratchpad_create(void) {
- return (psx_scratchpad_t*)malloc(sizeof(psx_scratchpad_t));
-}
-
-void psx_scratchpad_init(psx_scratchpad_t* scratchpad) {
- memset(scratchpad, 0, sizeof(psx_scratchpad_t));
-
- scratchpad->io_base = PSX_SCRATCHPAD_BEGIN;
- scratchpad->io_size = PSX_SCRATCHPAD_SIZE;
-
- scratchpad->buf = (uint8_t*)malloc(PSX_SCRATCHPAD_SIZE);
-}
-
-uint32_t psx_scratchpad_read32(psx_scratchpad_t* scratchpad, uint32_t offset) {
- return *((uint32_t*)(scratchpad->buf + offset));
-}
-
-uint16_t psx_scratchpad_read16(psx_scratchpad_t* scratchpad, uint32_t offset) {
- return *((uint16_t*)(scratchpad->buf + offset));
-}
-
-uint8_t psx_scratchpad_read8(psx_scratchpad_t* scratchpad, uint32_t offset) {
- return scratchpad->buf[offset];
-}
-
-void psx_scratchpad_write32(psx_scratchpad_t* scratchpad, uint32_t offset, uint32_t value) {
- *((uint32_t*)(scratchpad->buf + offset)) = value;
-}
-
-void psx_scratchpad_write16(psx_scratchpad_t* scratchpad, uint32_t offset, uint16_t value) {
- *((uint16_t*)(scratchpad->buf + offset)) = value;
-}
-
-void psx_scratchpad_write8(psx_scratchpad_t* scratchpad, uint32_t offset, uint8_t value) {
- scratchpad->buf[offset] = value;
-}
-
-void psx_scratchpad_destroy(psx_scratchpad_t* scratchpad) {
- free(scratchpad->buf);
- free(scratchpad);
+#include "p9.h"
+
+#include "log.h"
+#include "dev/scratchpad.h"
+
+psx_scratchpad_t* psx_scratchpad_create(void) {+ return (psx_scratchpad_t*)malloc(sizeof(psx_scratchpad_t));
+}
+
+void psx_scratchpad_init(psx_scratchpad_t* scratchpad) {+ memset(scratchpad, 0, sizeof(psx_scratchpad_t));
+
+ scratchpad->io_base = PSX_SCRATCHPAD_BEGIN;
+ scratchpad->io_size = PSX_SCRATCHPAD_SIZE;
+
+ scratchpad->buf = (uint8_t*)malloc(PSX_SCRATCHPAD_SIZE);
+}
+
+uint32_t psx_scratchpad_read32(psx_scratchpad_t* scratchpad, uint32_t offset) {+ return *((uint32_t*)(scratchpad->buf + offset));
+}
+
+uint16_t psx_scratchpad_read16(psx_scratchpad_t* scratchpad, uint32_t offset) {+ return *((uint16_t*)(scratchpad->buf + offset));
+}
+
+uint8_t psx_scratchpad_read8(psx_scratchpad_t* scratchpad, uint32_t offset) {+ return scratchpad->buf[offset];
+}
+
+void psx_scratchpad_write32(psx_scratchpad_t* scratchpad, uint32_t offset, uint32_t value) {+ *((uint32_t*)(scratchpad->buf + offset)) = value;
+}
+
+void psx_scratchpad_write16(psx_scratchpad_t* scratchpad, uint32_t offset, uint16_t value) {+ *((uint16_t*)(scratchpad->buf + offset)) = value;
+}
+
+void psx_scratchpad_write8(psx_scratchpad_t* scratchpad, uint32_t offset, uint8_t value) {+ scratchpad->buf[offset] = value;
+}
+
+void psx_scratchpad_destroy(psx_scratchpad_t* scratchpad) {+ free(scratchpad->buf);
+ free(scratchpad);
}
\ No newline at end of file
--- a/psx/dev/scratchpad.h
+++ b/psx/dev/scratchpad.h
@@ -1,14 +1,14 @@
#ifndef PSX_DEV_SCRATCHPAD_H
-#define PSX_DEV_SCRATCHPAD_H
-
-#include "p9.h"
-
-#include "dev/mc1.h"
-
-#define PSX_SCRATCHPAD_BEGIN 0x1f800000
-#define PSX_SCRATCHPAD_SIZE 0x400
-#define PSX_SCRATCHPAD_END 0x1f8003ff
-
+#define PSX_DEV_SCRATCHPAD_H
+
+#include "p9.h"
+
+#include "dev/mc1.h"
+
+#define PSX_SCRATCHPAD_BEGIN 0x1f800000
+#define PSX_SCRATCHPAD_SIZE 0x400
+#define PSX_SCRATCHPAD_END 0x1f8003ff
+
struct psx_scratchpad_t {uint32_t bus_delay;
uint32_t io_base, io_size;
@@ -17,15 +17,15 @@
};
typedef struct psx_scratchpad_t psx_scratchpad_t;
-
-psx_scratchpad_t* psx_scratchpad_create(void);
-void psx_scratchpad_init(psx_scratchpad_t*);
-uint32_t psx_scratchpad_read32(psx_scratchpad_t*, uint32_t);
-uint16_t psx_scratchpad_read16(psx_scratchpad_t*, uint32_t);
-uint8_t psx_scratchpad_read8(psx_scratchpad_t*, uint32_t);
-void psx_scratchpad_write32(psx_scratchpad_t*, uint32_t, uint32_t);
-void psx_scratchpad_write16(psx_scratchpad_t*, uint32_t, uint16_t);
-void psx_scratchpad_write8(psx_scratchpad_t*, uint32_t, uint8_t);
-void psx_scratchpad_destroy(psx_scratchpad_t*);
-
+
+psx_scratchpad_t* psx_scratchpad_create(void);
+void psx_scratchpad_init(psx_scratchpad_t*);
+uint32_t psx_scratchpad_read32(psx_scratchpad_t*, uint32_t);
+uint16_t psx_scratchpad_read16(psx_scratchpad_t*, uint32_t);
+uint8_t psx_scratchpad_read8(psx_scratchpad_t*, uint32_t);
+void psx_scratchpad_write32(psx_scratchpad_t*, uint32_t, uint32_t);
+void psx_scratchpad_write16(psx_scratchpad_t*, uint32_t, uint16_t);
+void psx_scratchpad_write8(psx_scratchpad_t*, uint32_t, uint8_t);
+void psx_scratchpad_destroy(psx_scratchpad_t*);
+
#endif
--- a/psx/dev/spu.c
+++ b/psx/dev/spu.c
@@ -1,747 +1,747 @@
-#include "p9.h"
-
-#include "dev/spu.h"
-#include "log.h"
-
-#define CLAMP(v, l, h) (((v) <= (l)) ? (l) : (((v) >= (h)) ? (h) : (v)))
-#define MAX(a, b) ((a) > (b) ? (a) : (b))
-
-#define VOICE_COUNT 24
-
-// static float interpolate_hermite(float a, float b, float c, float d, float t) {
-// float x = -a/2.0f + (3.0f*b)/2.0f - (3.0f*c)/2.0f + d/2.0f;
-// float y = a - (5.0f*b)/2.0f + 2.0f*c - d / 2.0f;
-// float z = -a/2.0f + c/2.0f;
-// float w = b;
-
-// return (x*t*t*t) + (y*t*t) + (z*t) + w;
-// }
-
-static const int g_spu_pos_adpcm_table[] = {
- 0, +60, +115, +98, +122
-};
-
-static const int g_spu_neg_adpcm_table[] = {
- 0, 0, -52, -55, -60
-};
-
-static const int16_t g_spu_gauss_table[] = {
- -0x001, -0x001, -0x001, -0x001, -0x001, -0x001, -0x001, -0x001,
- -0x001, -0x001, -0x001, -0x001, -0x001, -0x001, -0x001, -0x001,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001,
- 0x0001, 0x0001, 0x0001, 0x0002, 0x0002, 0x0002, 0x0003, 0x0003,
- 0x0003, 0x0004, 0x0004, 0x0005, 0x0005, 0x0006, 0x0007, 0x0007,
- 0x0008, 0x0009, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E,
- 0x000F, 0x0010, 0x0011, 0x0012, 0x0013, 0x0015, 0x0016, 0x0018,
- 0x0019, 0x001B, 0x001C, 0x001E, 0x0020, 0x0021, 0x0023, 0x0025,
- 0x0027, 0x0029, 0x002C, 0x002E, 0x0030, 0x0033, 0x0035, 0x0038,
- 0x003A, 0x003D, 0x0040, 0x0043, 0x0046, 0x0049, 0x004D, 0x0050,
- 0x0054, 0x0057, 0x005B, 0x005F, 0x0063, 0x0067, 0x006B, 0x006F,
- 0x0074, 0x0078, 0x007D, 0x0082, 0x0087, 0x008C, 0x0091, 0x0096,
- 0x009C, 0x00A1, 0x00A7, 0x00AD, 0x00B3, 0x00BA, 0x00C0, 0x00C7,
- 0x00CD, 0x00D4, 0x00DB, 0x00E3, 0x00EA, 0x00F2, 0x00FA, 0x0101,
- 0x010A, 0x0112, 0x011B, 0x0123, 0x012C, 0x0135, 0x013F, 0x0148,
- 0x0152, 0x015C, 0x0166, 0x0171, 0x017B, 0x0186, 0x0191, 0x019C,
- 0x01A8, 0x01B4, 0x01C0, 0x01CC, 0x01D9, 0x01E5, 0x01F2, 0x0200,
- 0x020D, 0x021B, 0x0229, 0x0237, 0x0246, 0x0255, 0x0264, 0x0273,
- 0x0283, 0x0293, 0x02A3, 0x02B4, 0x02C4, 0x02D6, 0x02E7, 0x02F9,
- 0x030B, 0x031D, 0x0330, 0x0343, 0x0356, 0x036A, 0x037E, 0x0392,
- 0x03A7, 0x03BC, 0x03D1, 0x03E7, 0x03FC, 0x0413, 0x042A, 0x0441,
- 0x0458, 0x0470, 0x0488, 0x04A0, 0x04B9, 0x04D2, 0x04EC, 0x0506,
- 0x0520, 0x053B, 0x0556, 0x0572, 0x058E, 0x05AA, 0x05C7, 0x05E4,
- 0x0601, 0x061F, 0x063E, 0x065C, 0x067C, 0x069B, 0x06BB, 0x06DC,
- 0x06FD, 0x071E, 0x0740, 0x0762, 0x0784, 0x07A7, 0x07CB, 0x07EF,
- 0x0813, 0x0838, 0x085D, 0x0883, 0x08A9, 0x08D0, 0x08F7, 0x091E,
- 0x0946, 0x096F, 0x0998, 0x09C1, 0x09EB, 0x0A16, 0x0A40, 0x0A6C,
- 0x0A98, 0x0AC4, 0x0AF1, 0x0B1E, 0x0B4C, 0x0B7A, 0x0BA9, 0x0BD8,
- 0x0C07, 0x0C38, 0x0C68, 0x0C99, 0x0CCB, 0x0CFD, 0x0D30, 0x0D63,
- 0x0D97, 0x0DCB, 0x0E00, 0x0E35, 0x0E6B, 0x0EA1, 0x0ED7, 0x0F0F,
- 0x0F46, 0x0F7F, 0x0FB7, 0x0FF1, 0x102A, 0x1065, 0x109F, 0x10DB,
- 0x1116, 0x1153, 0x118F, 0x11CD, 0x120B, 0x1249, 0x1288, 0x12C7,
- 0x1307, 0x1347, 0x1388, 0x13C9, 0x140B, 0x144D, 0x1490, 0x14D4,
- 0x1517, 0x155C, 0x15A0, 0x15E6, 0x162C, 0x1672, 0x16B9, 0x1700,
- 0x1747, 0x1790, 0x17D8, 0x1821, 0x186B, 0x18B5, 0x1900, 0x194B,
- 0x1996, 0x19E2, 0x1A2E, 0x1A7B, 0x1AC8, 0x1B16, 0x1B64, 0x1BB3,
- 0x1C02, 0x1C51, 0x1CA1, 0x1CF1, 0x1D42, 0x1D93, 0x1DE5, 0x1E37,
- 0x1E89, 0x1EDC, 0x1F2F, 0x1F82, 0x1FD6, 0x202A, 0x207F, 0x20D4,
- 0x2129, 0x217F, 0x21D5, 0x222C, 0x2282, 0x22DA, 0x2331, 0x2389,
- 0x23E1, 0x2439, 0x2492, 0x24EB, 0x2545, 0x259E, 0x25F8, 0x2653,
- 0x26AD, 0x2708, 0x2763, 0x27BE, 0x281A, 0x2876, 0x28D2, 0x292E,
- 0x298B, 0x29E7, 0x2A44, 0x2AA1, 0x2AFF, 0x2B5C, 0x2BBA, 0x2C18,
- 0x2C76, 0x2CD4, 0x2D33, 0x2D91, 0x2DF0, 0x2E4F, 0x2EAE, 0x2F0D,
- 0x2F6C, 0x2FCC, 0x302B, 0x308B, 0x30EA, 0x314A, 0x31AA, 0x3209,
- 0x3269, 0x32C9, 0x3329, 0x3389, 0x33E9, 0x3449, 0x34A9, 0x3509,
- 0x3569, 0x35C9, 0x3629, 0x3689, 0x36E8, 0x3748, 0x37A8, 0x3807,
- 0x3867, 0x38C6, 0x3926, 0x3985, 0x39E4, 0x3A43, 0x3AA2, 0x3B00,
- 0x3B5F, 0x3BBD, 0x3C1B, 0x3C79, 0x3CD7, 0x3D35, 0x3D92, 0x3DEF,
- 0x3E4C, 0x3EA9, 0x3F05, 0x3F62, 0x3FBD, 0x4019, 0x4074, 0x40D0,
- 0x412A, 0x4185, 0x41DF, 0x4239, 0x4292, 0x42EB, 0x4344, 0x439C,
- 0x43F4, 0x444C, 0x44A3, 0x44FA, 0x4550, 0x45A6, 0x45FC, 0x4651,
- 0x46A6, 0x46FA, 0x474E, 0x47A1, 0x47F4, 0x4846, 0x4898, 0x48E9,
- 0x493A, 0x498A, 0x49D9, 0x4A29, 0x4A77, 0x4AC5, 0x4B13, 0x4B5F,
- 0x4BAC, 0x4BF7, 0x4C42, 0x4C8D, 0x4CD7, 0x4D20, 0x4D68, 0x4DB0,
- 0x4DF7, 0x4E3E, 0x4E84, 0x4EC9, 0x4F0E, 0x4F52, 0x4F95, 0x4FD7,
- 0x5019, 0x505A, 0x509A, 0x50DA, 0x5118, 0x5156, 0x5194, 0x51D0,
- 0x520C, 0x5247, 0x5281, 0x52BA, 0x52F3, 0x532A, 0x5361, 0x5397,
- 0x53CC, 0x5401, 0x5434, 0x5467, 0x5499, 0x54CA, 0x54FA, 0x5529,
- 0x5558, 0x5585, 0x55B2, 0x55DE, 0x5609, 0x5632, 0x565B, 0x5684,
- 0x56AB, 0x56D1, 0x56F6, 0x571B, 0x573E, 0x5761, 0x5782, 0x57A3,
- 0x57C3, 0x57E2, 0x57FF, 0x581C, 0x5838, 0x5853, 0x586D, 0x5886,
- 0x589E, 0x58B5, 0x58CB, 0x58E0, 0x58F4, 0x5907, 0x5919, 0x592A,
- 0x593A, 0x5949, 0x5958, 0x5965, 0x5971, 0x597C, 0x5986, 0x598F,
- 0x5997, 0x599E, 0x59A4, 0x59A9, 0x59AD, 0x59B0, 0x59B2, 0x59B3
-};
-
-psx_spu_t* psx_spu_create(void) {
- return (psx_spu_t*)malloc(sizeof(psx_spu_t));
-}
-
-void psx_spu_init(psx_spu_t* spu, psx_ic_t* ic) {
- memset(spu, 0, sizeof(psx_spu_t));
-
- spu->io_base = PSX_SPU_BEGIN;
- spu->io_size = PSX_SPU_SIZE;
-
- spu->ic = ic;
- spu->ram = (uint8_t*)malloc(SPU_RAM_SIZE);
-
- memset(spu->ram, 0, SPU_RAM_SIZE);
-
- // Mute all voices
- spu->endx = 0x00ffffff;
- spu->irq9addr = 0xffff;
-}
-
-uint32_t psx_spu_read32(psx_spu_t* spu, uint32_t offset) {
- const uint8_t* ptr = (uint8_t*)&spu->voice[0].volumel;
-
- return *((uint32_t*)(ptr + offset));
-}
-
-uint16_t psx_spu_read16(psx_spu_t* spu, uint32_t offset) {
- if (offset == SPUR_TFIFO) {
- uint16_t data = *(uint16_t*)(&spu->ram[spu->taddr]);
-
- spu->taddr += 2;
-
- return data;
- }
-
- const uint8_t* ptr = (uint8_t*)&spu->voice[0].volumel;
-
- return *((uint16_t*)(ptr + offset));
-}
-
+#include "p9.h"
+
+#include "dev/spu.h"
+#include "log.h"
+
+#define CLAMP(v, l, h) (((v) <= (l)) ? (l) : (((v) >= (h)) ? (h) : (v)))
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+#define VOICE_COUNT 24
+
+// static float interpolate_hermite(float a, float b, float c, float d, float t) {+// float x = -a/2.0f + (3.0f*b)/2.0f - (3.0f*c)/2.0f + d/2.0f;
+// float y = a - (5.0f*b)/2.0f + 2.0f*c - d / 2.0f;
+// float z = -a/2.0f + c/2.0f;
+// float w = b;
+
+// return (x*t*t*t) + (y*t*t) + (z*t) + w;
+// }
+
+static const int g_spu_pos_adpcm_table[] = {+ 0, +60, +115, +98, +122
+};
+
+static const int g_spu_neg_adpcm_table[] = {+ 0, 0, -52, -55, -60
+};
+
+static const int16_t g_spu_gauss_table[] = {+ -0x001, -0x001, -0x001, -0x001, -0x001, -0x001, -0x001, -0x001,
+ -0x001, -0x001, -0x001, -0x001, -0x001, -0x001, -0x001, -0x001,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001,
+ 0x0001, 0x0001, 0x0001, 0x0002, 0x0002, 0x0002, 0x0003, 0x0003,
+ 0x0003, 0x0004, 0x0004, 0x0005, 0x0005, 0x0006, 0x0007, 0x0007,
+ 0x0008, 0x0009, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E,
+ 0x000F, 0x0010, 0x0011, 0x0012, 0x0013, 0x0015, 0x0016, 0x0018,
+ 0x0019, 0x001B, 0x001C, 0x001E, 0x0020, 0x0021, 0x0023, 0x0025,
+ 0x0027, 0x0029, 0x002C, 0x002E, 0x0030, 0x0033, 0x0035, 0x0038,
+ 0x003A, 0x003D, 0x0040, 0x0043, 0x0046, 0x0049, 0x004D, 0x0050,
+ 0x0054, 0x0057, 0x005B, 0x005F, 0x0063, 0x0067, 0x006B, 0x006F,
+ 0x0074, 0x0078, 0x007D, 0x0082, 0x0087, 0x008C, 0x0091, 0x0096,
+ 0x009C, 0x00A1, 0x00A7, 0x00AD, 0x00B3, 0x00BA, 0x00C0, 0x00C7,
+ 0x00CD, 0x00D4, 0x00DB, 0x00E3, 0x00EA, 0x00F2, 0x00FA, 0x0101,
+ 0x010A, 0x0112, 0x011B, 0x0123, 0x012C, 0x0135, 0x013F, 0x0148,
+ 0x0152, 0x015C, 0x0166, 0x0171, 0x017B, 0x0186, 0x0191, 0x019C,
+ 0x01A8, 0x01B4, 0x01C0, 0x01CC, 0x01D9, 0x01E5, 0x01F2, 0x0200,
+ 0x020D, 0x021B, 0x0229, 0x0237, 0x0246, 0x0255, 0x0264, 0x0273,
+ 0x0283, 0x0293, 0x02A3, 0x02B4, 0x02C4, 0x02D6, 0x02E7, 0x02F9,
+ 0x030B, 0x031D, 0x0330, 0x0343, 0x0356, 0x036A, 0x037E, 0x0392,
+ 0x03A7, 0x03BC, 0x03D1, 0x03E7, 0x03FC, 0x0413, 0x042A, 0x0441,
+ 0x0458, 0x0470, 0x0488, 0x04A0, 0x04B9, 0x04D2, 0x04EC, 0x0506,
+ 0x0520, 0x053B, 0x0556, 0x0572, 0x058E, 0x05AA, 0x05C7, 0x05E4,
+ 0x0601, 0x061F, 0x063E, 0x065C, 0x067C, 0x069B, 0x06BB, 0x06DC,
+ 0x06FD, 0x071E, 0x0740, 0x0762, 0x0784, 0x07A7, 0x07CB, 0x07EF,
+ 0x0813, 0x0838, 0x085D, 0x0883, 0x08A9, 0x08D0, 0x08F7, 0x091E,
+ 0x0946, 0x096F, 0x0998, 0x09C1, 0x09EB, 0x0A16, 0x0A40, 0x0A6C,
+ 0x0A98, 0x0AC4, 0x0AF1, 0x0B1E, 0x0B4C, 0x0B7A, 0x0BA9, 0x0BD8,
+ 0x0C07, 0x0C38, 0x0C68, 0x0C99, 0x0CCB, 0x0CFD, 0x0D30, 0x0D63,
+ 0x0D97, 0x0DCB, 0x0E00, 0x0E35, 0x0E6B, 0x0EA1, 0x0ED7, 0x0F0F,
+ 0x0F46, 0x0F7F, 0x0FB7, 0x0FF1, 0x102A, 0x1065, 0x109F, 0x10DB,
+ 0x1116, 0x1153, 0x118F, 0x11CD, 0x120B, 0x1249, 0x1288, 0x12C7,
+ 0x1307, 0x1347, 0x1388, 0x13C9, 0x140B, 0x144D, 0x1490, 0x14D4,
+ 0x1517, 0x155C, 0x15A0, 0x15E6, 0x162C, 0x1672, 0x16B9, 0x1700,
+ 0x1747, 0x1790, 0x17D8, 0x1821, 0x186B, 0x18B5, 0x1900, 0x194B,
+ 0x1996, 0x19E2, 0x1A2E, 0x1A7B, 0x1AC8, 0x1B16, 0x1B64, 0x1BB3,
+ 0x1C02, 0x1C51, 0x1CA1, 0x1CF1, 0x1D42, 0x1D93, 0x1DE5, 0x1E37,
+ 0x1E89, 0x1EDC, 0x1F2F, 0x1F82, 0x1FD6, 0x202A, 0x207F, 0x20D4,
+ 0x2129, 0x217F, 0x21D5, 0x222C, 0x2282, 0x22DA, 0x2331, 0x2389,
+ 0x23E1, 0x2439, 0x2492, 0x24EB, 0x2545, 0x259E, 0x25F8, 0x2653,
+ 0x26AD, 0x2708, 0x2763, 0x27BE, 0x281A, 0x2876, 0x28D2, 0x292E,
+ 0x298B, 0x29E7, 0x2A44, 0x2AA1, 0x2AFF, 0x2B5C, 0x2BBA, 0x2C18,
+ 0x2C76, 0x2CD4, 0x2D33, 0x2D91, 0x2DF0, 0x2E4F, 0x2EAE, 0x2F0D,
+ 0x2F6C, 0x2FCC, 0x302B, 0x308B, 0x30EA, 0x314A, 0x31AA, 0x3209,
+ 0x3269, 0x32C9, 0x3329, 0x3389, 0x33E9, 0x3449, 0x34A9, 0x3509,
+ 0x3569, 0x35C9, 0x3629, 0x3689, 0x36E8, 0x3748, 0x37A8, 0x3807,
+ 0x3867, 0x38C6, 0x3926, 0x3985, 0x39E4, 0x3A43, 0x3AA2, 0x3B00,
+ 0x3B5F, 0x3BBD, 0x3C1B, 0x3C79, 0x3CD7, 0x3D35, 0x3D92, 0x3DEF,
+ 0x3E4C, 0x3EA9, 0x3F05, 0x3F62, 0x3FBD, 0x4019, 0x4074, 0x40D0,
+ 0x412A, 0x4185, 0x41DF, 0x4239, 0x4292, 0x42EB, 0x4344, 0x439C,
+ 0x43F4, 0x444C, 0x44A3, 0x44FA, 0x4550, 0x45A6, 0x45FC, 0x4651,
+ 0x46A6, 0x46FA, 0x474E, 0x47A1, 0x47F4, 0x4846, 0x4898, 0x48E9,
+ 0x493A, 0x498A, 0x49D9, 0x4A29, 0x4A77, 0x4AC5, 0x4B13, 0x4B5F,
+ 0x4BAC, 0x4BF7, 0x4C42, 0x4C8D, 0x4CD7, 0x4D20, 0x4D68, 0x4DB0,
+ 0x4DF7, 0x4E3E, 0x4E84, 0x4EC9, 0x4F0E, 0x4F52, 0x4F95, 0x4FD7,
+ 0x5019, 0x505A, 0x509A, 0x50DA, 0x5118, 0x5156, 0x5194, 0x51D0,
+ 0x520C, 0x5247, 0x5281, 0x52BA, 0x52F3, 0x532A, 0x5361, 0x5397,
+ 0x53CC, 0x5401, 0x5434, 0x5467, 0x5499, 0x54CA, 0x54FA, 0x5529,
+ 0x5558, 0x5585, 0x55B2, 0x55DE, 0x5609, 0x5632, 0x565B, 0x5684,
+ 0x56AB, 0x56D1, 0x56F6, 0x571B, 0x573E, 0x5761, 0x5782, 0x57A3,
+ 0x57C3, 0x57E2, 0x57FF, 0x581C, 0x5838, 0x5853, 0x586D, 0x5886,
+ 0x589E, 0x58B5, 0x58CB, 0x58E0, 0x58F4, 0x5907, 0x5919, 0x592A,
+ 0x593A, 0x5949, 0x5958, 0x5965, 0x5971, 0x597C, 0x5986, 0x598F,
+ 0x5997, 0x599E, 0x59A4, 0x59A9, 0x59AD, 0x59B0, 0x59B2, 0x59B3
+};
+
+psx_spu_t* psx_spu_create(void) {+ return (psx_spu_t*)malloc(sizeof(psx_spu_t));
+}
+
+void psx_spu_init(psx_spu_t* spu, psx_ic_t* ic) {+ memset(spu, 0, sizeof(psx_spu_t));
+
+ spu->io_base = PSX_SPU_BEGIN;
+ spu->io_size = PSX_SPU_SIZE;
+
+ spu->ic = ic;
+ spu->ram = (uint8_t*)malloc(SPU_RAM_SIZE);
+
+ memset(spu->ram, 0, SPU_RAM_SIZE);
+
+ // Mute all voices
+ spu->endx = 0x00ffffff;
+ spu->irq9addr = 0xffff;
+}
+
+uint32_t psx_spu_read32(psx_spu_t* spu, uint32_t offset) {+ const uint8_t* ptr = (uint8_t*)&spu->voice[0].volumel;
+
+ return *((uint32_t*)(ptr + offset));
+}
+
+uint16_t psx_spu_read16(psx_spu_t* spu, uint32_t offset) {+ if (offset == SPUR_TFIFO) {+ uint16_t data = *(uint16_t*)(&spu->ram[spu->taddr]);
+
+ spu->taddr += 2;
+
+ return data;
+ }
+
+ const uint8_t* ptr = (uint8_t*)&spu->voice[0].volumel;
+
+ return *((uint16_t*)(ptr + offset));
+}
+
uint8_t psx_spu_read8(psx_spu_t* spu, uint32_t offset) {USED(spu);
log_fatal("Unhandled 8-bit SPU read at offset %08x", offset);-
- return 0x0;
-}
-
-void spu_read_block(psx_spu_t* spu, int v) {
- uint32_t addr = spu->data[v].current_addr;
- uint8_t hdr = spu->ram[addr];
-
- spu->data[v].block_flags = spu->ram[addr + 1];
-
- unsigned hdr_shift = hdr & 0x0f;
-
- if (hdr_shift > 12)
- hdr_shift = 9;
-
- unsigned shift = 12 - hdr_shift;
- unsigned filter = (hdr >> 4) & 7;
-
- int32_t f0 = g_spu_pos_adpcm_table[filter];
- int32_t f1 = g_spu_neg_adpcm_table[filter];
-
- for (int j = 0; j < 28; j++) {
- uint16_t n = (spu->ram[addr + 2 + (j >> 1)] >> ((j & 1) * 4)) & 0xf;
-
- // Sign extend t
+
+ return 0x0;
+}
+
+void spu_read_block(psx_spu_t* spu, int v) {+ uint32_t addr = spu->data[v].current_addr;
+ uint8_t hdr = spu->ram[addr];
+
+ spu->data[v].block_flags = spu->ram[addr + 1];
+
+ unsigned hdr_shift = hdr & 0x0f;
+
+ if (hdr_shift > 12)
+ hdr_shift = 9;
+
+ unsigned shift = 12 - hdr_shift;
+ unsigned filter = (hdr >> 4) & 7;
+
+ int32_t f0 = g_spu_pos_adpcm_table[filter];
+ int32_t f1 = g_spu_neg_adpcm_table[filter];
+
+ for (int j = 0; j < 28; j++) {+ uint16_t n = (spu->ram[addr + 2 + (j >> 1)] >> ((j & 1) * 4)) & 0xf;
+
+ // Sign extend t
int16_t t = (int16_t)(n << 12) >> 12;
int32_t s = (t << shift) + (((spu->data[v].h[0] * f0) + (spu->data[v].h[1] * f1) + 32) / 64);
-
- s = (s < INT16_MIN) ? INT16_MIN : ((s > INT16_MAX) ? INT16_MAX : s);
-
+
+ s = (s < INT16_MIN) ? INT16_MIN : ((s > INT16_MAX) ? INT16_MAX : s);
+
spu->data[v].h[1] = spu->data[v].h[0];
spu->data[v].h[0] = (int16_t)s;
spu->data[v].buf[j] = (int16_t)s;
- }
-}
-
-#define PHASE spu->data[v].adsr_phase
-#define CYCLES spu->data[v].adsr_cycles
-#define EXPONENTIAL spu->data[v].adsr_mode
-#define DECREASE spu->data[v].adsr_dir
-#define SHIFT spu->data[v].adsr_shift
-#define STEP spu->data[v].adsr_step
-#define LEVEL_STEP spu->data[v].adsr_pending_step
-#define LEVEL spu->data[v].cvol
-
-/*
- ____lower 16bit (at 1F801C08h+N*10h)___________________________________
- 15 Attack Mode (0=Linear, 1=Exponential)
- - Attack Direction (Fixed, always Increase) (until Level 7FFFh)
- 14-10 Attack Shift (0..1Fh = Fast..Slow)
- 9-8 Attack Step (0..3 = "+7,+6,+5,+4")
- - Decay Mode (Fixed, always Exponential)
- - Decay Direction (Fixed, always Decrease) (until Sustain Level)
- 7-4 Decay Shift (0..0Fh = Fast..Slow)
- - Decay Step (Fixed, always "-8")
- 3-0 Sustain Level (0..0Fh) ;Level=(N+1)*800h
- ____upper 16bit (at 1F801C0Ah+N*10h)___________________________________
- 31 Sustain Mode (0=Linear, 1=Exponential)
- 30 Sustain Direction (0=Increase, 1=Decrease) (until Key OFF flag)
- 29 Not used? (should be zero)
- 28-24 Sustain Shift (0..1Fh = Fast..Slow)
- 23-22 Sustain Step (0..3 = "+7,+6,+5,+4" or "-8,-7,-6,-5") (inc/dec)
- 21 Release Mode (0=Linear, 1=Exponential)
- - Release Direction (Fixed, always Decrease) (until Level 0000h)
- 20-16 Release Shift (0..1Fh = Fast..Slow)
- - Release Step (Fixed, always "-8")
-*/
-
-enum {
- ADSR_ATTACK,
- ADSR_DECAY,
- ADSR_SUSTAIN,
- ADSR_RELEASE,
- ADSR_END
-};
-
-void adsr_calculate_values(psx_spu_t* spu, int v) {
- CYCLES = 1 << MAX(0, SHIFT - 11);
- LEVEL_STEP = STEP << MAX(0, 11 - SHIFT);
-
- if (EXPONENTIAL && (LEVEL > 0x6000) && !DECREASE)
- CYCLES *= 4;
-
- if (EXPONENTIAL && DECREASE)
- LEVEL_STEP = (LEVEL_STEP * LEVEL) >> 15;
-
- spu->data[v].adsr_cycles_reload = CYCLES;
-}
-
-void adsr_load_attack(psx_spu_t* spu, int v) {
- EXPONENTIAL = spu->data[v].envctl >> 15;
- DECREASE = 0;
- SHIFT = (spu->data[v].envctl >> 10) & 0x1f;
- STEP = 7 - ((spu->data[v].envctl >> 8) & 3);
- LEVEL = 0;
- PHASE = ADSR_ATTACK;
-
- adsr_calculate_values(spu, v);
-}
-
-void adsr_load_decay(psx_spu_t* spu, int v) {
- EXPONENTIAL = 1;
- DECREASE = 1;
- SHIFT = (spu->data[v].envctl >> 4) & 0xf;
- STEP = -8;
- LEVEL = 0x7fff;
- PHASE = ADSR_DECAY;
-
- adsr_calculate_values(spu, v);
-}
-
-void adsr_load_sustain(psx_spu_t* spu, int v) {
- EXPONENTIAL = spu->data[v].envctl >> 31;
- DECREASE = (spu->data[v].envctl >> 30) & 1;
- SHIFT = (spu->data[v].envctl >> 24) & 0x1f;
- STEP = (spu->data[v].envctl >> 22) & 3;
- LEVEL = spu->data[v].adsr_sustain_level;
- STEP = DECREASE ? (-8 + STEP) : (7 - STEP);
- PHASE = ADSR_SUSTAIN;
-
- adsr_calculate_values(spu, v);
-}
-
-void adsr_load_release(psx_spu_t* spu, int v) {
- EXPONENTIAL = (spu->data[v].envctl >> 21) & 1;
- DECREASE = 1;
- SHIFT = (spu->data[v].envctl >> 16) & 0x1f;
- STEP = -8;
- PHASE = ADSR_RELEASE;
-
- spu->endx |= 1 << v;
-
- adsr_calculate_values(spu, v);
-}
-
-void spu_handle_adsr(psx_spu_t* spu, int v) {
- if (CYCLES) {
- CYCLES -= 1;
-
- return;
- }
-
- adsr_calculate_values(spu, v);
-
- LEVEL += LEVEL_STEP;
-
- switch (spu->data[v].adsr_phase) {
- case ADSR_ATTACK: {
- LEVEL = CLAMP(LEVEL, 0x0000, 0x7fff);
-
- if (LEVEL == 0x7fff)
- adsr_load_decay(spu, v);
- } break;
-
- case ADSR_DECAY: {
- LEVEL = CLAMP(LEVEL, 0x0000, 0x7fff);
-
- if (LEVEL <= spu->data[v].adsr_sustain_level)
- adsr_load_sustain(spu, v);
- } break;
-
- case ADSR_SUSTAIN: {
- LEVEL = CLAMP(LEVEL, 0x0000, 0x7fff);
-
- /* Not stopped automatically, need to KOFF */
- } break;
-
- case ADSR_RELEASE: {
- LEVEL = CLAMP(LEVEL, 0x0000, 0x7fff);
-
- if (!LEVEL) {
- PHASE = ADSR_END;
- CYCLES = 0;
- LEVEL_STEP = 0;
-
- spu->data[v].playing = 0;
- }
- } break;
-
- case ADSR_END: {
- spu->data[v].playing = 0;
- } break;
- }
-
- spu->voice[v].envcvol = spu->data[v].cvol;
-
- CYCLES = spu->data[v].adsr_cycles_reload;
-}
-
-#undef PHASE
-#undef CYCLES
-#undef MODE
-#undef DIR
-#undef SHIFT
-#undef STEP
-#undef PENDING_STEP
-
-void spu_kon(psx_spu_t* spu, uint32_t value) {
- for (int i = 0; i < VOICE_COUNT; i++) {
- if ((value & (1 << i))) {
- spu->data[i].playing = 1;
- spu->data[i].current_addr = spu->voice[i].adsaddr << 3;
- spu->data[i].repeat_addr = spu->voice[i].adraddr << 3;
- spu->data[i].lvol = ((float)(spu->voice[i].volumel) / 32767.0f) * 2.0f;
- spu->data[i].rvol = ((float)(spu->voice[i].volumer) / 32767.0f) * 2.0f;
- spu->data[i].adsr_sustain_level = ((spu->voice[i].envctl1 & 0xf) + 1) * 0x800;
- spu->data[i].envctl = (((uint32_t)spu->voice[i].envctl2) << 16) |
- (uint32_t)spu->voice[i].envctl1;
-
- adsr_load_attack(spu, i);
- spu_read_block(spu, i);
-
- spu->voice[i].envcvol = 0x7fff;
- }
- }
-
- spu->endx &= ~(value & 0x00ffffff);
-}
-
-void spu_koff(psx_spu_t* spu, uint32_t value) {
- for (int i = 0; i < VOICE_COUNT; i++)
- if (value & (1 << i))
- adsr_load_release(spu, i);
-}
-
-int spu_handle_write(psx_spu_t* spu, uint32_t offset, uint32_t value) {
- switch (offset) {
- case SPUR_KONL: case SPUR_KONH: {
- int high = (offset & 2) != 0;
-
- if (!value)
- return 1;
-
- spu_kon(spu, value << (16 * high));
- } return 1;
-
- // case SPUR_SPUIRQA: {
- // spu->irq9addr = value << 3;
- // } return 1;
-
- case SPUR_KOFFL: case SPUR_KOFFH: {
- int high = (offset & 2) != 0;
-
- if (!value)
- return 1;
-
- spu_koff(spu, value << (16 * high));
- } return 1;
-
- case SPUR_TADDR: {
- spu->ramdta = value;
- spu->taddr = value << 3;
- } return 1;
-
- case SPUR_TFIFO: {
- spu->ramdtf = value;
- spu->tfifo[spu->tfifo_index++] = value;
-
- if (spu->tfifo_index == 32) {
- if (((spu->spucnt >> 4) & 3) == 2) {
- for (int i = 0; i < spu->tfifo_index; i++) {
- spu->ram[spu->taddr++] = spu->tfifo[i] & 0xff;
- spu->ram[spu->taddr++] = spu->tfifo[i] >> 8;
- }
-
- spu->tfifo_index = 0;
- }
- }
- } return 1;
-
- case SPUR_SPUCNT: {
- spu->spucnt = value;
- spu->spustat &= 0xffc0;
- spu->spustat |= value & 0x3f;
-
- if ((value >> 4) & 3) {
- for (int i = 0; i < spu->tfifo_index; i++) {
- spu->ram[spu->taddr++] = spu->tfifo[i] & 0xff;
- spu->ram[spu->taddr++] = spu->tfifo[i] >> 8;
- }
-
- spu->tfifo_index = 0;
- }
- } return 1;
-
- case SPUR_MBASE: {
- spu->mbase = value;
- spu->revbaddr = spu->mbase << 3;
- } return 1;
- }
-
- return 0;
-}
-
-void psx_spu_write32(psx_spu_t* spu, uint32_t offset, uint32_t value) {
- // Handle special cases first
- if (spu_handle_write(spu, offset, value))
- return;
-
- const uint8_t* ptr = (uint8_t*)&spu->voice[0];
-
- *((uint32_t*)(ptr + offset)) = value;
-}
-
-void psx_spu_write16(psx_spu_t* spu, uint32_t offset, uint16_t value) {
- // Handle special cases first
- if (spu_handle_write(spu, offset, value))
- return;
-
- const uint8_t* ptr = (uint8_t*)&spu->voice[0].volumel;
-
- if (offset != 0x0c)
- *((uint16_t*)(ptr + offset)) = value;
-}
-
+ }
+}
+
+#define PHASE spu->data[v].adsr_phase
+#define CYCLES spu->data[v].adsr_cycles
+#define EXPONENTIAL spu->data[v].adsr_mode
+#define DECREASE spu->data[v].adsr_dir
+#define SHIFT spu->data[v].adsr_shift
+#define STEP spu->data[v].adsr_step
+#define LEVEL_STEP spu->data[v].adsr_pending_step
+#define LEVEL spu->data[v].cvol
+
+/*
+ ____lower 16bit (at 1F801C08h+N*10h)___________________________________
+ 15 Attack Mode (0=Linear, 1=Exponential)
+ - Attack Direction (Fixed, always Increase) (until Level 7FFFh)
+ 14-10 Attack Shift (0..1Fh = Fast..Slow)
+ 9-8 Attack Step (0..3 = "+7,+6,+5,+4")
+ - Decay Mode (Fixed, always Exponential)
+ - Decay Direction (Fixed, always Decrease) (until Sustain Level)
+ 7-4 Decay Shift (0..0Fh = Fast..Slow)
+ - Decay Step (Fixed, always "-8")
+ 3-0 Sustain Level (0..0Fh) ;Level=(N+1)*800h
+ ____upper 16bit (at 1F801C0Ah+N*10h)___________________________________
+ 31 Sustain Mode (0=Linear, 1=Exponential)
+ 30 Sustain Direction (0=Increase, 1=Decrease) (until Key OFF flag)
+ 29 Not used? (should be zero)
+ 28-24 Sustain Shift (0..1Fh = Fast..Slow)
+ 23-22 Sustain Step (0..3 = "+7,+6,+5,+4" or "-8,-7,-6,-5") (inc/dec)
+ 21 Release Mode (0=Linear, 1=Exponential)
+ - Release Direction (Fixed, always Decrease) (until Level 0000h)
+ 20-16 Release Shift (0..1Fh = Fast..Slow)
+ - Release Step (Fixed, always "-8")
+*/
+
+enum {+ ADSR_ATTACK,
+ ADSR_DECAY,
+ ADSR_SUSTAIN,
+ ADSR_RELEASE,
+ ADSR_END
+};
+
+void adsr_calculate_values(psx_spu_t* spu, int v) {+ CYCLES = 1 << MAX(0, SHIFT - 11);
+ LEVEL_STEP = STEP << MAX(0, 11 - SHIFT);
+
+ if (EXPONENTIAL && (LEVEL > 0x6000) && !DECREASE)
+ CYCLES *= 4;
+
+ if (EXPONENTIAL && DECREASE)
+ LEVEL_STEP = (LEVEL_STEP * LEVEL) >> 15;
+
+ spu->data[v].adsr_cycles_reload = CYCLES;
+}
+
+void adsr_load_attack(psx_spu_t* spu, int v) {+ EXPONENTIAL = spu->data[v].envctl >> 15;
+ DECREASE = 0;
+ SHIFT = (spu->data[v].envctl >> 10) & 0x1f;
+ STEP = 7 - ((spu->data[v].envctl >> 8) & 3);
+ LEVEL = 0;
+ PHASE = ADSR_ATTACK;
+
+ adsr_calculate_values(spu, v);
+}
+
+void adsr_load_decay(psx_spu_t* spu, int v) {+ EXPONENTIAL = 1;
+ DECREASE = 1;
+ SHIFT = (spu->data[v].envctl >> 4) & 0xf;
+ STEP = -8;
+ LEVEL = 0x7fff;
+ PHASE = ADSR_DECAY;
+
+ adsr_calculate_values(spu, v);
+}
+
+void adsr_load_sustain(psx_spu_t* spu, int v) {+ EXPONENTIAL = spu->data[v].envctl >> 31;
+ DECREASE = (spu->data[v].envctl >> 30) & 1;
+ SHIFT = (spu->data[v].envctl >> 24) & 0x1f;
+ STEP = (spu->data[v].envctl >> 22) & 3;
+ LEVEL = spu->data[v].adsr_sustain_level;
+ STEP = DECREASE ? (-8 + STEP) : (7 - STEP);
+ PHASE = ADSR_SUSTAIN;
+
+ adsr_calculate_values(spu, v);
+}
+
+void adsr_load_release(psx_spu_t* spu, int v) {+ EXPONENTIAL = (spu->data[v].envctl >> 21) & 1;
+ DECREASE = 1;
+ SHIFT = (spu->data[v].envctl >> 16) & 0x1f;
+ STEP = -8;
+ PHASE = ADSR_RELEASE;
+
+ spu->endx |= 1 << v;
+
+ adsr_calculate_values(spu, v);
+}
+
+void spu_handle_adsr(psx_spu_t* spu, int v) {+ if (CYCLES) {+ CYCLES -= 1;
+
+ return;
+ }
+
+ adsr_calculate_values(spu, v);
+
+ LEVEL += LEVEL_STEP;
+
+ switch (spu->data[v].adsr_phase) {+ case ADSR_ATTACK: {+ LEVEL = CLAMP(LEVEL, 0x0000, 0x7fff);
+
+ if (LEVEL == 0x7fff)
+ adsr_load_decay(spu, v);
+ } break;
+
+ case ADSR_DECAY: {+ LEVEL = CLAMP(LEVEL, 0x0000, 0x7fff);
+
+ if (LEVEL <= spu->data[v].adsr_sustain_level)
+ adsr_load_sustain(spu, v);
+ } break;
+
+ case ADSR_SUSTAIN: {+ LEVEL = CLAMP(LEVEL, 0x0000, 0x7fff);
+
+ /* Not stopped automatically, need to KOFF */
+ } break;
+
+ case ADSR_RELEASE: {+ LEVEL = CLAMP(LEVEL, 0x0000, 0x7fff);
+
+ if (!LEVEL) {+ PHASE = ADSR_END;
+ CYCLES = 0;
+ LEVEL_STEP = 0;
+
+ spu->data[v].playing = 0;
+ }
+ } break;
+
+ case ADSR_END: {+ spu->data[v].playing = 0;
+ } break;
+ }
+
+ spu->voice[v].envcvol = spu->data[v].cvol;
+
+ CYCLES = spu->data[v].adsr_cycles_reload;
+}
+
+#undef PHASE
+#undef CYCLES
+#undef MODE
+#undef DIR
+#undef SHIFT
+#undef STEP
+#undef PENDING_STEP
+
+void spu_kon(psx_spu_t* spu, uint32_t value) {+ for (int i = 0; i < VOICE_COUNT; i++) {+ if ((value & (1 << i))) {+ spu->data[i].playing = 1;
+ spu->data[i].current_addr = spu->voice[i].adsaddr << 3;
+ spu->data[i].repeat_addr = spu->voice[i].adraddr << 3;
+ spu->data[i].lvol = ((float)(spu->voice[i].volumel) / 32767.0f) * 2.0f;
+ spu->data[i].rvol = ((float)(spu->voice[i].volumer) / 32767.0f) * 2.0f;
+ spu->data[i].adsr_sustain_level = ((spu->voice[i].envctl1 & 0xf) + 1) * 0x800;
+ spu->data[i].envctl = (((uint32_t)spu->voice[i].envctl2) << 16) |
+ (uint32_t)spu->voice[i].envctl1;
+
+ adsr_load_attack(spu, i);
+ spu_read_block(spu, i);
+
+ spu->voice[i].envcvol = 0x7fff;
+ }
+ }
+
+ spu->endx &= ~(value & 0x00ffffff);
+}
+
+void spu_koff(psx_spu_t* spu, uint32_t value) {+ for (int i = 0; i < VOICE_COUNT; i++)
+ if (value & (1 << i))
+ adsr_load_release(spu, i);
+}
+
+int spu_handle_write(psx_spu_t* spu, uint32_t offset, uint32_t value) {+ switch (offset) {+ case SPUR_KONL: case SPUR_KONH: {+ int high = (offset & 2) != 0;
+
+ if (!value)
+ return 1;
+
+ spu_kon(spu, value << (16 * high));
+ } return 1;
+
+ // case SPUR_SPUIRQA: {+ // spu->irq9addr = value << 3;
+ // } return 1;
+
+ case SPUR_KOFFL: case SPUR_KOFFH: {+ int high = (offset & 2) != 0;
+
+ if (!value)
+ return 1;
+
+ spu_koff(spu, value << (16 * high));
+ } return 1;
+
+ case SPUR_TADDR: {+ spu->ramdta = value;
+ spu->taddr = value << 3;
+ } return 1;
+
+ case SPUR_TFIFO: {+ spu->ramdtf = value;
+ spu->tfifo[spu->tfifo_index++] = value;
+
+ if (spu->tfifo_index == 32) {+ if (((spu->spucnt >> 4) & 3) == 2) {+ for (int i = 0; i < spu->tfifo_index; i++) {+ spu->ram[spu->taddr++] = spu->tfifo[i] & 0xff;
+ spu->ram[spu->taddr++] = spu->tfifo[i] >> 8;
+ }
+
+ spu->tfifo_index = 0;
+ }
+ }
+ } return 1;
+
+ case SPUR_SPUCNT: {+ spu->spucnt = value;
+ spu->spustat &= 0xffc0;
+ spu->spustat |= value & 0x3f;
+
+ if ((value >> 4) & 3) {+ for (int i = 0; i < spu->tfifo_index; i++) {+ spu->ram[spu->taddr++] = spu->tfifo[i] & 0xff;
+ spu->ram[spu->taddr++] = spu->tfifo[i] >> 8;
+ }
+
+ spu->tfifo_index = 0;
+ }
+ } return 1;
+
+ case SPUR_MBASE: {+ spu->mbase = value;
+ spu->revbaddr = spu->mbase << 3;
+ } return 1;
+ }
+
+ return 0;
+}
+
+void psx_spu_write32(psx_spu_t* spu, uint32_t offset, uint32_t value) {+ // Handle special cases first
+ if (spu_handle_write(spu, offset, value))
+ return;
+
+ const uint8_t* ptr = (uint8_t*)&spu->voice[0];
+
+ *((uint32_t*)(ptr + offset)) = value;
+}
+
+void psx_spu_write16(psx_spu_t* spu, uint32_t offset, uint16_t value) {+ // Handle special cases first
+ if (spu_handle_write(spu, offset, value))
+ return;
+
+ const uint8_t* ptr = (uint8_t*)&spu->voice[0].volumel;
+
+ if (offset != 0x0c)
+ *((uint16_t*)(ptr + offset)) = value;
+}
+
void psx_spu_write8(psx_spu_t* spu, uint32_t offset, uint8_t value) {USED(spu);
printf("Unhandled 8-bit SPU write at offset %08x (%02x)\n", offset, value);}
-
-void psx_spu_destroy(psx_spu_t* spu) {
- free(spu->ram);
- free(spu);
-}
-
-// To-do: Optimize reverb
-
-int16_t spu_read_reverb(psx_spu_t* spu, uint32_t addr) {
- uint32_t mbase = spu->mbase << 3;
-
- uint32_t relative = (addr + spu->revbaddr - mbase) % (0x80000 - mbase);
- uint32_t wrapped = (mbase + relative) & 0x7fffe;
-
- return *(int16_t*)(spu->ram + wrapped);
-}
-
-void spu_write_reverb(psx_spu_t* spu, uint32_t addr, int16_t value) {
- uint32_t mbase = spu->mbase << 3;
-
- uint32_t relative = (addr + spu->revbaddr - mbase) % (0x80000 - mbase);
- uint32_t wrapped = (mbase + relative) & 0x7fffe;
-
- *(int16_t*)(spu->ram + wrapped) = value;
-}
-
-#define R16(addr) (spu_read_reverb(spu, addr))
-#define W16(addr, value) spu_write_reverb(spu, addr, value)
-
-#define SAT(v) CLAMP(v, INT16_MIN, INT16_MAX)
-
-void spu_get_reverb_sample(psx_spu_t* spu, int inl, int inr, int* outl, int* outr) {
- uint32_t mbase = spu->mbase << 3;
- uint32_t dapf1 = spu->dapf1 << 3;
- uint32_t dapf2 = spu->dapf2 << 3;
- uint32_t mlsame = spu->mlsame << 3;
- uint32_t mrsame = spu->mrsame << 3;
- uint32_t dlsame = spu->dlsame << 3;
- uint32_t drsame = spu->drsame << 3;
- uint32_t mldiff = spu->mldiff << 3;
- uint32_t mrdiff = spu->mrdiff << 3;
- uint32_t dldiff = spu->dldiff << 3;
- uint32_t drdiff = spu->drdiff << 3;
- uint32_t mlcomb1 = spu->mlcomb1 << 3;
- uint32_t mlcomb2 = spu->mlcomb2 << 3;
- uint32_t mlcomb3 = spu->mlcomb3 << 3;
- uint32_t mlcomb4 = spu->mlcomb4 << 3;
- uint32_t mrcomb1 = spu->mrcomb1 << 3;
- uint32_t mrcomb2 = spu->mrcomb2 << 3;
- uint32_t mrcomb3 = spu->mrcomb3 << 3;
- uint32_t mrcomb4 = spu->mrcomb4 << 3;
- uint32_t mlapf1 = spu->mlapf1 << 3;
- uint32_t mlapf2 = spu->mlapf2 << 3;
- uint32_t mrapf1 = spu->mrapf1 << 3;
- uint32_t mrapf2 = spu->mrapf2 << 3;
-
- float vlin = (float)spu->vlin;
- float vrin = (float)spu->vrin;
- float viir = (float)spu->viir;
- float vwall = (float)spu->vwall;
- float vcomb1 = (float)spu->vcomb1;
- float vcomb2 = (float)spu->vcomb2;
- float vcomb3 = (float)spu->vcomb3;
- float vcomb4 = (float)spu->vcomb4;
- float vapf1 = (float)spu->vapf1;
- float vapf2 = (float)spu->vapf2;
- float vlout = (float)spu->vlout;
- float vrout = (float)spu->vrout;
-
- int lin = (vlin * inl) / 32768.0f;
- int rin = (vrin * inr) / 32768.0f;
-
- // same side reflection ltol and rtor
- int16_t mlsamev = SAT(lin + ((R16(dlsame) * vwall) / 32768.0f) - ((R16(mlsame - 2) * viir) / 32768.0f) + R16(mlsame - 2));
- int16_t mrsamev = SAT(rin + ((R16(drsame) * vwall) / 32768.0f) - ((R16(mrsame - 2) * viir) / 32768.0f) + R16(mrsame - 2));
- W16(mlsame, mlsamev);
- W16(mrsame, mrsamev);
-
- // different side reflection ltor and rtol
- int16_t mldiffv = SAT(lin + ((R16(drdiff) * vwall) / 32768.0f) - ((R16(mldiff - 2) * viir) / 32768.0f) + R16(mldiff - 2));
- int16_t mrdiffv = SAT(rin + ((R16(dldiff) * vwall) / 32768.0f) - ((R16(mrdiff - 2) * viir) / 32768.0f) + R16(mrdiff - 2));
- W16(mldiff, mldiffv);
- W16(mrdiff, mrdiffv);
-
- // early echo (comb filter with input from buffer)
- int16_t l = SAT((vcomb1 * R16(mlcomb1) / 32768.0f) + (vcomb2 * R16(mlcomb2) / 32768.0f) + (vcomb3 * R16(mlcomb3) / 32768.0f) + (vcomb4 * R16(mlcomb4) / 32768.0f));
- int16_t r = SAT((vcomb1 * R16(mrcomb1) / 32768.0f) + (vcomb2 * R16(mrcomb2) / 32768.0f) + (vcomb3 * R16(mrcomb3) / 32768.0f) + (vcomb4 * R16(mrcomb4) / 32768.0f));
-
- // late reverb apf1 (all pass filter 1 with input from comb)
- l = SAT(l - SAT((vapf1 * R16(mlapf1 - dapf1)) / 32768.0f));
- r = SAT(r - SAT((vapf1 * R16(mrapf1 - dapf1)) / 32768.0f));
-
- W16(mlapf1, l);
- W16(mrapf1, r);
-
- l = SAT((l * vapf1 / 32768.0f) + R16(mlapf1 - dapf1));
- r = SAT((r * vapf1 / 32768.0f) + R16(mrapf1 - dapf1));
-
- // late reverb apf2 (all pass filter 2 with input from apf1)
- l = SAT(l - SAT((vapf2 * R16(mlapf2 - dapf2)) / 32768.0f));
- r = SAT(r - SAT((vapf2 * R16(mrapf2 - dapf2)) / 32768.0f));
-
- W16(mlapf2, l);
- W16(mrapf2, r);
-
- l = SAT((l * vapf2 / 32768.0f) + R16(mlapf2 - dapf2));
- r = SAT((r * vapf2 / 32768.0f) + R16(mrapf2 - dapf2));
-
- // output to mixer (output volume multiplied with input from apf2)
- *outl = SAT(l * vlout / 32768.0f);
- *outr = SAT(r * vrout / 32768.0f);
-
- spu->revbaddr = MAX(mbase, (spu->revbaddr + 2) & 0x7fffe);
-}
-
-#undef R16
-#undef W16
-
-uint32_t psx_spu_get_sample(psx_spu_t* spu) {
- spu->even_cycle ^= 1;
-
- int left = 0;
- int right = 0;
- int revl = 0;
- int revr = 0;
-
- spu->koff = 0;
- spu->kon = 0;
-
- for (int v = 0; v < VOICE_COUNT; v++) {
- if (!spu->data[v].playing)
- continue;
-
- spu_handle_adsr(spu, v);
-
- uint32_t sample_index = spu->data[v].counter >> 12;
-
- if (sample_index > 27) {
- sample_index -= 28;
-
- spu->data[v].counter &= 0xfff;
- spu->data[v].counter |= sample_index << 12;
-
- if (spu->data[v].block_flags & 4)
- spu->data[v].repeat_addr = spu->data[v].current_addr;
-
- switch (spu->data[v].block_flags & 3) {
- case 0: case 2: {
- if (((spu->irq9addr << 3) == spu->data[v].current_addr) && (spu->spucnt & 0x40)) {
- psx_ic_irq(spu->ic, IC_SPU);
- }
-
- spu->data[v].current_addr += 0x10;
-
- if (((spu->irq9addr << 3) == spu->data[v].current_addr) && (spu->spucnt & 0x40)) {
- psx_ic_irq(spu->ic, IC_SPU);
- }
- } break;
-
- case 1: {
- spu->data[v].current_addr = spu->data[v].repeat_addr;
- spu->data[v].playing = 0;
- spu->voice[v].envcvol = 0;
-
- adsr_load_release(spu, v);
- } break;
-
- case 3: {
- spu->endx |= 1 << v;
- spu->data[v].current_addr = spu->data[v].repeat_addr;
- } break;
- }
-
- spu_read_block(spu, v);
- }
-
- // Fetch ADPCM sample
- if (spu->data[v].prev_sample_index != sample_index) {
- spu->data[v].s[3] = spu->data[v].s[2];
- spu->data[v].s[2] = spu->data[v].s[1];
- spu->data[v].s[1] = spu->data[v].s[0];
- }
-
- spu->data[v].s[0] = spu->data[v].buf[sample_index];
-
- // Apply 4-point Gaussian interpolation
- uint8_t gauss_index = (spu->data[v].counter >> 4) & 0xff;
- int16_t g0 = g_spu_gauss_table[0x0ff - gauss_index];
- int16_t g1 = g_spu_gauss_table[0x1ff - gauss_index];
- int16_t g2 = g_spu_gauss_table[0x100 + gauss_index];
- int16_t g3 = g_spu_gauss_table[0x000 + gauss_index];
- int16_t out;
-
- // out = interpolate_hermite(
- // spu->data[v].s[3],
- // spu->data[v].s[2],
- // spu->data[v].s[1],
- // spu->data[v].s[0],
- // (spu->data[v].counter & 0xfff) / 4096.0f
- // );
-
- out = (g0 * spu->data[v].s[3]) >> 15;
- out += (g1 * spu->data[v].s[2]) >> 15;
- out += (g2 * spu->data[v].s[1]) >> 15;
- out += (g3 * spu->data[v].s[0]) >> 15;
-
- float adsr_vol = (float)spu->voice[v].envcvol / 32767.0f;
-
- float samplel = (out * spu->data[v].lvol) * adsr_vol;
- float sampler = (out * spu->data[v].rvol) * adsr_vol;
-
- left += samplel;
- right += sampler;
-
- if (spu->eon & (1 << v)) {
- revl += samplel;
- revr += sampler;
- }
-
- uint16_t step = spu->voice[v].adsampr;
-
- /* To-do: Do pitch modulation here */
-
- spu->data[v].prev_sample_index = spu->data[v].counter >> 12;
- spu->data[v].counter += step;
- }
-
- int16_t clamprl = CLAMP(revl, INT16_MIN, INT16_MAX);
- int16_t clamprr = CLAMP(revr, INT16_MIN, INT16_MAX);
- int16_t clampsl = CLAMP(left, INT16_MIN, INT16_MAX);
- int16_t clampsr = CLAMP(right, INT16_MIN, INT16_MAX);
-
- if ((spu->spucnt & 0x4000) == 0)
- return 0;
-
- uint16_t clampl;
- uint16_t clampr;
-
- if (spu->spucnt & 0x0080) {
- if (spu->even_cycle)
- spu_get_reverb_sample(spu, clamprl, clamprr, &spu->lrsl, &spu->lrsr);
-
- clampl = CLAMP((clampsl + spu->lrsl), INT16_MIN, INT16_MAX) * (float)spu->mainlvol / 32767.0f;
- clampr = CLAMP((clampsr + spu->lrsr), INT16_MIN, INT16_MAX) * (float)spu->mainrvol / 32767.0f;
- } else {
- clampl = CLAMP(clampsl, INT16_MIN, INT16_MAX) * (float)spu->mainlvol / 32767.0f;
- clampr = CLAMP(clampsr, INT16_MIN, INT16_MAX) * (float)spu->mainrvol / 32767.0f;
- }
-
- return clampl | (((uint32_t)clampr) << 16);
-}
-
-int counter = 0;
-
-void psx_spu_update_cdda_buffer(psx_spu_t* spu, void* buf) {
- int16_t* ptr = buf;
- int16_t* ram = (int16_t*)spu->ram;
-
- for (int i = 0; i < 0x400; i++) {
- ram[i + 0x000] = *ptr++;
- ram[i + 0x400] = *ptr++;
- }
-
- // Little bit of lowpass/smoothing
- for (int i = 0; i < 0x400; i += 8) {
- int l = 0, r = 0;
-
- for (int j = 0; j < 8; j++) {
- l += ram[i + j];
- r += ram[i + j + 0x400];
- }
-
- ram[i + 0x000] = l / 8;
- ram[i + 0x400] = r / 8;
- }
-
- // Simulate capture IRQ
- if (spu->ramdtc & 0xc) {
- if (spu->irq9addr <= 0x1ff) {
- if (!counter) {
- psx_ic_irq(spu->ic, IC_SPU);
- }
-
- counter++;
- counter &= 0x1;
- }
- }
-}
-
-#undef CLAMP
+
+void psx_spu_destroy(psx_spu_t* spu) {+ free(spu->ram);
+ free(spu);
+}
+
+// To-do: Optimize reverb
+
+int16_t spu_read_reverb(psx_spu_t* spu, uint32_t addr) {+ uint32_t mbase = spu->mbase << 3;
+
+ uint32_t relative = (addr + spu->revbaddr - mbase) % (0x80000 - mbase);
+ uint32_t wrapped = (mbase + relative) & 0x7fffe;
+
+ return *(int16_t*)(spu->ram + wrapped);
+}
+
+void spu_write_reverb(psx_spu_t* spu, uint32_t addr, int16_t value) {+ uint32_t mbase = spu->mbase << 3;
+
+ uint32_t relative = (addr + spu->revbaddr - mbase) % (0x80000 - mbase);
+ uint32_t wrapped = (mbase + relative) & 0x7fffe;
+
+ *(int16_t*)(spu->ram + wrapped) = value;
+}
+
+#define R16(addr) (spu_read_reverb(spu, addr))
+#define W16(addr, value) spu_write_reverb(spu, addr, value)
+
+#define SAT(v) CLAMP(v, INT16_MIN, INT16_MAX)
+
+void spu_get_reverb_sample(psx_spu_t* spu, int inl, int inr, int* outl, int* outr) {+ uint32_t mbase = spu->mbase << 3;
+ uint32_t dapf1 = spu->dapf1 << 3;
+ uint32_t dapf2 = spu->dapf2 << 3;
+ uint32_t mlsame = spu->mlsame << 3;
+ uint32_t mrsame = spu->mrsame << 3;
+ uint32_t dlsame = spu->dlsame << 3;
+ uint32_t drsame = spu->drsame << 3;
+ uint32_t mldiff = spu->mldiff << 3;
+ uint32_t mrdiff = spu->mrdiff << 3;
+ uint32_t dldiff = spu->dldiff << 3;
+ uint32_t drdiff = spu->drdiff << 3;
+ uint32_t mlcomb1 = spu->mlcomb1 << 3;
+ uint32_t mlcomb2 = spu->mlcomb2 << 3;
+ uint32_t mlcomb3 = spu->mlcomb3 << 3;
+ uint32_t mlcomb4 = spu->mlcomb4 << 3;
+ uint32_t mrcomb1 = spu->mrcomb1 << 3;
+ uint32_t mrcomb2 = spu->mrcomb2 << 3;
+ uint32_t mrcomb3 = spu->mrcomb3 << 3;
+ uint32_t mrcomb4 = spu->mrcomb4 << 3;
+ uint32_t mlapf1 = spu->mlapf1 << 3;
+ uint32_t mlapf2 = spu->mlapf2 << 3;
+ uint32_t mrapf1 = spu->mrapf1 << 3;
+ uint32_t mrapf2 = spu->mrapf2 << 3;
+
+ float vlin = (float)spu->vlin;
+ float vrin = (float)spu->vrin;
+ float viir = (float)spu->viir;
+ float vwall = (float)spu->vwall;
+ float vcomb1 = (float)spu->vcomb1;
+ float vcomb2 = (float)spu->vcomb2;
+ float vcomb3 = (float)spu->vcomb3;
+ float vcomb4 = (float)spu->vcomb4;
+ float vapf1 = (float)spu->vapf1;
+ float vapf2 = (float)spu->vapf2;
+ float vlout = (float)spu->vlout;
+ float vrout = (float)spu->vrout;
+
+ int lin = (vlin * inl) / 32768.0f;
+ int rin = (vrin * inr) / 32768.0f;
+
+ // same side reflection ltol and rtor
+ int16_t mlsamev = SAT(lin + ((R16(dlsame) * vwall) / 32768.0f) - ((R16(mlsame - 2) * viir) / 32768.0f) + R16(mlsame - 2));
+ int16_t mrsamev = SAT(rin + ((R16(drsame) * vwall) / 32768.0f) - ((R16(mrsame - 2) * viir) / 32768.0f) + R16(mrsame - 2));
+ W16(mlsame, mlsamev);
+ W16(mrsame, mrsamev);
+
+ // different side reflection ltor and rtol
+ int16_t mldiffv = SAT(lin + ((R16(drdiff) * vwall) / 32768.0f) - ((R16(mldiff - 2) * viir) / 32768.0f) + R16(mldiff - 2));
+ int16_t mrdiffv = SAT(rin + ((R16(dldiff) * vwall) / 32768.0f) - ((R16(mrdiff - 2) * viir) / 32768.0f) + R16(mrdiff - 2));
+ W16(mldiff, mldiffv);
+ W16(mrdiff, mrdiffv);
+
+ // early echo (comb filter with input from buffer)
+ int16_t l = SAT((vcomb1 * R16(mlcomb1) / 32768.0f) + (vcomb2 * R16(mlcomb2) / 32768.0f) + (vcomb3 * R16(mlcomb3) / 32768.0f) + (vcomb4 * R16(mlcomb4) / 32768.0f));
+ int16_t r = SAT((vcomb1 * R16(mrcomb1) / 32768.0f) + (vcomb2 * R16(mrcomb2) / 32768.0f) + (vcomb3 * R16(mrcomb3) / 32768.0f) + (vcomb4 * R16(mrcomb4) / 32768.0f));
+
+ // late reverb apf1 (all pass filter 1 with input from comb)
+ l = SAT(l - SAT((vapf1 * R16(mlapf1 - dapf1)) / 32768.0f));
+ r = SAT(r - SAT((vapf1 * R16(mrapf1 - dapf1)) / 32768.0f));
+
+ W16(mlapf1, l);
+ W16(mrapf1, r);
+
+ l = SAT((l * vapf1 / 32768.0f) + R16(mlapf1 - dapf1));
+ r = SAT((r * vapf1 / 32768.0f) + R16(mrapf1 - dapf1));
+
+ // late reverb apf2 (all pass filter 2 with input from apf1)
+ l = SAT(l - SAT((vapf2 * R16(mlapf2 - dapf2)) / 32768.0f));
+ r = SAT(r - SAT((vapf2 * R16(mrapf2 - dapf2)) / 32768.0f));
+
+ W16(mlapf2, l);
+ W16(mrapf2, r);
+
+ l = SAT((l * vapf2 / 32768.0f) + R16(mlapf2 - dapf2));
+ r = SAT((r * vapf2 / 32768.0f) + R16(mrapf2 - dapf2));
+
+ // output to mixer (output volume multiplied with input from apf2)
+ *outl = SAT(l * vlout / 32768.0f);
+ *outr = SAT(r * vrout / 32768.0f);
+
+ spu->revbaddr = MAX(mbase, (spu->revbaddr + 2) & 0x7fffe);
+}
+
+#undef R16
+#undef W16
+
+uint32_t psx_spu_get_sample(psx_spu_t* spu) {+ spu->even_cycle ^= 1;
+
+ int left = 0;
+ int right = 0;
+ int revl = 0;
+ int revr = 0;
+
+ spu->koff = 0;
+ spu->kon = 0;
+
+ for (int v = 0; v < VOICE_COUNT; v++) {+ if (!spu->data[v].playing)
+ continue;
+
+ spu_handle_adsr(spu, v);
+
+ uint32_t sample_index = spu->data[v].counter >> 12;
+
+ if (sample_index > 27) {+ sample_index -= 28;
+
+ spu->data[v].counter &= 0xfff;
+ spu->data[v].counter |= sample_index << 12;
+
+ if (spu->data[v].block_flags & 4)
+ spu->data[v].repeat_addr = spu->data[v].current_addr;
+
+ switch (spu->data[v].block_flags & 3) {+ case 0: case 2: {+ if (((spu->irq9addr << 3) == spu->data[v].current_addr) && (spu->spucnt & 0x40)) {+ psx_ic_irq(spu->ic, IC_SPU);
+ }
+
+ spu->data[v].current_addr += 0x10;
+
+ if (((spu->irq9addr << 3) == spu->data[v].current_addr) && (spu->spucnt & 0x40)) {+ psx_ic_irq(spu->ic, IC_SPU);
+ }
+ } break;
+
+ case 1: {+ spu->data[v].current_addr = spu->data[v].repeat_addr;
+ spu->data[v].playing = 0;
+ spu->voice[v].envcvol = 0;
+
+ adsr_load_release(spu, v);
+ } break;
+
+ case 3: {+ spu->endx |= 1 << v;
+ spu->data[v].current_addr = spu->data[v].repeat_addr;
+ } break;
+ }
+
+ spu_read_block(spu, v);
+ }
+
+ // Fetch ADPCM sample
+ if (spu->data[v].prev_sample_index != sample_index) {+ spu->data[v].s[3] = spu->data[v].s[2];
+ spu->data[v].s[2] = spu->data[v].s[1];
+ spu->data[v].s[1] = spu->data[v].s[0];
+ }
+
+ spu->data[v].s[0] = spu->data[v].buf[sample_index];
+
+ // Apply 4-point Gaussian interpolation
+ uint8_t gauss_index = (spu->data[v].counter >> 4) & 0xff;
+ int16_t g0 = g_spu_gauss_table[0x0ff - gauss_index];
+ int16_t g1 = g_spu_gauss_table[0x1ff - gauss_index];
+ int16_t g2 = g_spu_gauss_table[0x100 + gauss_index];
+ int16_t g3 = g_spu_gauss_table[0x000 + gauss_index];
+ int16_t out;
+
+ // out = interpolate_hermite(
+ // spu->data[v].s[3],
+ // spu->data[v].s[2],
+ // spu->data[v].s[1],
+ // spu->data[v].s[0],
+ // (spu->data[v].counter & 0xfff) / 4096.0f
+ // );
+
+ out = (g0 * spu->data[v].s[3]) >> 15;
+ out += (g1 * spu->data[v].s[2]) >> 15;
+ out += (g2 * spu->data[v].s[1]) >> 15;
+ out += (g3 * spu->data[v].s[0]) >> 15;
+
+ float adsr_vol = (float)spu->voice[v].envcvol / 32767.0f;
+
+ float samplel = (out * spu->data[v].lvol) * adsr_vol;
+ float sampler = (out * spu->data[v].rvol) * adsr_vol;
+
+ left += samplel;
+ right += sampler;
+
+ if (spu->eon & (1 << v)) {+ revl += samplel;
+ revr += sampler;
+ }
+
+ uint16_t step = spu->voice[v].adsampr;
+
+ /* To-do: Do pitch modulation here */
+
+ spu->data[v].prev_sample_index = spu->data[v].counter >> 12;
+ spu->data[v].counter += step;
+ }
+
+ int16_t clamprl = CLAMP(revl, INT16_MIN, INT16_MAX);
+ int16_t clamprr = CLAMP(revr, INT16_MIN, INT16_MAX);
+ int16_t clampsl = CLAMP(left, INT16_MIN, INT16_MAX);
+ int16_t clampsr = CLAMP(right, INT16_MIN, INT16_MAX);
+
+ if ((spu->spucnt & 0x4000) == 0)
+ return 0;
+
+ uint16_t clampl;
+ uint16_t clampr;
+
+ if (spu->spucnt & 0x0080) {+ if (spu->even_cycle)
+ spu_get_reverb_sample(spu, clamprl, clamprr, &spu->lrsl, &spu->lrsr);
+
+ clampl = CLAMP((clampsl + spu->lrsl), INT16_MIN, INT16_MAX) * (float)spu->mainlvol / 32767.0f;
+ clampr = CLAMP((clampsr + spu->lrsr), INT16_MIN, INT16_MAX) * (float)spu->mainrvol / 32767.0f;
+ } else {+ clampl = CLAMP(clampsl, INT16_MIN, INT16_MAX) * (float)spu->mainlvol / 32767.0f;
+ clampr = CLAMP(clampsr, INT16_MIN, INT16_MAX) * (float)spu->mainrvol / 32767.0f;
+ }
+
+ return clampl | (((uint32_t)clampr) << 16);
+}
+
+int counter = 0;
+
+void psx_spu_update_cdda_buffer(psx_spu_t* spu, void* buf) {+ int16_t* ptr = buf;
+ int16_t* ram = (int16_t*)spu->ram;
+
+ for (int i = 0; i < 0x400; i++) {+ ram[i + 0x000] = *ptr++;
+ ram[i + 0x400] = *ptr++;
+ }
+
+ // Little bit of lowpass/smoothing
+ for (int i = 0; i < 0x400; i += 8) {+ int l = 0, r = 0;
+
+ for (int j = 0; j < 8; j++) {+ l += ram[i + j];
+ r += ram[i + j + 0x400];
+ }
+
+ ram[i + 0x000] = l / 8;
+ ram[i + 0x400] = r / 8;
+ }
+
+ // Simulate capture IRQ
+ if (spu->ramdtc & 0xc) {+ if (spu->irq9addr <= 0x1ff) {+ if (!counter) {+ psx_ic_irq(spu->ic, IC_SPU);
+ }
+
+ counter++;
+ counter &= 0x1;
+ }
+ }
+}
+
+#undef CLAMP
#undef MAX
--- a/psx/dev/spu.h
+++ b/psx/dev/spu.h
@@ -1,189 +1,189 @@
#ifndef PSX_DEV_SPU_H
-#define PSX_DEV_SPU_H
-
-#include "p9.h"
-
-#include "dev/ic.h"
-
-#define PSX_SPU_BEGIN 0x1f801c00
-#define PSX_SPU_SIZE 0x400
-#define PSX_SPU_END 0x1f801fff
-
-#define SPU_RAM_SIZE 0x80000
-
-/*
- 1F801D88h - Voice 0..23 Key ON (Start Attack/Decay/Sustain) (KON) (W)
- 1F801D8Ch - Voice 0..23 Key OFF (Start Release) (KOFF) (W)
- 1F801D9Ch - Voice 0..23 ON/OFF (status) (ENDX) (R)
- 1F801DA6h - Sound RAM Data Transfer Address
- 1F801DA8h - Sound RAM Data Transfer Fifo
- 1F801DACh - Sound RAM Data Transfer Control (should be 0004h)
-*/
-
-#define SPUR_KONL 0x188
-#define SPUR_KONH 0x18a
-#define SPUR_KOFFL 0x18c
-#define SPUR_KOFFH 0x18e
-#define SPUR_EONL 0x198
-#define SPUR_EONH 0x19a
-#define SPUR_ENDXL 0x19c
-#define SPUR_ENDXH 0x19e
-#define SPUR_TADDR 0x1a6
-#define SPUR_TFIFO 0x1a8
-#define SPUR_SPUCNT 0x1aa
-#define SPUR_TCTRL 0x1ac
-#define SPUR_SPUSTAT 0x1ae
-#define SPUR_MBASE 0x1a2
-#define SPUR_SPUIRQA 0x1a4
-
+#define PSX_DEV_SPU_H
+
+#include "p9.h"
+
+#include "dev/ic.h"
+
+#define PSX_SPU_BEGIN 0x1f801c00
+#define PSX_SPU_SIZE 0x400
+#define PSX_SPU_END 0x1f801fff
+
+#define SPU_RAM_SIZE 0x80000
+
+/*
+ 1F801D88h - Voice 0..23 Key ON (Start Attack/Decay/Sustain) (KON) (W)
+ 1F801D8Ch - Voice 0..23 Key OFF (Start Release) (KOFF) (W)
+ 1F801D9Ch - Voice 0..23 ON/OFF (status) (ENDX) (R)
+ 1F801DA6h - Sound RAM Data Transfer Address
+ 1F801DA8h - Sound RAM Data Transfer Fifo
+ 1F801DACh - Sound RAM Data Transfer Control (should be 0004h)
+*/
+
+#define SPUR_KONL 0x188
+#define SPUR_KONH 0x18a
+#define SPUR_KOFFL 0x18c
+#define SPUR_KOFFH 0x18e
+#define SPUR_EONL 0x198
+#define SPUR_EONH 0x19a
+#define SPUR_ENDXL 0x19c
+#define SPUR_ENDXH 0x19e
+#define SPUR_TADDR 0x1a6
+#define SPUR_TFIFO 0x1a8
+#define SPUR_SPUCNT 0x1aa
+#define SPUR_TCTRL 0x1ac
+#define SPUR_SPUSTAT 0x1ae
+#define SPUR_MBASE 0x1a2
+#define SPUR_SPUIRQA 0x1a4
+
struct __attribute__((__packed__)) psx_spu_t {- uint32_t bus_delay;
- uint32_t io_base, io_size;
-
- psx_ic_t* ic;
- uint8_t* ram;
-
- struct __attribute__((__packed__)) {
- uint16_t volumel;
- uint16_t volumer;
- uint16_t adsampr;
- uint16_t adsaddr;
- uint16_t envctl1;
- uint16_t envctl2;
- uint16_t envcvol;
- uint16_t adraddr;
- } voice[24];
-
- uint16_t mainlvol;
- uint16_t mainrvol;
- uint16_t vlout;
- uint16_t vrout;
- uint32_t kon;
- uint32_t koff;
- uint32_t pmon;
- uint32_t non;
- uint32_t eon;
- uint32_t endx;
- uint16_t unk_da0;
- uint16_t mbase;
- uint16_t irq9addr;
- uint16_t ramdta;
- uint16_t ramdtf;
- uint16_t spucnt;
- uint16_t ramdtc;
- uint16_t spustat;
- uint32_t cdaivol;
- uint32_t extivol;
- uint32_t currvol;
- uint32_t unk_dbc;
- uint16_t dapf1;
- uint16_t dapf2;
- int16_t viir;
- int16_t vcomb1;
- int16_t vcomb2;
- int16_t vcomb3;
- int16_t vcomb4;
- int16_t vwall;
- int16_t vapf1;
- int16_t vapf2;
- uint16_t mlsame;
- uint16_t mrsame;
- uint16_t mlcomb1;
- uint16_t mrcomb1;
- uint16_t mlcomb2;
- uint16_t mrcomb2;
- uint16_t dlsame;
- uint16_t drsame;
- uint16_t mldiff;
- uint16_t mrdiff;
- uint16_t mlcomb3;
- uint16_t mrcomb3;
- uint16_t mlcomb4;
- uint16_t mrcomb4;
- uint16_t dldiff;
- uint16_t drdiff;
- uint16_t mlapf1;
- uint16_t mrapf1;
- uint16_t mlapf2;
- uint16_t mrapf2;
- int16_t vlin;
- int16_t vrin;
-
- // Internal registers unimplemented
-
- uint32_t taddr;
- uint16_t tfifo[32];
- uint16_t tfifo_index;
- uint32_t revbaddr;
- int lrsl;
- int lrsr;
- int even_cycle;
-
- struct {
- int playing;
- uint32_t counter;
- uint32_t current_addr;
- uint32_t repeat_addr;
- uint32_t prev_sample_index;
- int16_t s[4];
- int block_flags;
- int16_t buf[28];
- int16_t h[2];
- float lvol;
- float rvol;
- int cvol;
- int eon;
- int reverbl;
- int reverbr;
-
- /*
- ____lower 16bit (at 1F801C08h+N*10h)___________________________________
- 15 Attack Mode (0=Linear, 1=Exponential)
- - Attack Direction (Fixed, always Increase) (until Level 7FFFh)
- 14-10 Attack Shift (0..1Fh = Fast..Slow)
- 9-8 Attack Step (0..3 = "+7,+6,+5,+4")
- - Decay Mode (Fixed, always Exponential)
- - Decay Direction (Fixed, always Decrease) (until Sustain Level)
- 7-4 Decay Shift (0..0Fh = Fast..Slow)
- - Decay Step (Fixed, always "-8")
- 3-0 Sustain Level (0..0Fh) ;Level=(N+1)*800h
- ____upper 16bit (at 1F801C0Ah+N*10h)___________________________________
- 31 Sustain Mode (0=Linear, 1=Exponential)
- 30 Sustain Direction (0=Increase, 1=Decrease) (until Key OFF flag)
- 29 Not used? (should be zero)
- 28-24 Sustain Shift (0..1Fh = Fast..Slow)
- 23-22 Sustain Step (0..3 = "+7,+6,+5,+4" or "-8,-7,-6,-5") (inc/dec)
- 21 Release Mode (0=Linear, 1=Exponential)
- - Release Direction (Fixed, always Decrease) (until Level 0000h)
- 20-16 Release Shift (0..1Fh = Fast..Slow)
- - Release Step (Fixed, always "-8")
- */
-
- int adsr_phase;
- int adsr_cycles_reload;
- int adsr_cycles;
- int adsr_mode;
- int adsr_dir;
- int adsr_shift;
- int adsr_step;
- int adsr_pending_step;
- int adsr_sustain_level;
- uint32_t envctl;
- } data[24];
+ uint32_t bus_delay;
+ uint32_t io_base, io_size;
+
+ psx_ic_t* ic;
+ uint8_t* ram;
+
+ struct __attribute__((__packed__)) {+ uint16_t volumel;
+ uint16_t volumer;
+ uint16_t adsampr;
+ uint16_t adsaddr;
+ uint16_t envctl1;
+ uint16_t envctl2;
+ uint16_t envcvol;
+ uint16_t adraddr;
+ } voice[24];
+
+ uint16_t mainlvol;
+ uint16_t mainrvol;
+ uint16_t vlout;
+ uint16_t vrout;
+ uint32_t kon;
+ uint32_t koff;
+ uint32_t pmon;
+ uint32_t non;
+ uint32_t eon;
+ uint32_t endx;
+ uint16_t unk_da0;
+ uint16_t mbase;
+ uint16_t irq9addr;
+ uint16_t ramdta;
+ uint16_t ramdtf;
+ uint16_t spucnt;
+ uint16_t ramdtc;
+ uint16_t spustat;
+ uint32_t cdaivol;
+ uint32_t extivol;
+ uint32_t currvol;
+ uint32_t unk_dbc;
+ uint16_t dapf1;
+ uint16_t dapf2;
+ int16_t viir;
+ int16_t vcomb1;
+ int16_t vcomb2;
+ int16_t vcomb3;
+ int16_t vcomb4;
+ int16_t vwall;
+ int16_t vapf1;
+ int16_t vapf2;
+ uint16_t mlsame;
+ uint16_t mrsame;
+ uint16_t mlcomb1;
+ uint16_t mrcomb1;
+ uint16_t mlcomb2;
+ uint16_t mrcomb2;
+ uint16_t dlsame;
+ uint16_t drsame;
+ uint16_t mldiff;
+ uint16_t mrdiff;
+ uint16_t mlcomb3;
+ uint16_t mrcomb3;
+ uint16_t mlcomb4;
+ uint16_t mrcomb4;
+ uint16_t dldiff;
+ uint16_t drdiff;
+ uint16_t mlapf1;
+ uint16_t mrapf1;
+ uint16_t mlapf2;
+ uint16_t mrapf2;
+ int16_t vlin;
+ int16_t vrin;
+
+ // Internal registers unimplemented
+
+ uint32_t taddr;
+ uint16_t tfifo[32];
+ uint16_t tfifo_index;
+ uint32_t revbaddr;
+ int lrsl;
+ int lrsr;
+ int even_cycle;
+
+ struct {+ int playing;
+ uint32_t counter;
+ uint32_t current_addr;
+ uint32_t repeat_addr;
+ uint32_t prev_sample_index;
+ int16_t s[4];
+ int block_flags;
+ int16_t buf[28];
+ int16_t h[2];
+ float lvol;
+ float rvol;
+ int cvol;
+ int eon;
+ int reverbl;
+ int reverbr;
+
+ /*
+ ____lower 16bit (at 1F801C08h+N*10h)___________________________________
+ 15 Attack Mode (0=Linear, 1=Exponential)
+ - Attack Direction (Fixed, always Increase) (until Level 7FFFh)
+ 14-10 Attack Shift (0..1Fh = Fast..Slow)
+ 9-8 Attack Step (0..3 = "+7,+6,+5,+4")
+ - Decay Mode (Fixed, always Exponential)
+ - Decay Direction (Fixed, always Decrease) (until Sustain Level)
+ 7-4 Decay Shift (0..0Fh = Fast..Slow)
+ - Decay Step (Fixed, always "-8")
+ 3-0 Sustain Level (0..0Fh) ;Level=(N+1)*800h
+ ____upper 16bit (at 1F801C0Ah+N*10h)___________________________________
+ 31 Sustain Mode (0=Linear, 1=Exponential)
+ 30 Sustain Direction (0=Increase, 1=Decrease) (until Key OFF flag)
+ 29 Not used? (should be zero)
+ 28-24 Sustain Shift (0..1Fh = Fast..Slow)
+ 23-22 Sustain Step (0..3 = "+7,+6,+5,+4" or "-8,-7,-6,-5") (inc/dec)
+ 21 Release Mode (0=Linear, 1=Exponential)
+ - Release Direction (Fixed, always Decrease) (until Level 0000h)
+ 20-16 Release Shift (0..1Fh = Fast..Slow)
+ - Release Step (Fixed, always "-8")
+ */
+
+ int adsr_phase;
+ int adsr_cycles_reload;
+ int adsr_cycles;
+ int adsr_mode;
+ int adsr_dir;
+ int adsr_shift;
+ int adsr_step;
+ int adsr_pending_step;
+ int adsr_sustain_level;
+ uint32_t envctl;
+ } data[24];
};
typedef struct psx_spu_t psx_spu_t;
-
-psx_spu_t* psx_spu_create(void);
-void psx_spu_init(psx_spu_t*, psx_ic_t*);
-uint32_t psx_spu_read32(psx_spu_t*, uint32_t);
-uint16_t psx_spu_read16(psx_spu_t*, uint32_t);
-uint8_t psx_spu_read8(psx_spu_t*, uint32_t);
-void psx_spu_write32(psx_spu_t*, uint32_t, uint32_t);
-void psx_spu_write16(psx_spu_t*, uint32_t, uint16_t);
-void psx_spu_write8(psx_spu_t*, uint32_t, uint8_t);
-void psx_spu_destroy(psx_spu_t*);
-void psx_spu_update_cdda_buffer(psx_spu_t*, void*);
-uint32_t psx_spu_get_sample(psx_spu_t*);
-
+
+psx_spu_t* psx_spu_create(void);
+void psx_spu_init(psx_spu_t*, psx_ic_t*);
+uint32_t psx_spu_read32(psx_spu_t*, uint32_t);
+uint16_t psx_spu_read16(psx_spu_t*, uint32_t);
+uint8_t psx_spu_read8(psx_spu_t*, uint32_t);
+void psx_spu_write32(psx_spu_t*, uint32_t, uint32_t);
+void psx_spu_write16(psx_spu_t*, uint32_t, uint16_t);
+void psx_spu_write8(psx_spu_t*, uint32_t, uint8_t);
+void psx_spu_destroy(psx_spu_t*);
+void psx_spu_update_cdda_buffer(psx_spu_t*, void*);
+uint32_t psx_spu_get_sample(psx_spu_t*);
+
#endif
--- a/psx/dev/timer.c
+++ b/psx/dev/timer.c
@@ -1,195 +1,195 @@
-#include "p9.h"
-
-#include "dev/timer.h"
-#include "log.h"
-
-#define T0_COUNTER timer->timer[0].counter
-#define T0_SYNC_EN timer->timer[0].sync_enable
-#define T0_SYNC_MODE timer->timer[0].sync_mode
-#define T0_RESET_TGT timer->timer[0].reset_target
-#define T0_IRQ_TGT timer->timer[0].irq_target
-#define T0_IRQ_MAX timer->timer[0].irq_max
-#define T0_IRQ_REPEAT timer->timer[0].irq_repeat
-#define T0_IRQ_TOGGLE timer->timer[0].irq_toggle
-#define T0_CLKSRC timer->timer[0].clk_source
-#define T0_IRQ timer->timer[0].irq
-#define T0_TGT_REACHED timer->timer[0].target_reached
-#define T0_MAX_REACHED timer->timer[0].max_reached
-#define T0_IRQ_FIRED timer->timer[0].irq_fired
-#define T0_PAUSED timer->timer[0].paused
-#define T0_BLANK_ONCE timer->timer[0].blank_once
-#define T1_COUNTER timer->timer[1].counter
-#define T1_SYNC_EN timer->timer[1].sync_enable
-#define T1_SYNC_MODE timer->timer[1].sync_mode
-#define T1_RESET_TGT timer->timer[1].reset_target
-#define T1_IRQ_TGT timer->timer[1].irq_target
-#define T1_IRQ_MAX timer->timer[1].irq_max
-#define T1_IRQ_REPEAT timer->timer[1].irq_repeat
-#define T1_IRQ_TOGGLE timer->timer[1].irq_toggle
-#define T1_CLKSRC timer->timer[1].clk_source
-#define T1_IRQ timer->timer[1].irq
-#define T1_TGT_REACHED timer->timer[1].target_reached
-#define T1_MAX_REACHED timer->timer[1].max_reached
-#define T1_IRQ_FIRED timer->timer[1].irq_fired
-#define T1_PAUSED timer->timer[1].paused
-#define T1_BLANK_ONCE timer->timer[1].blank_once
-#define T2_COUNTER timer->timer[2].counter
-#define T2_SYNC_EN timer->timer[2].sync_enable
-#define T2_SYNC_MODE timer->timer[2].sync_mode
-#define T2_RESET_TGT timer->timer[2].reset_target
-#define T2_IRQ_TGT timer->timer[2].irq_target
-#define T2_IRQ_MAX timer->timer[2].irq_max
-#define T2_IRQ_REPEAT timer->timer[2].irq_repeat
-#define T2_IRQ_TOGGLE timer->timer[2].irq_toggle
-#define T2_CLKSRC timer->timer[2].clk_source
-#define T2_IRQ timer->timer[2].irq
-#define T2_TGT_REACHED timer->timer[2].target_reached
-#define T2_MAX_REACHED timer->timer[2].max_reached
-#define T2_IRQ_FIRED timer->timer[2].irq_fired
-#define T2_PAUSED timer->timer[2].paused
-#define T2_BLANK_ONCE timer->timer[2].blank_once
-#define T2_DIV_COUNTER timer->timer[2].div_counter
-
-uint16_t timer_get_mode(psx_timer_t* timer, int index) {
- uint16_t value = (timer->timer[index].sync_enable << 0) |
- (timer->timer[index].sync_mode << 1) |
- (timer->timer[index].reset_target << 3) |
- (timer->timer[index].irq_target << 4) |
- (timer->timer[index].irq_max << 5) |
- (timer->timer[index].irq_repeat << 6) |
- (timer->timer[index].irq_toggle << 7) |
- (timer->timer[index].clk_source << 8) |
- (timer->timer[index].irq << 10) |
- (timer->timer[index].target_reached << 11) |
- (timer->timer[index].max_reached << 12);
-
- timer->timer[index].target_reached = 0;
- timer->timer[index].max_reached = 0;
-
- return value;
-}
-
-void timer_set_mode(psx_timer_t* timer, int index, uint16_t value) {
- timer->timer[index].sync_enable = (value >> 0) & 1;
- timer->timer[index].sync_mode = (value >> 1) & 3;
- timer->timer[index].reset_target = (value >> 3) & 1;
- timer->timer[index].irq_target = (value >> 4) & 1;
- timer->timer[index].irq_max = (value >> 5) & 1;
- timer->timer[index].irq_repeat = (value >> 6) & 1;
- timer->timer[index].irq_toggle = (value >> 7) & 1;
- timer->timer[index].clk_source = (value >> 8) & 3;
- timer->timer[index].target_reached = 0;
- timer->timer[index].max_reached = 0;
-
- // IRQ and counter are set to 0 on mode writes
- timer->timer[index].irq = 1;
- timer->timer[index].irq_fired = 0;
- timer->timer[index].counter = 0;
- timer->timer[index].div_counter = 0;
- timer->timer[index].blank_once = 0;
- timer->timer[index].paused = 0;
-
- // printf(
- // "timer_set_mode %u %04x\n"
- // "sync_enable %u\n"
- // "sync_mode %u\n"
- // "reset_target %u\n"
- // "irq_target %u\n"
- // "irq_max %u\n"
- // "irq_repeat %u\n"
- // "irq_toggle %u\n"
- // "clk_source %u\n"
- // "target_reached %u\n"
- // "max_reached %u\n"
- // "target %04x\n",
- // index, value,
- // timer->timer[index].sync_enable,
- // timer->timer[index].sync_mode,
- // timer->timer[index].reset_target,
- // timer->timer[index].irq_target,
- // timer->timer[index].irq_max,
- // timer->timer[index].irq_repeat,
- // timer->timer[index].irq_toggle,
- // timer->timer[index].clk_source,
- // timer->timer[index].target_reached,
- // timer->timer[index].max_reached,
- // timer->timer[index].target
- // );
-
- switch (index) {
- case 0: {
- if ((T0_SYNC_MODE == 1) || (T0_SYNC_MODE == 2) || !T0_SYNC_EN)
- return;
-
- T0_PAUSED = timer->hblank | (T0_SYNC_MODE == 3);
- } break;
-
- case 1: {
- if ((T1_SYNC_MODE == 1) || (T1_SYNC_MODE == 2) || !T1_SYNC_EN)
- return;
-
- T1_PAUSED = timer->vblank | (T1_SYNC_MODE == 3);
- } break;
-
- case 2: {
- if (!T2_SYNC_EN)
- return;
-
- T2_PAUSED = (T2_SYNC_MODE == 0) || (T2_SYNC_MODE == 3);
- } break;
- }
-}
-
-const char* g_psx_timer_reg_names[] = {
- "counter", 0, 0, 0,
- "mode", 0, 0, 0,
- "target", 0, 0, 0
-};
-
-psx_timer_t* psx_timer_create(void) {
- return (psx_timer_t*)malloc(sizeof(psx_timer_t));
-}
-
-void psx_timer_init(psx_timer_t* timer, psx_ic_t* ic, psx_gpu_t* gpu) {
- memset(timer, 0, sizeof(psx_timer_t));
-
- timer->io_base = PSX_TIMER_BEGIN;
- timer->io_size = PSX_TIMER_SIZE;
-
- timer->ic = ic;
- timer->gpu = gpu;
-}
-
-uint32_t psx_timer_read32(psx_timer_t* timer, uint32_t offset) {
- int index = offset >> 4;
- int reg = offset & 0xf;
-
- switch (reg) {
- case 0: return timer->timer[index].counter;
- case 4: return timer_get_mode(timer, index);
- case 8: return timer->timer[index].target;
- }
-
- printf("Unhandled 32-bit TIMER read at offset %08x\n", offset);
-
- return 0x0;
-}
-
-uint16_t psx_timer_read16(psx_timer_t* timer, uint32_t offset) {
- int index = offset >> 4;
- int reg = offset & 0xf;
-
- switch (reg) {
- case 0: return timer->timer[index].counter;
- case 4: return timer_get_mode(timer, index);
- case 8: return timer->timer[index].target;
- }
-
- printf("Unhandled 16-bit TIMER read at offset %08x\n", offset);
-
- return 0x0;
-}
-
+#include "p9.h"
+
+#include "dev/timer.h"
+#include "log.h"
+
+#define T0_COUNTER timer->timer[0].counter
+#define T0_SYNC_EN timer->timer[0].sync_enable
+#define T0_SYNC_MODE timer->timer[0].sync_mode
+#define T0_RESET_TGT timer->timer[0].reset_target
+#define T0_IRQ_TGT timer->timer[0].irq_target
+#define T0_IRQ_MAX timer->timer[0].irq_max
+#define T0_IRQ_REPEAT timer->timer[0].irq_repeat
+#define T0_IRQ_TOGGLE timer->timer[0].irq_toggle
+#define T0_CLKSRC timer->timer[0].clk_source
+#define T0_IRQ timer->timer[0].irq
+#define T0_TGT_REACHED timer->timer[0].target_reached
+#define T0_MAX_REACHED timer->timer[0].max_reached
+#define T0_IRQ_FIRED timer->timer[0].irq_fired
+#define T0_PAUSED timer->timer[0].paused
+#define T0_BLANK_ONCE timer->timer[0].blank_once
+#define T1_COUNTER timer->timer[1].counter
+#define T1_SYNC_EN timer->timer[1].sync_enable
+#define T1_SYNC_MODE timer->timer[1].sync_mode
+#define T1_RESET_TGT timer->timer[1].reset_target
+#define T1_IRQ_TGT timer->timer[1].irq_target
+#define T1_IRQ_MAX timer->timer[1].irq_max
+#define T1_IRQ_REPEAT timer->timer[1].irq_repeat
+#define T1_IRQ_TOGGLE timer->timer[1].irq_toggle
+#define T1_CLKSRC timer->timer[1].clk_source
+#define T1_IRQ timer->timer[1].irq
+#define T1_TGT_REACHED timer->timer[1].target_reached
+#define T1_MAX_REACHED timer->timer[1].max_reached
+#define T1_IRQ_FIRED timer->timer[1].irq_fired
+#define T1_PAUSED timer->timer[1].paused
+#define T1_BLANK_ONCE timer->timer[1].blank_once
+#define T2_COUNTER timer->timer[2].counter
+#define T2_SYNC_EN timer->timer[2].sync_enable
+#define T2_SYNC_MODE timer->timer[2].sync_mode
+#define T2_RESET_TGT timer->timer[2].reset_target
+#define T2_IRQ_TGT timer->timer[2].irq_target
+#define T2_IRQ_MAX timer->timer[2].irq_max
+#define T2_IRQ_REPEAT timer->timer[2].irq_repeat
+#define T2_IRQ_TOGGLE timer->timer[2].irq_toggle
+#define T2_CLKSRC timer->timer[2].clk_source
+#define T2_IRQ timer->timer[2].irq
+#define T2_TGT_REACHED timer->timer[2].target_reached
+#define T2_MAX_REACHED timer->timer[2].max_reached
+#define T2_IRQ_FIRED timer->timer[2].irq_fired
+#define T2_PAUSED timer->timer[2].paused
+#define T2_BLANK_ONCE timer->timer[2].blank_once
+#define T2_DIV_COUNTER timer->timer[2].div_counter
+
+uint16_t timer_get_mode(psx_timer_t* timer, int index) {+ uint16_t value = (timer->timer[index].sync_enable << 0) |
+ (timer->timer[index].sync_mode << 1) |
+ (timer->timer[index].reset_target << 3) |
+ (timer->timer[index].irq_target << 4) |
+ (timer->timer[index].irq_max << 5) |
+ (timer->timer[index].irq_repeat << 6) |
+ (timer->timer[index].irq_toggle << 7) |
+ (timer->timer[index].clk_source << 8) |
+ (timer->timer[index].irq << 10) |
+ (timer->timer[index].target_reached << 11) |
+ (timer->timer[index].max_reached << 12);
+
+ timer->timer[index].target_reached = 0;
+ timer->timer[index].max_reached = 0;
+
+ return value;
+}
+
+void timer_set_mode(psx_timer_t* timer, int index, uint16_t value) {+ timer->timer[index].sync_enable = (value >> 0) & 1;
+ timer->timer[index].sync_mode = (value >> 1) & 3;
+ timer->timer[index].reset_target = (value >> 3) & 1;
+ timer->timer[index].irq_target = (value >> 4) & 1;
+ timer->timer[index].irq_max = (value >> 5) & 1;
+ timer->timer[index].irq_repeat = (value >> 6) & 1;
+ timer->timer[index].irq_toggle = (value >> 7) & 1;
+ timer->timer[index].clk_source = (value >> 8) & 3;
+ timer->timer[index].target_reached = 0;
+ timer->timer[index].max_reached = 0;
+
+ // IRQ and counter are set to 0 on mode writes
+ timer->timer[index].irq = 1;
+ timer->timer[index].irq_fired = 0;
+ timer->timer[index].counter = 0;
+ timer->timer[index].div_counter = 0;
+ timer->timer[index].blank_once = 0;
+ timer->timer[index].paused = 0;
+
+ // printf(
+ // "timer_set_mode %u %04x\n"
+ // "sync_enable %u\n"
+ // "sync_mode %u\n"
+ // "reset_target %u\n"
+ // "irq_target %u\n"
+ // "irq_max %u\n"
+ // "irq_repeat %u\n"
+ // "irq_toggle %u\n"
+ // "clk_source %u\n"
+ // "target_reached %u\n"
+ // "max_reached %u\n"
+ // "target %04x\n",
+ // index, value,
+ // timer->timer[index].sync_enable,
+ // timer->timer[index].sync_mode,
+ // timer->timer[index].reset_target,
+ // timer->timer[index].irq_target,
+ // timer->timer[index].irq_max,
+ // timer->timer[index].irq_repeat,
+ // timer->timer[index].irq_toggle,
+ // timer->timer[index].clk_source,
+ // timer->timer[index].target_reached,
+ // timer->timer[index].max_reached,
+ // timer->timer[index].target
+ // );
+
+ switch (index) {+ case 0: {+ if ((T0_SYNC_MODE == 1) || (T0_SYNC_MODE == 2) || !T0_SYNC_EN)
+ return;
+
+ T0_PAUSED = timer->hblank | (T0_SYNC_MODE == 3);
+ } break;
+
+ case 1: {+ if ((T1_SYNC_MODE == 1) || (T1_SYNC_MODE == 2) || !T1_SYNC_EN)
+ return;
+
+ T1_PAUSED = timer->vblank | (T1_SYNC_MODE == 3);
+ } break;
+
+ case 2: {+ if (!T2_SYNC_EN)
+ return;
+
+ T2_PAUSED = (T2_SYNC_MODE == 0) || (T2_SYNC_MODE == 3);
+ } break;
+ }
+}
+
+const char* g_psx_timer_reg_names[] = {+ "counter", 0, 0, 0,
+ "mode", 0, 0, 0,
+ "target", 0, 0, 0
+};
+
+psx_timer_t* psx_timer_create(void) {+ return (psx_timer_t*)malloc(sizeof(psx_timer_t));
+}
+
+void psx_timer_init(psx_timer_t* timer, psx_ic_t* ic, psx_gpu_t* gpu) {+ memset(timer, 0, sizeof(psx_timer_t));
+
+ timer->io_base = PSX_TIMER_BEGIN;
+ timer->io_size = PSX_TIMER_SIZE;
+
+ timer->ic = ic;
+ timer->gpu = gpu;
+}
+
+uint32_t psx_timer_read32(psx_timer_t* timer, uint32_t offset) {+ int index = offset >> 4;
+ int reg = offset & 0xf;
+
+ switch (reg) {+ case 0: return timer->timer[index].counter;
+ case 4: return timer_get_mode(timer, index);
+ case 8: return timer->timer[index].target;
+ }
+
+ printf("Unhandled 32-bit TIMER read at offset %08x\n", offset);+
+ return 0x0;
+}
+
+uint16_t psx_timer_read16(psx_timer_t* timer, uint32_t offset) {+ int index = offset >> 4;
+ int reg = offset & 0xf;
+
+ switch (reg) {+ case 0: return timer->timer[index].counter;
+ case 4: return timer_get_mode(timer, index);
+ case 8: return timer->timer[index].target;
+ }
+
+ printf("Unhandled 16-bit TIMER read at offset %08x\n", offset);+
+ return 0x0;
+}
+
uint8_t psx_timer_read8(psx_timer_t* timer, uint32_t offset) {USED(timer);
printf("Unhandled 8-bit TIMER read at offset %08x\n", offset);@@ -196,233 +196,233 @@
return 0x0;
}
-
-void timer_handle_irq(psx_timer_t* timer, int i);
-
-void psx_timer_write32(psx_timer_t* timer, uint32_t offset, uint32_t value) {
- int index = offset >> 4;
- int reg = offset & 0xf;
-
- switch (reg) {
- case 0: timer->timer[index].counter = value & 0xffff; break;
- case 4: timer_set_mode(timer, index, value); break;
- case 8: timer->timer[index].target = value & 0xffff; break;
- }
-
- timer_handle_irq(timer, index);
-}
-
-void psx_timer_write16(psx_timer_t* timer, uint32_t offset, uint16_t value) {
- int index = offset >> 4;
- int reg = offset & 0xf;
-
- switch (reg) {
- case 0: timer->timer[index].counter = value & 0xffff; break;
- case 4: timer_set_mode(timer, index, value); break;
- case 8: timer->timer[index].target = value & 0xffff; break;
- }
-
- timer_handle_irq(timer, index);
-}
-
+
+void timer_handle_irq(psx_timer_t* timer, int i);
+
+void psx_timer_write32(psx_timer_t* timer, uint32_t offset, uint32_t value) {+ int index = offset >> 4;
+ int reg = offset & 0xf;
+
+ switch (reg) {+ case 0: timer->timer[index].counter = value & 0xffff; break;
+ case 4: timer_set_mode(timer, index, value); break;
+ case 8: timer->timer[index].target = value & 0xffff; break;
+ }
+
+ timer_handle_irq(timer, index);
+}
+
+void psx_timer_write16(psx_timer_t* timer, uint32_t offset, uint16_t value) {+ int index = offset >> 4;
+ int reg = offset & 0xf;
+
+ switch (reg) {+ case 0: timer->timer[index].counter = value & 0xffff; break;
+ case 4: timer_set_mode(timer, index, value); break;
+ case 8: timer->timer[index].target = value & 0xffff; break;
+ }
+
+ timer_handle_irq(timer, index);
+}
+
void psx_timer_write8(psx_timer_t* timer, uint32_t offset, uint8_t value) {USED(timer);
printf("Unhandled 8-bit TIMER write at offset %08x (%02x)\n", offset, value);}
-
-void timer_handle_irq(psx_timer_t* timer, int i) {
- int irq = 0;
-
- int target_reached = timer->timer[i].counter > timer->timer[i].target;
- int max_reached = timer->timer[i].counter > 65535.0f;
-
- if (target_reached) {
- timer->timer[i].target_reached = 1;
-
- // if ((i == 1) && (T1_CLKSRC == 1))
- // printf("target %04x (%f) reached\n", timer->timer[i].target, timer->timer[i].counter);
-
- if (timer->timer[i].reset_target)
- timer->timer[i].counter = 0;
-
- if (timer->timer[i].irq_target)
- irq = 1;
- }
-
- if (max_reached) {
- timer->timer[i].counter = 0;
- timer->timer[i].max_reached = 1;
-
- if (timer->timer[i].irq_max)
- irq = 1;
- }
-
- if (!irq)
- return;
-
- if (!timer->timer[i].irq_toggle) {
- timer->timer[i].irq = 0;
- } else {
- timer->timer[i].irq ^= 1;
- }
-
- int trigger = !timer->timer[i].irq;
-
- if (!timer->timer[i].irq_repeat) {
- if (trigger && !timer->timer[i].irq_fired) {
- timer->timer[i].irq_fired = 1;
- } else {
- return;
- }
- }
-
- timer->timer[i].irq = 1;
-
- if (trigger) {
- psx_ic_irq(timer->ic, 16 << i);
- }
-}
-
-float timer_get_dotclock_div(psx_timer_t* timer) {
- static const float dmode_dotclk_div_table[] = {
- 10.0f, 8.0f, 5.0f, 4.0f
- };
-
- if (timer->gpu->display_mode & 0x40) {
- return 11.0f / 7.0f / 7.0f;
- } else {
- return 11.0f / 7.0f / dmode_dotclk_div_table[timer->gpu->display_mode & 0x3];
- }
-}
-
-void timer_update_timer0(psx_timer_t* timer, int cyc) {
- if (T0_PAUSED)
- return;
-
- if (T0_CLKSRC & 1) {
- // Dotclock test
- T0_COUNTER += (float)cyc * timer_get_dotclock_div(timer);
- } else {
- T0_COUNTER += (float)cyc;
- }
-
- timer_handle_irq(timer, 0);
-}
-
-void timer_update_timer1(psx_timer_t* timer, int cyc) {
- if (T1_PAUSED)
- return;
-
- if (T1_CLKSRC & 1) {
- // Counter is incremented in our hblank callback
- } else {
- T1_COUNTER += (float)cyc;
- }
-
- timer_handle_irq(timer, 1);
-}
-
-void timer_update_timer2(psx_timer_t* timer, int cyc) {
- if (T2_PAUSED)
- return;
-
- if (T2_CLKSRC <= 1) {
- T2_COUNTER += (float)cyc;
- } else {
- T2_COUNTER += ((float)cyc) / 8.0f;
- }
-
- timer_handle_irq(timer, 2);
-}
-
+
+void timer_handle_irq(psx_timer_t* timer, int i) {+ int irq = 0;
+
+ int target_reached = timer->timer[i].counter > timer->timer[i].target;
+ int max_reached = timer->timer[i].counter > 65535.0f;
+
+ if (target_reached) {+ timer->timer[i].target_reached = 1;
+
+ // if ((i == 1) && (T1_CLKSRC == 1))
+ // printf("target %04x (%f) reached\n", timer->timer[i].target, timer->timer[i].counter);+
+ if (timer->timer[i].reset_target)
+ timer->timer[i].counter = 0;
+
+ if (timer->timer[i].irq_target)
+ irq = 1;
+ }
+
+ if (max_reached) {+ timer->timer[i].counter = 0;
+ timer->timer[i].max_reached = 1;
+
+ if (timer->timer[i].irq_max)
+ irq = 1;
+ }
+
+ if (!irq)
+ return;
+
+ if (!timer->timer[i].irq_toggle) {+ timer->timer[i].irq = 0;
+ } else {+ timer->timer[i].irq ^= 1;
+ }
+
+ int trigger = !timer->timer[i].irq;
+
+ if (!timer->timer[i].irq_repeat) {+ if (trigger && !timer->timer[i].irq_fired) {+ timer->timer[i].irq_fired = 1;
+ } else {+ return;
+ }
+ }
+
+ timer->timer[i].irq = 1;
+
+ if (trigger) {+ psx_ic_irq(timer->ic, 16 << i);
+ }
+}
+
+float timer_get_dotclock_div(psx_timer_t* timer) {+ static const float dmode_dotclk_div_table[] = {+ 10.0f, 8.0f, 5.0f, 4.0f
+ };
+
+ if (timer->gpu->display_mode & 0x40) {+ return 11.0f / 7.0f / 7.0f;
+ } else {+ return 11.0f / 7.0f / dmode_dotclk_div_table[timer->gpu->display_mode & 0x3];
+ }
+}
+
+void timer_update_timer0(psx_timer_t* timer, int cyc) {+ if (T0_PAUSED)
+ return;
+
+ if (T0_CLKSRC & 1) {+ // Dotclock test
+ T0_COUNTER += (float)cyc * timer_get_dotclock_div(timer);
+ } else {+ T0_COUNTER += (float)cyc;
+ }
+
+ timer_handle_irq(timer, 0);
+}
+
+void timer_update_timer1(psx_timer_t* timer, int cyc) {+ if (T1_PAUSED)
+ return;
+
+ if (T1_CLKSRC & 1) {+ // Counter is incremented in our hblank callback
+ } else {+ T1_COUNTER += (float)cyc;
+ }
+
+ timer_handle_irq(timer, 1);
+}
+
+void timer_update_timer2(psx_timer_t* timer, int cyc) {+ if (T2_PAUSED)
+ return;
+
+ if (T2_CLKSRC <= 1) {+ T2_COUNTER += (float)cyc;
+ } else {+ T2_COUNTER += ((float)cyc) / 8.0f;
+ }
+
+ timer_handle_irq(timer, 2);
+}
+
void psx_timer_update(psx_timer_t* timer, int cyc) {USED(cyc);
timer->prev_hblank = timer->hblank;
timer->prev_vblank = timer->vblank;
-
- timer_update_timer0(timer, 2);
- timer_update_timer1(timer, 2);
- timer_update_timer2(timer, 2);
-}
-
-void psxe_gpu_hblank_event_cb(psx_gpu_t* gpu) {
- psx_timer_t* timer = gpu->udata[1];
-
- timer->hblank = 1;
-
- if ((T1_CLKSRC & 1) && !T1_PAUSED) {
- ++T1_COUNTER;
-
- timer_handle_irq(timer, 1);
- }
-
- if (!T0_SYNC_EN)
- return;
-
- switch (T0_SYNC_MODE) {
- case 0: T0_PAUSED = 1; break;
- case 1: T0_COUNTER = 0; break;
- case 2: T0_COUNTER = 0; T0_PAUSED = 0; break;
- case 3: {
- if (!T0_BLANK_ONCE) {
- T0_BLANK_ONCE = 1;
- T0_SYNC_EN = 0;
- T0_PAUSED = 0;
- }
- } break;
- }
-}
-
-void psxe_gpu_hblank_end_event_cb(psx_gpu_t* gpu) {
- psx_timer_t* timer = gpu->udata[1];
-
- timer->hblank = 0;
-
- if (!T0_SYNC_EN)
- return;
-
- switch (T0_SYNC_MODE) {
- case 0: T0_PAUSED = 0; break;
- case 2: T0_PAUSED = 1; break;
- }
-}
-
-void psxe_gpu_vblank_timer_event_cb(psx_gpu_t* gpu) {
- psx_timer_t* timer = gpu->udata[1];
-
- timer->vblank = 1;
-
- if (!T1_SYNC_EN)
- return;
-
- switch (T1_SYNC_MODE) {
- case 0: T1_PAUSED = 1; break;
- case 1: T1_COUNTER = 0; break;
- case 2: T1_COUNTER = 0; T1_PAUSED = 0; break;
- case 3: {
- if (!T1_BLANK_ONCE) {
- T1_BLANK_ONCE = 1;
- T1_SYNC_EN = 0;
- T1_PAUSED = 0;
- }
- } break;
- }
-}
-
-void psxe_gpu_vblank_end_event_cb(psx_gpu_t* gpu) {
- psx_timer_t* timer = gpu->udata[1];
-
- timer->vblank = 0;
-
- if (!T1_SYNC_EN)
- return;
-
- switch (T1_SYNC_MODE) {
- case 0: T1_PAUSED = 0; break;
- case 2: T1_PAUSED = 1; break;
- }
-}
-
-void psx_timer_destroy(psx_timer_t* timer) {
- free(timer);
+
+ timer_update_timer0(timer, 2);
+ timer_update_timer1(timer, 2);
+ timer_update_timer2(timer, 2);
+}
+
+void psxe_gpu_hblank_event_cb(psx_gpu_t* gpu) {+ psx_timer_t* timer = gpu->udata[1];
+
+ timer->hblank = 1;
+
+ if ((T1_CLKSRC & 1) && !T1_PAUSED) {+ ++T1_COUNTER;
+
+ timer_handle_irq(timer, 1);
+ }
+
+ if (!T0_SYNC_EN)
+ return;
+
+ switch (T0_SYNC_MODE) {+ case 0: T0_PAUSED = 1; break;
+ case 1: T0_COUNTER = 0; break;
+ case 2: T0_COUNTER = 0; T0_PAUSED = 0; break;
+ case 3: {+ if (!T0_BLANK_ONCE) {+ T0_BLANK_ONCE = 1;
+ T0_SYNC_EN = 0;
+ T0_PAUSED = 0;
+ }
+ } break;
+ }
+}
+
+void psxe_gpu_hblank_end_event_cb(psx_gpu_t* gpu) {+ psx_timer_t* timer = gpu->udata[1];
+
+ timer->hblank = 0;
+
+ if (!T0_SYNC_EN)
+ return;
+
+ switch (T0_SYNC_MODE) {+ case 0: T0_PAUSED = 0; break;
+ case 2: T0_PAUSED = 1; break;
+ }
+}
+
+void psxe_gpu_vblank_timer_event_cb(psx_gpu_t* gpu) {+ psx_timer_t* timer = gpu->udata[1];
+
+ timer->vblank = 1;
+
+ if (!T1_SYNC_EN)
+ return;
+
+ switch (T1_SYNC_MODE) {+ case 0: T1_PAUSED = 1; break;
+ case 1: T1_COUNTER = 0; break;
+ case 2: T1_COUNTER = 0; T1_PAUSED = 0; break;
+ case 3: {+ if (!T1_BLANK_ONCE) {+ T1_BLANK_ONCE = 1;
+ T1_SYNC_EN = 0;
+ T1_PAUSED = 0;
+ }
+ } break;
+ }
+}
+
+void psxe_gpu_vblank_end_event_cb(psx_gpu_t* gpu) {+ psx_timer_t* timer = gpu->udata[1];
+
+ timer->vblank = 0;
+
+ if (!T1_SYNC_EN)
+ return;
+
+ switch (T1_SYNC_MODE) {+ case 0: T1_PAUSED = 0; break;
+ case 2: T1_PAUSED = 1; break;
+ }
+}
+
+void psx_timer_destroy(psx_timer_t* timer) {+ free(timer);
}
--- a/psx/dev/timer.h
+++ b/psx/dev/timer.h
@@ -1,118 +1,118 @@
#ifndef PSX_DEV_TIMER_H
-#define PSX_DEV_TIMER_H
-
-#include "p9.h"
-
-#include "dev/ic.h"
-#include "dev/gpu.h"
-
-#define PSX_TIMER_BEGIN 0x1f801100
-#define PSX_TIMER_SIZE 0x30
-#define PSX_TIMER_END 0x1f80112f
-
-/*
- 0 Synchronization Enable (0=Free Run, 1=Synchronize via Bit1-2)
- 1-2 Synchronization Mode (0-3, see lists below)
- Synchronization Modes for Counter 0:
- 0 = Pause counter during Hblank(s)
- 1 = Reset counter to 0000h at Hblank(s)
- 2 = Reset counter to 0000h at Hblank(s) and pause outside of Hblank
- 3 = Pause until Hblank occurs once, then switch to Free Run
- Synchronization Modes for Counter 1:
- Same as above, but using Vblank instead of Hblank
- Synchronization Modes for Counter 2:
- 0 or 3 = Stop counter at current value (forever, no h/v-blank start)
- 1 or 2 = Free Run (same as when Synchronization Disabled)
- 3 Reset counter to 0000h (0=After Counter=FFFFh, 1=After Counter=Target)
- 4 IRQ when Counter=Target (0=Disable, 1=Enable)
- 5 IRQ when Counter=FFFFh (0=Disable, 1=Enable)
- 6 IRQ Once/Repeat Mode (0=One-shot, 1=Repeatedly)
- 7 IRQ Pulse/Toggle Mode (0=Short Bit10=0 Pulse, 1=Toggle Bit10 on/off)
- 8-9 Clock Source (0-3, see list below)
- Counter 0: 0 or 2 = System Clock, 1 or 3 = Dotclock
- Counter 1: 0 or 2 = System Clock, 1 or 3 = Hblank
- Counter 2: 0 or 1 = System Clock, 2 or 3 = System Clock/8
- 10 Interrupt Request (0=Yes, 1=No) (Set after Writing) (W=1) (R)
- 11 Reached Target Value (0=No, 1=Yes) (Reset after Reading) (R)
- 12 Reached FFFFh Value (0=No, 1=Yes) (Reset after Reading) (R)
- 13-15 Unknown (seems to be always zero)
- 16-31 Garbage (next opcode)
-*/
-#define MODE_SYNCEN 0x0001
-#define MODE_SYNCMD 0x0006
-#define T0MD_HBLPAUSE 0
-#define T0MD_HBLRESET 1
-#define T0MD_HBLRANDP 2
-#define T0MD_HBLOSHOT 3
-// #define T1MD_VBLPAUSE 0
-// #define T1MD_VBLRESET 1
-// #define T1MD_VBLRANDP 2
-// #define T1MD_VBLOSHOT 3
-// #define T2MD_STOPMODE 0
-// #define T2MD_FREEMODE 1
-#define MODE_RESETC 0x0008
-#define MODE_TGTIRQ 0x0010
-#define MODE_MAXIRQ 0x0020
-#define MODE_IRQRMD 0x0040
-#define MODE_IRQPMD 0x0080
-#define MODE_CLK 0x0080
-
-/*
- 0 Synchronization Enable (0=Free Run, 1=Synchronize via Bit1-2)
- 1-2 Synchronization Mode (0-3, see lists below)
- Synchronization Modes for Counter 0:
- 0 = Pause counter during Hblank(s)
- 1 = Reset counter to 0000h at Hblank(s)
- 2 = Reset counter to 0000h at Hblank(s) and pause outside of Hblank
- 3 = Pause until Hblank occurs once, then switch to Free Run
- Synchronization Modes for Counter 1:
- Same as above, but using Vblank instead of Hblank
- Synchronization Modes for Counter 2:
- 0 or 3 = Stop counter at current value (forever, no h/v-blank start)
- 1 or 2 = Free Run (same as when Synchronization Disabled)
- 3 Reset counter to 0000h (0=After Counter=FFFFh, 1=After Counter=Target)
- 4 IRQ when Counter=Target (0=Disable, 1=Enable)
- 5 IRQ when Counter=FFFFh (0=Disable, 1=Enable)
- 6 IRQ Once/Repeat Mode (0=One-shot, 1=Repeatedly)
- 7 IRQ Pulse/Toggle Mode (0=Short Bit10=0 Pulse, 1=Toggle Bit10 on/off)
- 8-9 Clock Source (0-3, see list below)
- Counter 0: 0 or 2 = System Clock, 1 or 3 = Dotclock
- Counter 1: 0 or 2 = System Clock, 1 or 3 = Hblank
- Counter 2: 0 or 1 = System Clock, 2 or 3 = System Clock/8
- 10 Interrupt Request (0=Yes, 1=No) (Set after Writing) (W=1) (R)
- 11 Reached Target Value (0=No, 1=Yes) (Reset after Reading) (R)
- 12 Reached FFFFh Value (0=No, 1=Yes) (Reset after Reading) (R)
- 13-15 Unknown (seems to be always zero)
- 16-31 Garbage (next opcode)
-*/
-
+#define PSX_DEV_TIMER_H
+
+#include "p9.h"
+
+#include "dev/ic.h"
+#include "dev/gpu.h"
+
+#define PSX_TIMER_BEGIN 0x1f801100
+#define PSX_TIMER_SIZE 0x30
+#define PSX_TIMER_END 0x1f80112f
+
+/*
+ 0 Synchronization Enable (0=Free Run, 1=Synchronize via Bit1-2)
+ 1-2 Synchronization Mode (0-3, see lists below)
+ Synchronization Modes for Counter 0:
+ 0 = Pause counter during Hblank(s)
+ 1 = Reset counter to 0000h at Hblank(s)
+ 2 = Reset counter to 0000h at Hblank(s) and pause outside of Hblank
+ 3 = Pause until Hblank occurs once, then switch to Free Run
+ Synchronization Modes for Counter 1:
+ Same as above, but using Vblank instead of Hblank
+ Synchronization Modes for Counter 2:
+ 0 or 3 = Stop counter at current value (forever, no h/v-blank start)
+ 1 or 2 = Free Run (same as when Synchronization Disabled)
+ 3 Reset counter to 0000h (0=After Counter=FFFFh, 1=After Counter=Target)
+ 4 IRQ when Counter=Target (0=Disable, 1=Enable)
+ 5 IRQ when Counter=FFFFh (0=Disable, 1=Enable)
+ 6 IRQ Once/Repeat Mode (0=One-shot, 1=Repeatedly)
+ 7 IRQ Pulse/Toggle Mode (0=Short Bit10=0 Pulse, 1=Toggle Bit10 on/off)
+ 8-9 Clock Source (0-3, see list below)
+ Counter 0: 0 or 2 = System Clock, 1 or 3 = Dotclock
+ Counter 1: 0 or 2 = System Clock, 1 or 3 = Hblank
+ Counter 2: 0 or 1 = System Clock, 2 or 3 = System Clock/8
+ 10 Interrupt Request (0=Yes, 1=No) (Set after Writing) (W=1) (R)
+ 11 Reached Target Value (0=No, 1=Yes) (Reset after Reading) (R)
+ 12 Reached FFFFh Value (0=No, 1=Yes) (Reset after Reading) (R)
+ 13-15 Unknown (seems to be always zero)
+ 16-31 Garbage (next opcode)
+*/
+#define MODE_SYNCEN 0x0001
+#define MODE_SYNCMD 0x0006
+#define T0MD_HBLPAUSE 0
+#define T0MD_HBLRESET 1
+#define T0MD_HBLRANDP 2
+#define T0MD_HBLOSHOT 3
+// #define T1MD_VBLPAUSE 0
+// #define T1MD_VBLRESET 1
+// #define T1MD_VBLRANDP 2
+// #define T1MD_VBLOSHOT 3
+// #define T2MD_STOPMODE 0
+// #define T2MD_FREEMODE 1
+#define MODE_RESETC 0x0008
+#define MODE_TGTIRQ 0x0010
+#define MODE_MAXIRQ 0x0020
+#define MODE_IRQRMD 0x0040
+#define MODE_IRQPMD 0x0080
+#define MODE_CLK 0x0080
+
+/*
+ 0 Synchronization Enable (0=Free Run, 1=Synchronize via Bit1-2)
+ 1-2 Synchronization Mode (0-3, see lists below)
+ Synchronization Modes for Counter 0:
+ 0 = Pause counter during Hblank(s)
+ 1 = Reset counter to 0000h at Hblank(s)
+ 2 = Reset counter to 0000h at Hblank(s) and pause outside of Hblank
+ 3 = Pause until Hblank occurs once, then switch to Free Run
+ Synchronization Modes for Counter 1:
+ Same as above, but using Vblank instead of Hblank
+ Synchronization Modes for Counter 2:
+ 0 or 3 = Stop counter at current value (forever, no h/v-blank start)
+ 1 or 2 = Free Run (same as when Synchronization Disabled)
+ 3 Reset counter to 0000h (0=After Counter=FFFFh, 1=After Counter=Target)
+ 4 IRQ when Counter=Target (0=Disable, 1=Enable)
+ 5 IRQ when Counter=FFFFh (0=Disable, 1=Enable)
+ 6 IRQ Once/Repeat Mode (0=One-shot, 1=Repeatedly)
+ 7 IRQ Pulse/Toggle Mode (0=Short Bit10=0 Pulse, 1=Toggle Bit10 on/off)
+ 8-9 Clock Source (0-3, see list below)
+ Counter 0: 0 or 2 = System Clock, 1 or 3 = Dotclock
+ Counter 1: 0 or 2 = System Clock, 1 or 3 = Hblank
+ Counter 2: 0 or 1 = System Clock, 2 or 3 = System Clock/8
+ 10 Interrupt Request (0=Yes, 1=No) (Set after Writing) (W=1) (R)
+ 11 Reached Target Value (0=No, 1=Yes) (Reset after Reading) (R)
+ 12 Reached FFFFh Value (0=No, 1=Yes) (Reset after Reading) (R)
+ 13-15 Unknown (seems to be always zero)
+ 16-31 Garbage (next opcode)
+*/
+
struct psx_timer_t {uint32_t bus_delay;
uint32_t io_base, io_size;
-
- psx_ic_t* ic;
- psx_gpu_t* gpu;
-
- int hblank, prev_hblank;
- int vblank, prev_vblank;
-
- struct {
- float counter;
- uint32_t target;
- int sync_enable;
- int sync_mode;
- int reset_target;
- int irq_target;
- int irq_max;
- int irq_repeat;
- int irq_toggle;
- int clk_source;
- int irq;
- int target_reached;
- int max_reached;
- int irq_fired;
- uint32_t div_counter;
-
+
+ psx_ic_t* ic;
+ psx_gpu_t* gpu;
+
+ int hblank, prev_hblank;
+ int vblank, prev_vblank;
+
+ struct {+ float counter;
+ uint32_t target;
+ int sync_enable;
+ int sync_mode;
+ int reset_target;
+ int irq_target;
+ int irq_max;
+ int irq_repeat;
+ int irq_toggle;
+ int clk_source;
+ int irq;
+ int target_reached;
+ int max_reached;
+ int irq_fired;
+ uint32_t div_counter;
+
int paused;
int blank_once;
} timer[3];
@@ -119,22 +119,22 @@
};
typedef struct psx_timer_t psx_timer_t;
-
-psx_timer_t* psx_timer_create(void);
-void psx_timer_init(psx_timer_t*, psx_ic_t*, psx_gpu_t*);
-uint32_t psx_timer_read32(psx_timer_t*, uint32_t);
-uint16_t psx_timer_read16(psx_timer_t*, uint32_t);
-uint8_t psx_timer_read8(psx_timer_t*, uint32_t);
-void psx_timer_write32(psx_timer_t*, uint32_t, uint32_t);
-void psx_timer_write16(psx_timer_t*, uint32_t, uint16_t);
-void psx_timer_write8(psx_timer_t*, uint32_t, uint8_t);
-void psx_timer_update(psx_timer_t*, int);
-void psx_timer_destroy(psx_timer_t*);
-
-// GPU event handlers
-void psxe_gpu_hblank_event_cb(psx_gpu_t*);
-void psxe_gpu_hblank_end_event_cb(psx_gpu_t*);
-void psxe_gpu_vblank_timer_event_cb(psx_gpu_t*);
-void psxe_gpu_vblank_end_event_cb(psx_gpu_t*);
-
+
+psx_timer_t* psx_timer_create(void);
+void psx_timer_init(psx_timer_t*, psx_ic_t*, psx_gpu_t*);
+uint32_t psx_timer_read32(psx_timer_t*, uint32_t);
+uint16_t psx_timer_read16(psx_timer_t*, uint32_t);
+uint8_t psx_timer_read8(psx_timer_t*, uint32_t);
+void psx_timer_write32(psx_timer_t*, uint32_t, uint32_t);
+void psx_timer_write16(psx_timer_t*, uint32_t, uint16_t);
+void psx_timer_write8(psx_timer_t*, uint32_t, uint8_t);
+void psx_timer_update(psx_timer_t*, int);
+void psx_timer_destroy(psx_timer_t*);
+
+// GPU event handlers
+void psxe_gpu_hblank_event_cb(psx_gpu_t*);
+void psxe_gpu_hblank_end_event_cb(psx_gpu_t*);
+void psxe_gpu_vblank_timer_event_cb(psx_gpu_t*);
+void psxe_gpu_vblank_end_event_cb(psx_gpu_t*);
+
#endif
--- a/psx/dev/xa.c
+++ b/psx/dev/xa.c
@@ -1,12 +1,12 @@
-#include "dev/xa.h"
-
-#include "p9.h"
-
+#include "dev/xa.h"
+
+#include "p9.h"
+
void xa_decode_audio(uint8_t* src, uint16_t* dst) {USED(dst);
// Not a XA sector
if (src[XA_HDR_MODE] != 0x02)
return;
-
- // uint8_t ci = src[XA_SHDR_CODINGINFO];
+
+ // uint8_t ci = src[XA_SHDR_CODINGINFO];
}
--- a/psx/dev/xa.h
+++ b/psx/dev/xa.h
@@ -1,69 +1,69 @@
#ifndef PSX_DEV_XA_H
-#define PSX_DEV_XA_H
-
-/*
- 000h 0Ch Sync
- 00Ch 4 Header (Minute,Second,Sector,Mode=02h)
- 010h 4 Sub-Header (File, Channel, Submode with bit5=1, Codinginfo)
- 014h 4 Copy of Sub-Header
- 018h 914h Data (2324 bytes)
- 92Ch 4 EDC (checksum accross [010h..92Bh]) (or 00000000h if no EDC)
-*/
-
-enum {
- XA_HDR_MINUTE = 0x0c,
- XA_HDR_SECOND,
- XA_HDR_SECTOR,
- XA_HDR_MODE,
- XA_SHDR_FILE,
- XA_SHDR_CHANNEL,
- XA_SHDR_SUBMODE,
- XA_SHDR_CODINGINFO
-};
-
-/*
- 0 End of Record (EOR) (all Volume Descriptors, and all sectors with EOF)
- 1 Video ;\Sector Type (usually ONE of these bits should be set)
- 2 Audio ; Note: PSX .STR files are declared as Data (not as Video)
- 3 Data ;/
- 4 Trigger (for application use)
- 5 Form2 (0=Form1/800h-byte data, 1=Form2, 914h-byte data)
- 6 Real Time (RT)
- 7 End of File (EOF) (or end of Directory/PathTable/VolumeTerminator)
-*/
-
-enum {
- XA_SM_EOR = 0x01,
- XA_SM_VIDEO = 0x02,
- XA_SM_AUDIO = 0x04,
- XA_SM_DATA = 0x08,
- XA_SM_TRIG = 0x10,
- XA_SM_FORM2 = 0x20,
- XA_SM_RT = 0x40,
- XA_SM_EOF = 0x80
-};
-
-/*
- 0-1 Mono/Stereo (0=Mono, 1=Stereo, 2-3=Reserved)
- 2-2 Sample Rate (0=37800Hz, 1=18900Hz, 2-3=Reserved)
- 4-5 Bits per Sample (0=Normal/4bit, 1=8bit, 2-3=Reserved)
- 6 Emphasis (0=Normal/Off, 1=Emphasis)
- 7 Reserved (0)
-*/
-
-enum {
- XA_CI_MODE = 0x03,
- XA_CI_SAMPLERATE = 0x0c,
- XA_CI_BPS = 0x30,
- XA_CI_EMPHASIS = 0x40,
- XA_CI_MONO = 0x00,
- XA_CI_STEREO = 0x01,
- XA_CI_37800HZ = 0x00,
- XA_CI_18900HZ = 0x04,
- XA_CI_4BIT = 0x00,
- XA_CI_8BIT = 0x10
-};
-
-void xa_decode_sector(void*, void*);
-
+#define PSX_DEV_XA_H
+
+/*
+ 000h 0Ch Sync
+ 00Ch 4 Header (Minute,Second,Sector,Mode=02h)
+ 010h 4 Sub-Header (File, Channel, Submode with bit5=1, Codinginfo)
+ 014h 4 Copy of Sub-Header
+ 018h 914h Data (2324 bytes)
+ 92Ch 4 EDC (checksum accross [010h..92Bh]) (or 00000000h if no EDC)
+*/
+
+enum {+ XA_HDR_MINUTE = 0x0c,
+ XA_HDR_SECOND,
+ XA_HDR_SECTOR,
+ XA_HDR_MODE,
+ XA_SHDR_FILE,
+ XA_SHDR_CHANNEL,
+ XA_SHDR_SUBMODE,
+ XA_SHDR_CODINGINFO
+};
+
+/*
+ 0 End of Record (EOR) (all Volume Descriptors, and all sectors with EOF)
+ 1 Video ;\Sector Type (usually ONE of these bits should be set)
+ 2 Audio ; Note: PSX .STR files are declared as Data (not as Video)
+ 3 Data ;/
+ 4 Trigger (for application use)
+ 5 Form2 (0=Form1/800h-byte data, 1=Form2, 914h-byte data)
+ 6 Real Time (RT)
+ 7 End of File (EOF) (or end of Directory/PathTable/VolumeTerminator)
+*/
+
+enum {+ XA_SM_EOR = 0x01,
+ XA_SM_VIDEO = 0x02,
+ XA_SM_AUDIO = 0x04,
+ XA_SM_DATA = 0x08,
+ XA_SM_TRIG = 0x10,
+ XA_SM_FORM2 = 0x20,
+ XA_SM_RT = 0x40,
+ XA_SM_EOF = 0x80
+};
+
+/*
+ 0-1 Mono/Stereo (0=Mono, 1=Stereo, 2-3=Reserved)
+ 2-2 Sample Rate (0=37800Hz, 1=18900Hz, 2-3=Reserved)
+ 4-5 Bits per Sample (0=Normal/4bit, 1=8bit, 2-3=Reserved)
+ 6 Emphasis (0=Normal/Off, 1=Emphasis)
+ 7 Reserved (0)
+*/
+
+enum {+ XA_CI_MODE = 0x03,
+ XA_CI_SAMPLERATE = 0x0c,
+ XA_CI_BPS = 0x30,
+ XA_CI_EMPHASIS = 0x40,
+ XA_CI_MONO = 0x00,
+ XA_CI_STEREO = 0x01,
+ XA_CI_37800HZ = 0x00,
+ XA_CI_18900HZ = 0x04,
+ XA_CI_4BIT = 0x00,
+ XA_CI_8BIT = 0x10
+};
+
+void xa_decode_sector(void*, void*);
+
#endif
\ No newline at end of file
--- a/psx/exe.c
+++ b/psx/exe.c
@@ -53,14 +53,14 @@
// Load initial register values
cpu->pc = hdr.ipc;
- cpu->next_pc = cpu->pc + 4;
- cpu->r[28] = hdr.igp;
-
- if (hdr.ispb) {
- cpu->r[29] = hdr.ispb + hdr.ispoff;
- cpu->r[30] = cpu->r[29];
- }
-
+ cpu->next_pc = cpu->pc + 4;
+ cpu->r[28] = hdr.igp;
+
+ if (hdr.ispb) {+ cpu->r[29] = hdr.ispb + hdr.ispoff;
+ cpu->r[30] = cpu->r[29];
+ }
+
log_info("Loaded PS-X EXE file \"%s\"", path); log_fatal("PC=%08x SP=%08x (%08x) GP=%08x", cpu->pc, cpu->r[29], hdr.ispb, cpu->r[28]);--- a/psx/exe.h
+++ b/psx/exe.h
@@ -1,51 +1,51 @@
#ifndef PSX_EXE_H
#define PSX_EXE_H
-
-#include "p9.h"
-
-#include "cpu.h"
-#include "bus_init.h"
-
-/*
-PSX executables are having an 800h-byte header, followed by the code/data.
-
- 000h-007h ASCII ID "PS-X EXE"
- 008h-00Fh Zerofilled
- 010h Initial PC (usually 80010000h, or higher)
- 014h Initial GP/R28 (usually 0)
- 018h Destination Address in RAM (usually 80010000h, or higher)
- 01Ch Filesize (must be N*800h) (excluding 800h-byte header)
- 020h Unknown/Unused ;Addr (usually 0) ;\optional overlay?
- 024h Unknown/Unused ;Size (usually 0) ;/(not auto-loaded)
- 028h Memfill Start Address (usually 0) (when below Size=None)
- 02Ch Memfill Size in bytes (usually 0) (0=None)
- 030h Initial SP/R29 & FP/R30 Base (usually 801FFFF0h) (or 0=None)
- 034h Initial SP/R29 & FP/R30 Offs (usually 0, added to above Base)
- 038h-04Bh Reserved for A(43h) Function (should be zerofilled in exefile)
- 04Ch-xxxh ASCII marker
- "Sony Computer Entertainment Inc. for Japan area" ;NTSC
- "Sony Computer Entertainment Inc. for Europe area" ;PAL
- "Sony Computer Entertainment Inc. for North America area" ;NTSC
- (or often zerofilled in some homebrew files)
- (the BIOS doesn't verify this string, and boots fine without it)
- xxxh-7FFh Zerofilled
- 800h... Code/Data (loaded to entry[018h] and up)
-*/
-
-typedef struct {
- char id[16];
- uint32_t ipc;
- uint32_t igp;
- uint32_t ramdest;
- uint32_t filesz;
- uint32_t unk20;
- uint32_t unk24;
- uint32_t mfill_start;
- uint32_t mfill_size;
- uint32_t ispb;
- uint32_t ispoff;
-} psx_exe_hdr_t;
-
-int psx_exe_load(psx_cpu_t*, const char*);
-
+
+#include "p9.h"
+
+#include "cpu.h"
+#include "bus_init.h"
+
+/*
+PSX executables are having an 800h-byte header, followed by the code/data.
+
+ 000h-007h ASCII ID "PS-X EXE"
+ 008h-00Fh Zerofilled
+ 010h Initial PC (usually 80010000h, or higher)
+ 014h Initial GP/R28 (usually 0)
+ 018h Destination Address in RAM (usually 80010000h, or higher)
+ 01Ch Filesize (must be N*800h) (excluding 800h-byte header)
+ 020h Unknown/Unused ;Addr (usually 0) ;\optional overlay?
+ 024h Unknown/Unused ;Size (usually 0) ;/(not auto-loaded)
+ 028h Memfill Start Address (usually 0) (when below Size=None)
+ 02Ch Memfill Size in bytes (usually 0) (0=None)
+ 030h Initial SP/R29 & FP/R30 Base (usually 801FFFF0h) (or 0=None)
+ 034h Initial SP/R29 & FP/R30 Offs (usually 0, added to above Base)
+ 038h-04Bh Reserved for A(43h) Function (should be zerofilled in exefile)
+ 04Ch-xxxh ASCII marker
+ "Sony Computer Entertainment Inc. for Japan area" ;NTSC
+ "Sony Computer Entertainment Inc. for Europe area" ;PAL
+ "Sony Computer Entertainment Inc. for North America area" ;NTSC
+ (or often zerofilled in some homebrew files)
+ (the BIOS doesn't verify this string, and boots fine without it)
+ xxxh-7FFh Zerofilled
+ 800h... Code/Data (loaded to entry[018h] and up)
+*/
+
+typedef struct {+ char id[16];
+ uint32_t ipc;
+ uint32_t igp;
+ uint32_t ramdest;
+ uint32_t filesz;
+ uint32_t unk20;
+ uint32_t unk24;
+ uint32_t mfill_start;
+ uint32_t mfill_size;
+ uint32_t ispb;
+ uint32_t ispoff;
+} psx_exe_hdr_t;
+
+int psx_exe_load(psx_cpu_t*, const char*);
+
#endif
--- a/psx/input/sda.c
+++ b/psx/input/sda.c
@@ -1,154 +1,154 @@
-/*
- This file is part of the PSXE Emulator Project
-
- Sony PlayStation Standard Digital/Analog Controller Emulator
-*/
-
-#include "input/sda.h"
-#include "log.h"
-
-#include "p9.h"
-
-psxi_sda_t* psxi_sda_create(void) {
- return (psxi_sda_t*)malloc(sizeof(psxi_sda_t));
-}
-
-void psxi_sda_init(psxi_sda_t* sda, uint16_t model) {
- memset(sda, 0, sizeof(psxi_sda_t));
-
- sda->tx_data = 0xff;
- sda->tx_data_ready = 1;
- sda->prev_model = model;
- sda->model = model;
- sda->state = SDA_STATE_TX_HIZ;
- sda->sw = 0xffff;
- sda->sa_mode = SA_MODE_DIGITAL;
- sda->adc0 = 0x80;
- sda->adc1 = 0x80;
- sda->adc2 = 0x80;
- sda->adc3 = 0x80;
-}
-
-uint32_t psxi_sda_read(void* udata) {
- psxi_sda_t* sda = (psxi_sda_t*)udata;
-
- switch (sda->state) {
- case SDA_STATE_TX_HIZ: sda->tx_data = 0xff; break;
- case SDA_STATE_TX_IDL: sda->tx_data = sda->model; break;
- case SDA_STATE_TX_IDH: sda->tx_data = 0x5a; break;
- case SDA_STATE_TX_SWL: sda->tx_data = sda->sw & 0xff; break;
-
- // Digital pad stops sending data here
- case SDA_STATE_TX_SWH: {
- if (sda->sa_mode == SA_MODE_ANALOG) {
- sda->tx_data_ready = 1;
- sda->state = SDA_STATE_TX_ADC0;
- } else {
- sda->tx_data_ready = 0;
- sda->state = SDA_STATE_TX_HIZ;
- }
-
- return sda->sw >> 8;
- } break;
-
- case SDA_STATE_TX_ADC0: sda->tx_data = sda->adc0; break;
- case SDA_STATE_TX_ADC1: sda->tx_data = sda->adc1; break;
- case SDA_STATE_TX_ADC2: sda->tx_data = sda->adc2; break;
-
- // Analog pad stops sending data here
- case SDA_STATE_TX_ADC3: {
- sda->tx_data_ready = 0;
- sda->state = SDA_STATE_TX_HIZ;
-
- if (sda->model == 0xf3)
- sda->model = sda->prev_model;
-
- return sda->adc3;
- } break;
-
- }
-
- // printf(" sda read %u -> %02x\n", sda->state, sda->tx_data);
-
- sda->tx_data_ready = 1;
- sda->state++;
-
- return sda->tx_data;
-}
-
-void psxi_sda_write(void* udata, uint16_t data) {
- psxi_sda_t* sda = (psxi_sda_t*)udata;
-
- // To-do: Handle TAP and MOT bytes here
-
- if (data == 0x43) {
- if (sda->sa_mode == SA_MODE_ANALOG) {
- sda->prev_model = sda->model;
- sda->model = 0xf3;
- } else {
- sda->tx_data = 0xff;
- sda->tx_data_ready = 0;
- sda->state = SDA_STATE_TX_HIZ;
- }
- }
-}
-
-void psxi_sda_on_button_press(void* udata, uint32_t data) {
- psxi_sda_t* sda = (psxi_sda_t*)udata;
-
- if (data == PSXI_SW_SDA_ANALOG) {
- sda->sa_mode ^= 1;
-
- if (sda->sa_mode) {
- sda->prev_model = sda->model;
- sda->model = SDA_MODEL_ANALOG_STICK;
- } else {
- sda->model = sda->prev_model;
- }
-
- printf("sda: Switched to %s mode\n", sda->sa_mode ? "analog" : "digital");
-
- return;
- }
-
- sda->sw &= ~data;
-}
-
-void psxi_sda_on_button_release(void* udata, uint32_t data) {
- psxi_sda_t* sda = (psxi_sda_t*)udata;
-
- sda->sw |= data;
-}
-
-// To-do: Implement analog mode
-void psxi_sda_on_analog_change(void* udata, uint32_t axis, uint16_t data) {
- // Suppress warning until we implement analog mode
- psxi_sda_t* sda = (psxi_sda_t*)udata;
-
- switch (axis) {
- case PSXI_AX_SDA_RIGHT_HORZ: sda->adc0 = data; break;
- case PSXI_AX_SDA_RIGHT_VERT: sda->adc1 = data; break;
- case PSXI_AX_SDA_LEFT_HORZ: sda->adc2 = data; break;
- case PSXI_AX_SDA_LEFT_VERT: sda->adc3 = data; break;
- }
-}
-
-int psxi_sda_query_fifo(void* udata) {
- psxi_sda_t* sda = (psxi_sda_t*)udata;
-
- return sda->tx_data_ready;
-}
-
-void psxi_sda_init_input(psxi_sda_t* sda, psx_input_t* input) {
- input->udata = sda;
- input->write_func = psxi_sda_write;
- input->read_func = psxi_sda_read;
- input->on_button_press_func = psxi_sda_on_button_press;
- input->on_button_release_func = psxi_sda_on_button_release;
- input->on_analog_change_func = psxi_sda_on_analog_change;
- input->query_fifo_func = psxi_sda_query_fifo;
-}
-
-void psxi_sda_destroy(psxi_sda_t* sda) {
- free(sda);
+/*
+ This file is part of the PSXE Emulator Project
+
+ Sony PlayStation Standard Digital/Analog Controller Emulator
+*/
+
+#include "input/sda.h"
+#include "log.h"
+
+#include "p9.h"
+
+psxi_sda_t* psxi_sda_create(void) {+ return (psxi_sda_t*)malloc(sizeof(psxi_sda_t));
+}
+
+void psxi_sda_init(psxi_sda_t* sda, uint16_t model) {+ memset(sda, 0, sizeof(psxi_sda_t));
+
+ sda->tx_data = 0xff;
+ sda->tx_data_ready = 1;
+ sda->prev_model = model;
+ sda->model = model;
+ sda->state = SDA_STATE_TX_HIZ;
+ sda->sw = 0xffff;
+ sda->sa_mode = SA_MODE_DIGITAL;
+ sda->adc0 = 0x80;
+ sda->adc1 = 0x80;
+ sda->adc2 = 0x80;
+ sda->adc3 = 0x80;
+}
+
+uint32_t psxi_sda_read(void* udata) {+ psxi_sda_t* sda = (psxi_sda_t*)udata;
+
+ switch (sda->state) {+ case SDA_STATE_TX_HIZ: sda->tx_data = 0xff; break;
+ case SDA_STATE_TX_IDL: sda->tx_data = sda->model; break;
+ case SDA_STATE_TX_IDH: sda->tx_data = 0x5a; break;
+ case SDA_STATE_TX_SWL: sda->tx_data = sda->sw & 0xff; break;
+
+ // Digital pad stops sending data here
+ case SDA_STATE_TX_SWH: {+ if (sda->sa_mode == SA_MODE_ANALOG) {+ sda->tx_data_ready = 1;
+ sda->state = SDA_STATE_TX_ADC0;
+ } else {+ sda->tx_data_ready = 0;
+ sda->state = SDA_STATE_TX_HIZ;
+ }
+
+ return sda->sw >> 8;
+ } break;
+
+ case SDA_STATE_TX_ADC0: sda->tx_data = sda->adc0; break;
+ case SDA_STATE_TX_ADC1: sda->tx_data = sda->adc1; break;
+ case SDA_STATE_TX_ADC2: sda->tx_data = sda->adc2; break;
+
+ // Analog pad stops sending data here
+ case SDA_STATE_TX_ADC3: {+ sda->tx_data_ready = 0;
+ sda->state = SDA_STATE_TX_HIZ;
+
+ if (sda->model == 0xf3)
+ sda->model = sda->prev_model;
+
+ return sda->adc3;
+ } break;
+
+ }
+
+ // printf(" sda read %u -> %02x\n", sda->state, sda->tx_data);+
+ sda->tx_data_ready = 1;
+ sda->state++;
+
+ return sda->tx_data;
+}
+
+void psxi_sda_write(void* udata, uint16_t data) {+ psxi_sda_t* sda = (psxi_sda_t*)udata;
+
+ // To-do: Handle TAP and MOT bytes here
+
+ if (data == 0x43) {+ if (sda->sa_mode == SA_MODE_ANALOG) {+ sda->prev_model = sda->model;
+ sda->model = 0xf3;
+ } else {+ sda->tx_data = 0xff;
+ sda->tx_data_ready = 0;
+ sda->state = SDA_STATE_TX_HIZ;
+ }
+ }
+}
+
+void psxi_sda_on_button_press(void* udata, uint32_t data) {+ psxi_sda_t* sda = (psxi_sda_t*)udata;
+
+ if (data == PSXI_SW_SDA_ANALOG) {+ sda->sa_mode ^= 1;
+
+ if (sda->sa_mode) {+ sda->prev_model = sda->model;
+ sda->model = SDA_MODEL_ANALOG_STICK;
+ } else {+ sda->model = sda->prev_model;
+ }
+
+ printf("sda: Switched to %s mode\n", sda->sa_mode ? "analog" : "digital");+
+ return;
+ }
+
+ sda->sw &= ~data;
+}
+
+void psxi_sda_on_button_release(void* udata, uint32_t data) {+ psxi_sda_t* sda = (psxi_sda_t*)udata;
+
+ sda->sw |= data;
+}
+
+// To-do: Implement analog mode
+void psxi_sda_on_analog_change(void* udata, uint32_t axis, uint16_t data) {+ // Suppress warning until we implement analog mode
+ psxi_sda_t* sda = (psxi_sda_t*)udata;
+
+ switch (axis) {+ case PSXI_AX_SDA_RIGHT_HORZ: sda->adc0 = data; break;
+ case PSXI_AX_SDA_RIGHT_VERT: sda->adc1 = data; break;
+ case PSXI_AX_SDA_LEFT_HORZ: sda->adc2 = data; break;
+ case PSXI_AX_SDA_LEFT_VERT: sda->adc3 = data; break;
+ }
+}
+
+int psxi_sda_query_fifo(void* udata) {+ psxi_sda_t* sda = (psxi_sda_t*)udata;
+
+ return sda->tx_data_ready;
+}
+
+void psxi_sda_init_input(psxi_sda_t* sda, psx_input_t* input) {+ input->udata = sda;
+ input->write_func = psxi_sda_write;
+ input->read_func = psxi_sda_read;
+ input->on_button_press_func = psxi_sda_on_button_press;
+ input->on_button_release_func = psxi_sda_on_button_release;
+ input->on_analog_change_func = psxi_sda_on_analog_change;
+ input->query_fifo_func = psxi_sda_query_fifo;
+}
+
+void psxi_sda_destroy(psxi_sda_t* sda) {+ free(sda);
}
\ No newline at end of file
--- a/psx/input/sda.h
+++ b/psx/input/sda.h
@@ -1,75 +1,75 @@
-/*
- This file is part of the PSXE Emulator Project
-
- Sony PlayStation Standard Digital/Analog Controller Emulator
-*/
-
-#ifndef SDA_H
-#define SDA_H
-
-#include "dev/input.h"
-
-// Controller/Input IDs
-#define SDA_MODEL_DIGITAL 0x41
-#define SDA_MODEL_ANALOG_PAD 0x73
-#define SDA_MODEL_ANALOG_STICK 0x53
-
-#define PSXI_SW_SDA_SELECT 0x00000001
-#define PSXI_SW_SDA_L3 0x00000002
-#define PSXI_SW_SDA_R3 0x00000004
-#define PSXI_SW_SDA_START 0x00000008
-#define PSXI_SW_SDA_PAD_UP 0x00000010
-#define PSXI_SW_SDA_PAD_RIGHT 0x00000020
-#define PSXI_SW_SDA_PAD_DOWN 0x00000040
-#define PSXI_SW_SDA_PAD_LEFT 0x00000080
-#define PSXI_SW_SDA_L2 0x00000100
-#define PSXI_SW_SDA_R2 0x00000200
-#define PSXI_SW_SDA_L1 0x00000400
-#define PSXI_SW_SDA_R1 0x00000800
-#define PSXI_SW_SDA_TRIANGLE 0x00001000
-#define PSXI_SW_SDA_CIRCLE 0x00002000
-#define PSXI_SW_SDA_CROSS 0x00004000
-#define PSXI_SW_SDA_SQUARE 0x00008000
-#define PSXI_SW_SDA_ANALOG 0x00010000
-#define PSXI_AX_SDA_RIGHT_HORZ 0x00020000
-#define PSXI_AX_SDA_RIGHT_VERT 0x00030000
-#define PSXI_AX_SDA_LEFT_HORZ 0x00040000
-#define PSXI_AX_SDA_LEFT_VERT 0x00050000
-
-enum {
- SDA_STATE_TX_HIZ = 0,
- SDA_STATE_TX_IDL,
- SDA_STATE_TX_IDH,
- SDA_STATE_TX_SWL,
- SDA_STATE_TX_SWH,
- SDA_STATE_TX_ADC0,
- SDA_STATE_TX_ADC1,
- SDA_STATE_TX_ADC2,
- SDA_STATE_TX_ADC3
-};
-
-enum {
- SA_MODE_DIGITAL = 0,
- SA_MODE_ANALOG
-};
-
-typedef struct {
- uint8_t prev_model;
- uint8_t model;
- int state;
- int sa_mode;
- uint16_t sw;
- uint8_t tx_data;
- int tx_data_ready;
- uint8_t adc0;
- uint8_t adc1;
- uint8_t adc2;
- uint8_t adc3;
-} psxi_sda_t;
-
-psxi_sda_t* psxi_sda_create(void);
-void psxi_sda_init(psxi_sda_t*, uint16_t);
-void psxi_sda_init_input(psxi_sda_t*, psx_input_t*);
-void psxi_sda_destroy(psxi_sda_t*);
-
+/*
+ This file is part of the PSXE Emulator Project
+
+ Sony PlayStation Standard Digital/Analog Controller Emulator
+*/
+
+#ifndef SDA_H
+#define SDA_H
+
+#include "dev/input.h"
+
+// Controller/Input IDs
+#define SDA_MODEL_DIGITAL 0x41
+#define SDA_MODEL_ANALOG_PAD 0x73
+#define SDA_MODEL_ANALOG_STICK 0x53
+
+#define PSXI_SW_SDA_SELECT 0x00000001
+#define PSXI_SW_SDA_L3 0x00000002
+#define PSXI_SW_SDA_R3 0x00000004
+#define PSXI_SW_SDA_START 0x00000008
+#define PSXI_SW_SDA_PAD_UP 0x00000010
+#define PSXI_SW_SDA_PAD_RIGHT 0x00000020
+#define PSXI_SW_SDA_PAD_DOWN 0x00000040
+#define PSXI_SW_SDA_PAD_LEFT 0x00000080
+#define PSXI_SW_SDA_L2 0x00000100
+#define PSXI_SW_SDA_R2 0x00000200
+#define PSXI_SW_SDA_L1 0x00000400
+#define PSXI_SW_SDA_R1 0x00000800
+#define PSXI_SW_SDA_TRIANGLE 0x00001000
+#define PSXI_SW_SDA_CIRCLE 0x00002000
+#define PSXI_SW_SDA_CROSS 0x00004000
+#define PSXI_SW_SDA_SQUARE 0x00008000
+#define PSXI_SW_SDA_ANALOG 0x00010000
+#define PSXI_AX_SDA_RIGHT_HORZ 0x00020000
+#define PSXI_AX_SDA_RIGHT_VERT 0x00030000
+#define PSXI_AX_SDA_LEFT_HORZ 0x00040000
+#define PSXI_AX_SDA_LEFT_VERT 0x00050000
+
+enum {+ SDA_STATE_TX_HIZ = 0,
+ SDA_STATE_TX_IDL,
+ SDA_STATE_TX_IDH,
+ SDA_STATE_TX_SWL,
+ SDA_STATE_TX_SWH,
+ SDA_STATE_TX_ADC0,
+ SDA_STATE_TX_ADC1,
+ SDA_STATE_TX_ADC2,
+ SDA_STATE_TX_ADC3
+};
+
+enum {+ SA_MODE_DIGITAL = 0,
+ SA_MODE_ANALOG
+};
+
+typedef struct {+ uint8_t prev_model;
+ uint8_t model;
+ int state;
+ int sa_mode;
+ uint16_t sw;
+ uint8_t tx_data;
+ int tx_data_ready;
+ uint8_t adc0;
+ uint8_t adc1;
+ uint8_t adc2;
+ uint8_t adc3;
+} psxi_sda_t;
+
+psxi_sda_t* psxi_sda_create(void);
+void psxi_sda_init(psxi_sda_t*, uint16_t);
+void psxi_sda_init_input(psxi_sda_t*, psx_input_t*);
+void psxi_sda_destroy(psxi_sda_t*);
+
#endif
\ No newline at end of file
--- a/psx/psx.c
+++ b/psx/psx.c
@@ -1,5 +1,4 @@
#include "psx.h"
-#include "dat.h"
#include "dev/bios.h"
#include "dev/ram.h"
#include "dev/dma.h"
@@ -18,208 +17,208 @@
#include "dev/mdec.h"
psx_t* psx_create(void) {- return (psx_t*)malloc(sizeof(psx_t));
-}
-
-int psx_load_bios(psx_t* psx, const char* path) {
- return psx_bios_load(psx->bios, path);
-}
-
+ return (psx_t*)malloc(sizeof(psx_t));
+}
+
+int psx_load_bios(psx_t* psx, const char* path) {+ return psx_bios_load(psx->bios, path);
+}
+
void psx_load_state(psx_t* psx, const char* path) {USED(psx);
USED(path);
log_fatal("State saving/loading is not yet supported");-
- exit(1);
-}
-
+
+ exit(1);
+}
+
void psx_save_state(psx_t* psx, const char* path) {USED(psx);
USED(path);
log_fatal("State saving/loading is not yet supported");-
- exit(1);
-}
-
-void psx_load_exe(psx_t* psx, const char* path) {
- psx_exe_load(psx->cpu, path);
-}
-
-void psx_update(psx_t* psx) {
- psx_cpu_cycle(psx->cpu);
-
- psx_cdrom_update(psx->cdrom, psx->cpu->last_cycles);
- psx_gpu_update(psx->gpu, psx->cpu->last_cycles);
- psx_pad_update(psx->pad, psx->cpu->last_cycles);
- psx_timer_update(psx->timer, psx->cpu->last_cycles);
- psx_dma_update(psx->dma, psx->cpu->last_cycles);
-}
-
-void psx_run_frame(psx_t* psx) {
- // NTSC: 59.29 Hz, PAL: 49.76 Hz
- float framerate = (psx->gpu->display_mode & 0x8) ? 59.29 : 49.76;
-
- unsigned int counter = (float)PSX_CPU_CPS / framerate;
-
- while (counter--) {
- psx_update(psx);
- }
-}
-
-void* psx_get_display_buffer(psx_t* psx) {
- return psx_gpu_get_display_buffer(psx->gpu);
-}
-
-void* psx_get_vram(psx_t* psx) {
- return psx->gpu->vram;
-}
-
-uint32_t psx_get_display_width(psx_t* psx) {
- int width = psx_get_dmode_width(psx);
-
- if (width == 368)
- width = 384;
-
- return width;
-}
-
-uint32_t psx_get_display_height(psx_t* psx) {
- return psx_get_dmode_height(psx);
-}
-
-uint32_t psx_get_display_format(psx_t* psx) {
- return (psx->gpu->display_mode >> 4) & 1;
-}
-
-uint32_t psx_get_dmode_width(psx_t* psx) {
- static int dmode_hres_table[] = {
- 256, 320, 512, 640
- };
-
- if (psx->gpu->display_mode & 0x40) {
- return 368;
- } else {
- return dmode_hres_table[psx->gpu->display_mode & 0x3];
- }
-}
-
-uint32_t psx_get_dmode_height(psx_t* psx) {
- if (psx->gpu->display_mode & 0x4)
- return 480;
-
- int disp = psx->gpu->disp_y2 - psx->gpu->disp_y1;
-
- if (disp < (255-16))
- return disp;
-
- return 240;
-}
-
-double psx_get_display_aspect(psx_t* psx) {
- double width = psx_get_dmode_width(psx);
- double height = psx_get_dmode_height(psx);
-
- if (height > width)
- return 4.0 / 3.0;
-
- double aspect = width / height;
-
- if (aspect > (4.0 / 3.0))
- return 4.0 / 3.0;
-
- return aspect;
-}
-
+
+ exit(1);
+}
+
+void psx_load_exe(psx_t* psx, const char* path) {+ psx_exe_load(psx->cpu, path);
+}
+
+void psx_update(psx_t* psx) {+ psx_cpu_cycle(psx->cpu);
+
+ psx_cdrom_update(psx->cdrom, psx->cpu->last_cycles);
+ psx_gpu_update(psx->gpu, psx->cpu->last_cycles);
+ psx_pad_update(psx->pad, psx->cpu->last_cycles);
+ psx_timer_update(psx->timer, psx->cpu->last_cycles);
+ psx_dma_update(psx->dma, psx->cpu->last_cycles);
+}
+
+void psx_run_frame(psx_t* psx) {+ // NTSC: 59.29 Hz, PAL: 49.76 Hz
+ float framerate = (psx->gpu->display_mode & 0x8) ? 59.29 : 49.76;
+
+ unsigned int counter = (float)PSX_CPU_CPS / framerate;
+
+ while (counter--) {+ psx_update(psx);
+ }
+}
+
+void* psx_get_display_buffer(psx_t* psx) {+ return psx_gpu_get_display_buffer(psx->gpu);
+}
+
+void* psx_get_vram(psx_t* psx) {+ return psx->gpu->vram;
+}
+
+uint32_t psx_get_display_width(psx_t* psx) {+ int width = psx_get_dmode_width(psx);
+
+ if (width == 368)
+ width = 384;
+
+ return width;
+}
+
+uint32_t psx_get_display_height(psx_t* psx) {+ return psx_get_dmode_height(psx);
+}
+
+uint32_t psx_get_display_format(psx_t* psx) {+ return (psx->gpu->display_mode >> 4) & 1;
+}
+
+uint32_t psx_get_dmode_width(psx_t* psx) {+ static int dmode_hres_table[] = {+ 256, 320, 512, 640
+ };
+
+ if (psx->gpu->display_mode & 0x40) {+ return 368;
+ } else {+ return dmode_hres_table[psx->gpu->display_mode & 0x3];
+ }
+}
+
+uint32_t psx_get_dmode_height(psx_t* psx) {+ if (psx->gpu->display_mode & 0x4)
+ return 480;
+
+ int disp = psx->gpu->disp_y2 - psx->gpu->disp_y1;
+
+ if (disp < (255-16))
+ return disp;
+
+ return 240;
+}
+
+double psx_get_display_aspect(psx_t* psx) {+ double width = psx_get_dmode_width(psx);
+ double height = psx_get_dmode_height(psx);
+
+ if (height > width)
+ return 4.0 / 3.0;
+
+ double aspect = width / height;
+
+ if (aspect > (4.0 / 3.0))
+ return 4.0 / 3.0;
+
+ return aspect;
+}
+
void atcons_tx(void* udata, unsigned char c) {USED(udata);
putchar(c);
}
-
-int psx_init(psx_t* psx, const char* bios_path, const char* exp_path) {
- memset(psx, 0, sizeof(psx_t));
-
- psx->bios = psx_bios_create();
- psx->ram = psx_ram_create();
- psx->dma = psx_dma_create();
- psx->exp1 = psx_exp1_create();
- psx->exp2 = psx_exp2_create();
- psx->mc1 = psx_mc1_create();
- psx->mc2 = psx_mc2_create();
- psx->mc3 = psx_mc3_create();
- psx->ic = psx_ic_create();
- psx->scratchpad = psx_scratchpad_create();
- psx->gpu = psx_gpu_create();
- psx->spu = psx_spu_create();
- psx->bus = psx_bus_create();
- psx->cpu = psx_cpu_create();
- psx->timer = psx_timer_create();
- psx->cdrom = psx_cdrom_create();
- psx->pad = psx_pad_create();
- psx->mdec = psx_mdec_create();
-
- psx_bus_init(psx->bus);
-
- psx_bus_init_bios(psx->bus, psx->bios);
- psx_bus_init_ram(psx->bus, psx->ram);
- psx_bus_init_dma(psx->bus, psx->dma);
- psx_bus_init_exp1(psx->bus, psx->exp1);
- psx_bus_init_exp2(psx->bus, psx->exp2);
- psx_bus_init_mc1(psx->bus, psx->mc1);
- psx_bus_init_mc2(psx->bus, psx->mc2);
- psx_bus_init_mc3(psx->bus, psx->mc3);
- psx_bus_init_ic(psx->bus, psx->ic);
- psx_bus_init_scratchpad(psx->bus, psx->scratchpad);
- psx_bus_init_gpu(psx->bus, psx->gpu);
- psx_bus_init_spu(psx->bus, psx->spu);
- psx_bus_init_timer(psx->bus, psx->timer);
- psx_bus_init_cdrom(psx->bus, psx->cdrom);
- psx_bus_init_pad(psx->bus, psx->pad);
- psx_bus_init_mdec(psx->bus, psx->mdec);
-
- // Init devices
- psx_bios_init(psx->bios);
-
- if (psx_bios_load(psx->bios, bios_path))
- return 1;
-
- psx_mc1_init(psx->mc1);
- psx_mc2_init(psx->mc2);
- psx_mc3_init(psx->mc3);
- psx_ram_init(psx->ram, psx->mc2, RAM_SIZE_2MB);
- psx_dma_init(psx->dma, psx->bus, psx->ic);
-
- if (psx_exp1_init(psx->exp1, psx->mc1, exp_path))
- return 2;
-
- psx_exp2_init(psx->exp2, atcons_tx, NULL);
- psx_ic_init(psx->ic, psx->cpu);
- psx_scratchpad_init(psx->scratchpad);
- psx_gpu_init(psx->gpu, psx->ic);
- psx_spu_init(psx->spu, psx->ic);
- psx_timer_init(psx->timer, psx->ic, psx->gpu);
- psx_cdrom_init(psx->cdrom, psx->ic);
- psx_pad_init(psx->pad, psx->ic);
- psx_mdec_init(psx->mdec);
- psx_cpu_init(psx->cpu, psx->bus);
-
- return 0;
-}
-
-int psx_load_expansion(psx_t* psx, const char* path) {
- return psx_exp1_init(psx->exp1, psx->mc1, path);
-}
-
+
+int psx_init(psx_t* psx, const char* bios_path, const char* exp_path) {+ memset(psx, 0, sizeof(psx_t));
+
+ psx->bios = psx_bios_create();
+ psx->ram = psx_ram_create();
+ psx->dma = psx_dma_create();
+ psx->exp1 = psx_exp1_create();
+ psx->exp2 = psx_exp2_create();
+ psx->mc1 = psx_mc1_create();
+ psx->mc2 = psx_mc2_create();
+ psx->mc3 = psx_mc3_create();
+ psx->ic = psx_ic_create();
+ psx->scratchpad = psx_scratchpad_create();
+ psx->gpu = psx_gpu_create();
+ psx->spu = psx_spu_create();
+ psx->bus = psx_bus_create();
+ psx->cpu = psx_cpu_create();
+ psx->timer = psx_timer_create();
+ psx->cdrom = psx_cdrom_create();
+ psx->pad = psx_pad_create();
+ psx->mdec = psx_mdec_create();
+
+ psx_bus_init(psx->bus);
+
+ psx_bus_init_bios(psx->bus, psx->bios);
+ psx_bus_init_ram(psx->bus, psx->ram);
+ psx_bus_init_dma(psx->bus, psx->dma);
+ psx_bus_init_exp1(psx->bus, psx->exp1);
+ psx_bus_init_exp2(psx->bus, psx->exp2);
+ psx_bus_init_mc1(psx->bus, psx->mc1);
+ psx_bus_init_mc2(psx->bus, psx->mc2);
+ psx_bus_init_mc3(psx->bus, psx->mc3);
+ psx_bus_init_ic(psx->bus, psx->ic);
+ psx_bus_init_scratchpad(psx->bus, psx->scratchpad);
+ psx_bus_init_gpu(psx->bus, psx->gpu);
+ psx_bus_init_spu(psx->bus, psx->spu);
+ psx_bus_init_timer(psx->bus, psx->timer);
+ psx_bus_init_cdrom(psx->bus, psx->cdrom);
+ psx_bus_init_pad(psx->bus, psx->pad);
+ psx_bus_init_mdec(psx->bus, psx->mdec);
+
+ // Init devices
+ psx_bios_init(psx->bios);
+
+ if (psx_bios_load(psx->bios, bios_path))
+ return 1;
+
+ psx_mc1_init(psx->mc1);
+ psx_mc2_init(psx->mc2);
+ psx_mc3_init(psx->mc3);
+ psx_ram_init(psx->ram, psx->mc2, RAM_SIZE_2MB);
+ psx_dma_init(psx->dma, psx->bus, psx->ic);
+
+ if (psx_exp1_init(psx->exp1, psx->mc1, exp_path))
+ return 2;
+
+ psx_exp2_init(psx->exp2, atcons_tx, NULL);
+ psx_ic_init(psx->ic, psx->cpu);
+ psx_scratchpad_init(psx->scratchpad);
+ psx_gpu_init(psx->gpu, psx->ic);
+ psx_spu_init(psx->spu, psx->ic);
+ psx_timer_init(psx->timer, psx->ic, psx->gpu);
+ psx_cdrom_init(psx->cdrom, psx->ic);
+ psx_pad_init(psx->pad, psx->ic);
+ psx_mdec_init(psx->mdec);
+ psx_cpu_init(psx->cpu, psx->bus);
+
+ return 0;
+}
+
+int psx_load_expansion(psx_t* psx, const char* path) {+ return psx_exp1_init(psx->exp1, psx->mc1, path);
+}
+
void psx_hard_reset(psx_t* psx) {USED(psx);
log_fatal("Hard reset not yet implemented");-
- exit(1);
-}
-
-void psx_soft_reset(psx_t* psx) {
- psx_cpu_init(psx->cpu, psx->bus);
-}
-
+
+ exit(1);
+}
+
+void psx_soft_reset(psx_t* psx) {+ psx_cpu_init(psx->cpu, psx->bus);
+}
+
uint32_t* psx_take_screenshot(psx_t* psx) {USED(psx);
log_fatal("Screenshots not yet supported");@@ -227,108 +226,108 @@
exit(1);
return nil;
}
-
-int psx_swap_disc(psx_t* psx, const char* path) {
- psx_cdrom_destroy(psx->cdrom);
-
- psx->cdrom = psx_cdrom_create();
-
- psx_bus_init_cdrom(psx->bus, psx->cdrom);
-
- psx_cdrom_init(psx->cdrom, psx->ic);
-
- return psx_cdrom_open(psx->cdrom, path);
-}
-
-void psx_destroy(psx_t* psx) {
- psx_cpu_destroy(psx->cpu);
- psx_bios_destroy(psx->bios);
- psx_bus_destroy(psx->bus);
- psx_ram_destroy(psx->ram);
- psx_exp1_destroy(psx->exp1);
- psx_mc1_destroy(psx->mc1);
- psx_mc2_destroy(psx->mc2);
- psx_mc3_destroy(psx->mc3);
- psx_ic_destroy(psx->ic);
- psx_scratchpad_destroy(psx->scratchpad);
- psx_gpu_destroy(psx->gpu);
- psx_spu_destroy(psx->spu);
- psx_timer_destroy(psx->timer);
- psx_cdrom_destroy(psx->cdrom);
- psx_pad_destroy(psx->pad);
- psx_mdec_destroy(psx->mdec);
-
- free(psx);
-}
-
-psx_bios_t* psx_get_bios(psx_t* psx) {
- return psx->bios;
-}
-
-psx_ram_t* psx_get_ram(psx_t* psx) {
- return psx->ram;
-}
-
-psx_dma_t* psx_get_dma(psx_t* psx) {
- return psx->dma;
-}
-
-psx_exp1_t* psx_get_exp1(psx_t* psx) {
- return psx->exp1;
-}
-
-psx_exp2_t* psx_get_exp2(psx_t* psx) {
- return psx->exp2;
-}
-
-psx_mc1_t* psx_get_mc1(psx_t* psx) {
- return psx->mc1;
-}
-
-psx_mc2_t* psx_get_mc2(psx_t* psx) {
- return psx->mc2;
-}
-
-psx_mc3_t* psx_get_mc3(psx_t* psx) {
- return psx->mc3;
-}
-
-psx_ic_t* psx_get_ic(psx_t* psx) {
- return psx->ic;
-}
-
-psx_scratchpad_t* psx_get_scratchpad(psx_t* psx) {
- return psx->scratchpad;
-}
-
-psx_gpu_t* psx_get_gpu(psx_t* psx) {
- return psx->gpu;
-}
-
-psx_spu_t* psx_get_spu(psx_t* psx) {
- return psx->spu;
-}
-
-psx_bus_t* psx_get_bus(psx_t* psx) {
- return psx->bus;
-}
-
-psx_timer_t* psx_get_timer(psx_t* psx) {
- return psx->timer;
-}
-
-psx_cdrom_t* psx_get_cdrom(psx_t* psx) {
- return psx->cdrom;
-}
-
-psx_pad_t* psx_get_pad(psx_t* psx) {
- return psx->pad;
-}
-
-psx_mdec_t* psx_get_mdec(psx_t* psx) {
- return psx->mdec;
-}
-
-psx_cpu_t* psx_get_cpu(psx_t* psx) {
- return psx->cpu;
+
+int psx_swap_disc(psx_t* psx, const char* path) {+ psx_cdrom_destroy(psx->cdrom);
+
+ psx->cdrom = psx_cdrom_create();
+
+ psx_bus_init_cdrom(psx->bus, psx->cdrom);
+
+ psx_cdrom_init(psx->cdrom, psx->ic);
+
+ return psx_cdrom_open(psx->cdrom, path);
+}
+
+void psx_destroy(psx_t* psx) {+ psx_cpu_destroy(psx->cpu);
+ psx_bios_destroy(psx->bios);
+ psx_bus_destroy(psx->bus);
+ psx_ram_destroy(psx->ram);
+ psx_exp1_destroy(psx->exp1);
+ psx_mc1_destroy(psx->mc1);
+ psx_mc2_destroy(psx->mc2);
+ psx_mc3_destroy(psx->mc3);
+ psx_ic_destroy(psx->ic);
+ psx_scratchpad_destroy(psx->scratchpad);
+ psx_gpu_destroy(psx->gpu);
+ psx_spu_destroy(psx->spu);
+ psx_timer_destroy(psx->timer);
+ psx_cdrom_destroy(psx->cdrom);
+ psx_pad_destroy(psx->pad);
+ psx_mdec_destroy(psx->mdec);
+
+ free(psx);
+}
+
+psx_bios_t* psx_get_bios(psx_t* psx) {+ return psx->bios;
+}
+
+psx_ram_t* psx_get_ram(psx_t* psx) {+ return psx->ram;
+}
+
+psx_dma_t* psx_get_dma(psx_t* psx) {+ return psx->dma;
+}
+
+psx_exp1_t* psx_get_exp1(psx_t* psx) {+ return psx->exp1;
+}
+
+psx_exp2_t* psx_get_exp2(psx_t* psx) {+ return psx->exp2;
+}
+
+psx_mc1_t* psx_get_mc1(psx_t* psx) {+ return psx->mc1;
+}
+
+psx_mc2_t* psx_get_mc2(psx_t* psx) {+ return psx->mc2;
+}
+
+psx_mc3_t* psx_get_mc3(psx_t* psx) {+ return psx->mc3;
+}
+
+psx_ic_t* psx_get_ic(psx_t* psx) {+ return psx->ic;
+}
+
+psx_scratchpad_t* psx_get_scratchpad(psx_t* psx) {+ return psx->scratchpad;
+}
+
+psx_gpu_t* psx_get_gpu(psx_t* psx) {+ return psx->gpu;
+}
+
+psx_spu_t* psx_get_spu(psx_t* psx) {+ return psx->spu;
+}
+
+psx_bus_t* psx_get_bus(psx_t* psx) {+ return psx->bus;
+}
+
+psx_timer_t* psx_get_timer(psx_t* psx) {+ return psx->timer;
+}
+
+psx_cdrom_t* psx_get_cdrom(psx_t* psx) {+ return psx->cdrom;
+}
+
+psx_pad_t* psx_get_pad(psx_t* psx) {+ return psx->pad;
+}
+
+psx_mdec_t* psx_get_mdec(psx_t* psx) {+ return psx->mdec;
+}
+
+psx_cpu_t* psx_get_cpu(psx_t* psx) {+ return psx->cpu;
}
--- a/psx/psx.h
+++ b/psx/psx.h
@@ -1,79 +1,87 @@
#ifndef PSX_PSX_H
#define PSX_PSX_H
-
-#include "cpu.h"
-#include "log.h"
-#include "exe.h"
-
-#include "p9.h"
-
-#define STR1(m) #m
-#define STR(m) STR1(m)
-
-#define PSXE_VERSION STR(REP_VERSION)
-#define PSXE_COMMIT STR(REP_COMMIT_HASH)
-#define PSXE_BUILD_OS STR(OS_INFO)
-
+
+#include "cpu.h"
+#include "log.h"
+#include "exe.h"
+
+#include "p9.h"
+
+#define STR1(m) #m
+#define STR(m) STR1(m)
+
+#define PSXE_VERSION STR(REP_VERSION)
+#define PSXE_COMMIT STR(REP_COMMIT_HASH)
+#define PSXE_BUILD_OS STR(OS_INFO)
+
typedef struct psx_t {psx_bios_t* bios;
psx_ram_t* ram;
psx_dma_t* dma;
- psx_exp1_t* exp1;
- psx_exp2_t* exp2;
- psx_mc1_t* mc1;
- psx_mc2_t* mc2;
- psx_mc3_t* mc3;
- psx_ic_t* ic;
- psx_scratchpad_t* scratchpad;
- psx_gpu_t* gpu;
- psx_spu_t* spu;
- psx_bus_t* bus;
- psx_cpu_t* cpu;
- psx_timer_t* timer;
+ psx_exp1_t* exp1;
+ psx_exp2_t* exp2;
+ psx_mc1_t* mc1;
+ psx_mc2_t* mc2;
+ psx_mc3_t* mc3;
+ psx_ic_t* ic;
+ psx_scratchpad_t* scratchpad;
+ psx_gpu_t* gpu;
+ psx_spu_t* spu;
+ psx_bus_t* bus;
+ psx_cpu_t* cpu;
+ psx_timer_t* timer;
psx_cdrom_t* cdrom;
psx_pad_t* pad;
psx_mdec_t* mdec;
} psx_t;
-
-psx_t* psx_create(void);
-int psx_init(psx_t*, const char*, const char*);
-int psx_load_expansion(psx_t*, const char*);
-int psx_load_bios(psx_t*, const char*);
-void psx_hard_reset(psx_t*);
-void psx_soft_reset(psx_t*);
-void psx_load_state(psx_t*, const char*);
-void psx_save_state(psx_t*, const char*);
-void psx_load_exe(psx_t*, const char*);
-void psx_update(psx_t*);
-void psx_run_frame(psx_t*);
-void* psx_get_display_buffer(psx_t*);
-void* psx_get_vram(psx_t*);
-uint32_t psx_get_dmode_width(psx_t*);
-uint32_t psx_get_dmode_height(psx_t*);
-uint32_t psx_get_display_width(psx_t*);
-uint32_t psx_get_display_height(psx_t*);
-uint32_t psx_get_display_format(psx_t*);
-double psx_get_display_aspect(psx_t*);
-uint32_t* psx_take_screenshot(psx_t*);
-int psx_swap_disc(psx_t*, const char*);
-psx_bios_t* psx_get_bios(psx_t*);
-psx_ram_t* psx_get_ram(psx_t*);
-psx_dma_t* psx_get_dma(psx_t*);
-psx_exp1_t* psx_get_exp1(psx_t*);
-psx_exp2_t* psx_get_exp2(psx_t*);
-psx_mc1_t* psx_get_mc1(psx_t*);
-psx_mc2_t* psx_get_mc2(psx_t*);
-psx_mc3_t* psx_get_mc3(psx_t*);
-psx_ic_t* psx_get_ic(psx_t*);
-psx_scratchpad_t* psx_get_scratchpad(psx_t*);
-psx_gpu_t* psx_get_gpu(psx_t*);
-psx_spu_t* psx_get_spu(psx_t*);
-psx_bus_t* psx_get_bus(psx_t*);
-psx_timer_t* psx_get_timer(psx_t*);
-psx_cdrom_t* psx_get_cdrom(psx_t*);
-psx_pad_t* psx_get_pad(psx_t*);
-psx_mdec_t* psx_get_mdec(psx_t*);
-psx_cpu_t* psx_get_cpu(psx_t*);
-void psx_destroy(psx_t*);
-
+
+/*
+ * 9front/6c: keep these SPU lifecycle declarations in the core umbrella header.
+ * Do not move them back to a .c file; psx.c must always see these prototypes.
+ */
+psx_spu_t* psx_spu_create(void);
+void psx_spu_init(psx_spu_t*, psx_ic_t*);
+void psx_spu_destroy(psx_spu_t*);
+
+psx_t* psx_create(void);
+int psx_init(psx_t*, const char*, const char*);
+int psx_load_expansion(psx_t*, const char*);
+int psx_load_bios(psx_t*, const char*);
+void psx_hard_reset(psx_t*);
+void psx_soft_reset(psx_t*);
+void psx_load_state(psx_t*, const char*);
+void psx_save_state(psx_t*, const char*);
+void psx_load_exe(psx_t*, const char*);
+void psx_update(psx_t*);
+void psx_run_frame(psx_t*);
+void* psx_get_display_buffer(psx_t*);
+void* psx_get_vram(psx_t*);
+uint32_t psx_get_dmode_width(psx_t*);
+uint32_t psx_get_dmode_height(psx_t*);
+uint32_t psx_get_display_width(psx_t*);
+uint32_t psx_get_display_height(psx_t*);
+uint32_t psx_get_display_format(psx_t*);
+double psx_get_display_aspect(psx_t*);
+uint32_t* psx_take_screenshot(psx_t*);
+int psx_swap_disc(psx_t*, const char*);
+psx_bios_t* psx_get_bios(psx_t*);
+psx_ram_t* psx_get_ram(psx_t*);
+psx_dma_t* psx_get_dma(psx_t*);
+psx_exp1_t* psx_get_exp1(psx_t*);
+psx_exp2_t* psx_get_exp2(psx_t*);
+psx_mc1_t* psx_get_mc1(psx_t*);
+psx_mc2_t* psx_get_mc2(psx_t*);
+psx_mc3_t* psx_get_mc3(psx_t*);
+psx_ic_t* psx_get_ic(psx_t*);
+psx_scratchpad_t* psx_get_scratchpad(psx_t*);
+psx_gpu_t* psx_get_gpu(psx_t*);
+psx_spu_t* psx_get_spu(psx_t*);
+psx_bus_t* psx_get_bus(psx_t*);
+psx_timer_t* psx_get_timer(psx_t*);
+psx_cdrom_t* psx_get_cdrom(psx_t*);
+psx_pad_t* psx_get_pad(psx_t*);
+psx_mdec_t* psx_get_mdec(psx_t*);
+psx_cpu_t* psx_get_cpu(psx_t*);
+void psx_destroy(psx_t*);
+
#endif
--
⑨