Merge branch 'master' into feature/zip-support

This commit is contained in:
WaluigiWare64 2020-10-23 00:39:29 +01:00 committed by GitHub
commit 8d70d0926c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
85 changed files with 2651 additions and 999 deletions

View File

@ -20,8 +20,10 @@ jobs:
- name: Upgrade system - name: Upgrade system
shell: bash shell: bash
working-directory: ${{runner.workspace}} working-directory: ${{runner.workspace}}
run: | run: | #Fix grub installation error - https://github.com/actions/virtual-environments/issues/1605
sudo apt update sudo apt update
sudo apt-get install grub-efi
sudo update-grub
sudo apt full-upgrade sudo apt full-upgrade
- name: Install dependencies - name: Install dependencies
shell: bash shell: bash
@ -32,7 +34,8 @@ jobs:
sudo rm /etc/apt/sources.list sudo rm /etc/apt/sources.list
sudo mv /etc/apt/sources.list{.new,} sudo mv /etc/apt/sources.list{.new,}
sudo apt update sudo apt update
sudo apt install {gcc-10,g++-10,pkg-config}-aarch64-linux-gnu libsdl2-dev:arm64 qtbase5-dev:arm64 libslirp-dev:arm64 libzip-dev:arm64 sudo apt install aptitude
sudo aptitude install -y {gcc-10,g++-10,pkg-config}-aarch64-linux-gnu libsdl2-dev:arm64 qtbase5-dev:arm64 libslirp-dev:arm64 libarchive-dev:arm64
- name: Create build environment - name: Create build environment
run: mkdir ${{runner.workspace}}/build run: mkdir ${{runner.workspace}}/build
- name: Configure - name: Configure

View File

@ -24,8 +24,8 @@ jobs:
working-directory: ${{runner.workspace}} working-directory: ${{runner.workspace}}
run: | # Fetch a new version of CMake, because the default is too old. run: | # Fetch a new version of CMake, because the default is too old.
sudo rm -f /etc/apt/sources.list.d/dotnetdev.list /etc/apt/sources.list.d/microsoft-prod.list \ sudo rm -f /etc/apt/sources.list.d/dotnetdev.list /etc/apt/sources.list.d/microsoft-prod.list \
&& sudo apt-get update \ && sudo apt update \
&& sudo apt-get install cmake libcurl4-gnutls-dev libpcap0.8-dev libsdl2-dev qt5-default libslirp-dev libzip-dev && sudo apt install cmake libcurl4-gnutls-dev libpcap0.8-dev libsdl2-dev qt5-default libslirp0=4.1.0-2ubuntu2.1 libslirp-dev libarchive-dev --allow-downgrades
- name: Create build environment - name: Create build environment
run: mkdir ${{runner.workspace}}/build run: mkdir ${{runner.workspace}}/build
- name: Configure - name: Configure

View File

@ -36,9 +36,8 @@ jobs:
- name: Make - name: Make
run: | run: |
C:\tools\msys64\usr\bin\bash.exe -lc "export PATH=`"/mingw64/bin:`$PATH`" \ C:\tools\msys64\usr\bin\bash.exe -lc "export PATH=`"/mingw64/bin:`$PATH`" \
&& cd melonDS/build && make -j$(nproc --all) \ && cd melonDS/build && make -j$(nproc --all)"
&& ../msys-dist.sh"
- uses: actions/upload-artifact@v1 - uses: actions/upload-artifact@v1
with: with:
name: melonDS name: melonDS
path: C:\tools\msys64\home\runneradmin\melonDS\build\dist path: C:\tools\msys64\home\runneradmin\melonDS\build\melonDS.exe

View File

@ -50,6 +50,12 @@ else()
option(ENABLE_LTO "Enable link-time optimization" OFF) option(ENABLE_LTO "Enable link-time optimization" OFF)
endif() endif()
option(ENABLE_OGLRENDERER "Enable OpenGL renderer" ON)
if (ENABLE_OGLRENDERER)
add_definitions(-DOGLRENDERER_ENABLED)
endif()
if (CMAKE_BUILD_TYPE STREQUAL Debug) if (CMAKE_BUILD_TYPE STREQUAL Debug)
add_compile_options(-Og) add_compile_options(-Og)
endif() endif()

View File

@ -2,7 +2,7 @@
<h2 align="center"><b>melonDS</b></h2> <h2 align="center"><b>melonDS</b></h2>
<p align="center"> <p align="center">
<a href="http://melonds.kuribo64.net/" alt="melonDS website"><img src="https://img.shields.io/badge/website-melonds.kuribo64.net-%2331352e.svg"></a> <a href="http://melonds.kuribo64.net/" alt="melonDS website"><img src="https://img.shields.io/badge/website-melonds.kuribo64.net-%2331352e.svg"></a>
<a href="http://melonds.kuribo64.net/downloads.php" alt="Release: 0.8.3"><img src="https://img.shields.io/badge/release-0.8.3-%235c913b.svg"></a> <a href="http://melonds.kuribo64.net/downloads.php" alt="Release: 0.9"><img src="https://img.shields.io/badge/release-0.9-%235c913b.svg"></a>
<a href="https://www.gnu.org/licenses/gpl-3.0" alt="License: GPLv3"><img src="https://img.shields.io/badge/License-GPL%20v3-%23ff554d.svg"></a> <a href="https://www.gnu.org/licenses/gpl-3.0" alt="License: GPLv3"><img src="https://img.shields.io/badge/License-GPL%20v3-%23ff554d.svg"></a>
<a href="https://kiwiirc.com/client/irc.badnik.net/?nick=IRC-Source_?#melonds" alt="IRC channel: #melonds"><img src="https://img.shields.io/badge/IRC%20chat-%23melonds-%23dd2e44.svg"></a> <a href="https://kiwiirc.com/client/irc.badnik.net/?nick=IRC-Source_?#melonds" alt="IRC channel: #melonds"><img src="https://img.shields.io/badge/IRC%20chat-%23melonds-%23dd2e44.svg"></a>
</p> </p>
@ -38,7 +38,7 @@ As for the rest, the interface should be pretty straightforward. If you have a q
* Install dependencies: * Install dependencies:
```sh ```sh
sudo apt-get install libgtk-3-dev libcurl4-gnutls-dev libpcap0.8-dev libsdl2-dev libslirp-dev libzip-dev sudo apt-get install cmake libgtk-3-dev libcurl4-gnutls-dev libpcap0.8-dev libsdl2-dev qtbase5-dev qtdeclarative5-dev libslirp-dev libarchive-dev
``` ```
* Compile: * Compile:
@ -55,7 +55,23 @@ make -j$(nproc --all)
1. Install [MSYS2](https://www.msys2.org/) 1. Install [MSYS2](https://www.msys2.org/)
2. Open the **MSYS2 MinGW 64-bit** terminal 2. Open the **MSYS2 MinGW 64-bit** terminal
3. Update the packages using `pacman -Syu` and reopen the terminal if it asks you to 3. Update the packages using `pacman -Syu` and reopen the terminal if it asks you to
4. Install dependencies: `pacman -S git make mingw-w64-x86_64-{cmake,mesa,SDL2,libslirp,libzip,toolchain}`
#### Dynamic builds (with DLLs)
4. Install dependencies: `pacman -S git make mingw-w64-x86_64-{cmake,mesa,SDL2,toolchain,qt5,libslirp,libarchive}`
5. Run the following commands
```bash
git clone https://github.com/Arisotura/melonDS.git
cd melonDS
mkdir build
cd build
cmake .. -G "MSYS Makefiles"
make -j$(nproc --all)
../msys-dist.sh
```
If everything went well, melonDS and the libraries it needs should now be in the `dist` folder.
#### Static builds (without DLLs, standalone executable)
4. Install dependencies: `pacman -S git make mingw-w64-x86_64-{cmake,mesa,SDL2,toolchain,qt5-static,libslirp,libarchive}`
5. Run the following commands 5. Run the following commands
```bash ```bash
git clone https://github.com/Arisotura/melonDS.git git clone https://github.com/Arisotura/melonDS.git
@ -64,10 +80,9 @@ make -j$(nproc --all)
cd build cd build
cmake .. -G 'MSYS Makefiles' -DBUILD_STATIC=ON -DQT5_STATIC_DIR=/mingw64/qt5-static cmake .. -G 'MSYS Makefiles' -DBUILD_STATIC=ON -DQT5_STATIC_DIR=/mingw64/qt5-static
make -j$(nproc --all) make -j$(nproc --all)
../msys-dist.sh mkdir dist && cp melonDS.exe dist
``` ```
If everything went well, melonDS should now be in the `dist` folder.
If everything went well, melonDS and the libraries it needs should now be in the `dist` folder.
## TODO LIST ## TODO LIST
@ -99,4 +114,4 @@ If everything went well, melonDS and the libraries it needs should now be in the
melonDS is free software: you can redistribute it and/or modify melonDS is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.

View File

@ -6,8 +6,8 @@
//include version information in .exe, modify these values to match your needs //include version information in .exe, modify these values to match your needs
1 VERSIONINFO 1 VERSIONINFO
FILEVERSION 0,8,3,0 FILEVERSION 0,9,0,0
PRODUCTVERSION 0,8,3,0 PRODUCTVERSION 0,9,0,0
FILETYPE VFT_APP FILETYPE VFT_APP
{ {
BLOCK "StringFileInfo" BLOCK "StringFileInfo"
@ -15,14 +15,14 @@ FILETYPE VFT_APP
BLOCK "040904E4" BLOCK "040904E4"
{ {
VALUE "CompanyName", "Melon Factory of Kuribo64" VALUE "CompanyName", "Melon Factory of Kuribo64"
VALUE "FileVersion", "0.8.3" VALUE "FileVersion", "0.9"
VALUE "FileDescription", "DS emulator, sorta. also 1st quality melon." VALUE "FileDescription", "DS emulator, sorta. also 1st quality melon."
VALUE "InternalName", "SDnolem" VALUE "InternalName", "SDnolem"
VALUE "LegalCopyright", "2016-2020 Arisotura & co." VALUE "LegalCopyright", "2016-2020 Arisotura & co."
VALUE "LegalTrademarks", "" VALUE "LegalTrademarks", ""
VALUE "OriginalFilename", "zafkflzdasd.exe" VALUE "OriginalFilename", "zafkflzdasd.exe"
VALUE "ProductName", "melonDS" VALUE "ProductName", "melonDS"
VALUE "ProductVersion", "0.8.3" VALUE "ProductVersion", "0.9"
} }
} }
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View File

@ -11,4 +11,5 @@ for lib in $(ldd melonDS.exe | grep mingw | sed "s/.*=> //" | sed "s/(.*)//"); d
cp "${lib}" dist cp "${lib}" dist
done done
cp melonDS.exe dist cp melonDS.exe dist
windeployqt dist

191
src/ARCodeFile.cpp Normal file
View File

@ -0,0 +1,191 @@
/*
Copyright 2016-2020 Arisotura
This file is part of melonDS.
melonDS is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option)
any later version.
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with melonDS. If not, see http://www.gnu.org/licenses/.
*/
#include <stdio.h>
#include <string.h>
#include "ARCodeFile.h"
#include "Platform.h"
// TODO: import codes from other sources (usrcheat.dat, ...)
// TODO: more user-friendly error reporting
ARCodeFile::ARCodeFile(const char* filename)
{
memset(Filename, 0, sizeof(Filename));
strncpy(Filename, filename, 1023);
Error = false;
Categories.clear();
if (!Load())
Error = true;
}
ARCodeFile::~ARCodeFile()
{
Categories.clear();
}
bool ARCodeFile::Load()
{
FILE* f = Platform::OpenFile(Filename, "r");
if (!f) return true;
Categories.clear();
bool isincat = false;
ARCodeCat curcat;
bool isincode = false;
ARCode curcode;
char linebuf[1024];
while (!feof(f))
{
fgets(linebuf, 1024, f);
linebuf[1023] = '\0';
char* start = linebuf;
while (start[0]==' ' || start[0]=='\t')
start++;
if (start[0]=='#' || start[0]=='\r' || start[0]=='\n' || start[0]=='\0')
continue;
if (!strncasecmp(start, "CAT", 3))
{
char catname[128];
int ret = sscanf(start, "CAT %127[^\r\n]", catname);
catname[127] = '\0';
if (ret < 1)
{
printf("AR: malformed CAT line: %s\n", start);
fclose(f);
return false;
}
if (isincode) curcat.Codes.push_back(curcode);
isincode = false;
if (isincat) Categories.push_back(curcat);
isincat = true;
memcpy(curcat.Name, catname, 128);
curcat.Codes.clear();
}
else if (!strncasecmp(start, "CODE", 4))
{
int enable;
char codename[128];
int ret = sscanf(start, "CODE %d %127[^\r\n]", &enable, codename);
codename[127] = '\0';
if (ret < 2)
{
printf("AR: malformed CODE line: %s\n", start);
fclose(f);
return false;
}
if (!isincat)
{
printf("AR: encountered CODE line with no category started\n");
fclose(f);
return false;
}
if (isincode) curcat.Codes.push_back(curcode);
isincode = true;
memcpy(curcode.Name, codename, 128);
curcode.Enabled = enable!=0;
curcode.CodeLen = 0;
}
else
{
u32 c0, c1;
int ret = sscanf(start, "%08X %08X", &c0, &c1);
if (ret < 2)
{
printf("AR: malformed data line: %s\n", start);
fclose(f);
return false;
}
if (!isincode)
{
printf("AR: encountered data line with no code started\n");
fclose(f);
return false;
}
if (curcode.CodeLen >= 2*64)
{
printf("AR: code too long!\n");
fclose(f);
return false;
}
u32 idx = curcode.CodeLen;
curcode.Code[idx+0] = c0;
curcode.Code[idx+1] = c1;
curcode.CodeLen += 2;
}
}
if (isincode) curcat.Codes.push_back(curcode);
if (isincat) Categories.push_back(curcat);
fclose(f);
return true;
}
bool ARCodeFile::Save()
{
FILE* f = Platform::OpenFile(Filename, "w");
if (!f) return false;
for (ARCodeCatList::iterator it = Categories.begin(); it != Categories.end(); it++)
{
ARCodeCat& cat = *it;
if (it != Categories.begin()) fprintf(f, "\n");
fprintf(f, "CAT %s\n\n", cat.Name);
for (ARCodeList::iterator jt = cat.Codes.begin(); jt != cat.Codes.end(); jt++)
{
ARCode& code = *jt;
fprintf(f, "CODE %d %s\n", code.Enabled, code.Name);
for (u32 i = 0; i < code.CodeLen; i+=2)
{
fprintf(f, "%08X %08X\n", code.Code[i], code.Code[i+1]);
}
fprintf(f, "\n");
}
}
fclose(f);
return true;
}

View File

@ -16,18 +16,49 @@
with melonDS. If not, see http://www.gnu.org/licenses/. with melonDS. If not, see http://www.gnu.org/licenses/.
*/ */
#ifndef ARCODELIST_H #ifndef ARCODEFILE_H
#define ARCODELIST_H #define ARCODEFILE_H
#include <list>
#include "types.h" #include "types.h"
#define ARCL_MAJOR 1 typedef struct
#define ARCL_MINOR 1 {
char Name[128];
bool Enabled;
u32 CodeLen;
u32 Code[2*64];
class ARCodeList } ARCode;
typedef std::list<ARCode> ARCodeList;
typedef struct
{
char Name[128];
ARCodeList Codes;
} ARCodeCat;
typedef std::list<ARCodeCat> ARCodeCatList;
class ARCodeFile
{ {
public: public:
// ARCodeFile(const char* filename);
~ARCodeFile();
bool Error;
bool Load();
bool Save();
ARCodeCatList Categories;
private:
char Filename[1024];
}; };
#endif // ARCODELIST_H #endif // ARCODEFILE_H

View File

@ -1,38 +0,0 @@
/*
Copyright 2016-2020 Arisotura
This file is part of melonDS.
melonDS is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option)
any later version.
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with melonDS. If not, see http://www.gnu.org/licenses/.
*/
#include <stdio.h>
#include "ARCodeList.h"
/*
Action Replay code list format
header:
00 - magic MLAR
04 - version major
06 - version minor
08 - length
0C - number of codes
code header:
00 - magic MLCD
04 - name length
08 - code length
0C - enable flag
10 - code data (UTF8 name then actual code)
*/

View File

@ -19,125 +19,63 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "NDS.h" #include "NDS.h"
#include "DSi.h"
#include "AREngine.h" #include "AREngine.h"
namespace AREngine namespace AREngine
{ {
typedef struct // AR code file - frontend is responsible for managing this
{ ARCodeFile* CodeFile;
u32 Code[2 * 64]; // TODO: more sensible size for this? allocate on demand?
bool Enabled;
} CheatEntry; u8 (*BusRead8)(u32 addr);
u16 (*BusRead16)(u32 addr);
// TODO: more sensible size for this? allocate on demand? u32 (*BusRead32)(u32 addr);
CheatEntry CheatCodes[64]; void (*BusWrite8)(u32 addr, u8 val);
u32 NumCheatCodes; void (*BusWrite16)(u32 addr, u16 val);
void (*BusWrite32)(u32 addr, u32 val);
void ParseTextCode(char* text, int tlen, u32* code, int clen) // or whatever this should be named?
{
u32 cur_word = 0;
u32 ndigits = 0;
u32 nin = 0;
u32 nout = 0;
char c;
while ((c = *text++) != '\0')
{
u32 val;
if (c >= '0' && c <= '9')
val = c - '0';
else if (c >= 'a' && c <= 'f')
val = c - 'a' + 0xA;
else if (c >= 'A' && c <= 'F')
val = c - 'A' + 0xA;
else
continue;
cur_word <<= 4;
cur_word |= val;
ndigits++;
if (ndigits >= 8)
{
if (nout >= clen)
{
printf("AR: code too long!\n");
return;
}
*code++ = cur_word;
nout++;
ndigits = 0;
cur_word = 0;
}
nin++;
if (nin >= tlen) break;
}
if (nout & 1)
{
printf("AR: code was missing one word\n");
if (nout >= clen)
{
printf("AR: code too long!\n");
return;
}
*code++ = 0;
}
}
bool Init() bool Init()
{ {
CodeFile = nullptr;
return true; return true;
} }
void DeInit() void DeInit()
{ {
//
} }
void Reset() void Reset()
{ {
memset(CheatCodes, 0, sizeof(CheatCodes)); CodeFile = nullptr;
NumCheatCodes = 0;
// TODO: acquire codes from a sensible source! if (NDS::ConsoleType == 1)
CheatEntry* entry = &CheatCodes[0];
u32* ptr = &entry->Code[0];
/*char* test = R"(9209D09A 00000000
6209B468 00000000
B209B468 00000000
10000672 000003FF
D2000000 00000000
9209D09A 00000000
94000130 FCBF0000
6209B468 00000000
B209B468 00000000
200006B3 00000001
200006B4 00000001
D2000000 00000000
9209D09A 00000000
94000130 FC7F0000
6209B468 00000000
B209B468 00000000
10000672 00000000
D2000000 00000000)";
ParseTextCode(test, entry->Code, 2*64);
printf("PARSED CODE:\n");
for (int i = 0; i < 2*64; i+=2)
{ {
printf("%08X %08X\n", entry->Code[i], entry->Code[i+1]); BusRead8 = DSi::ARM7Read8;
BusRead16 = DSi::ARM7Read16;
BusRead32 = DSi::ARM7Read32;
BusWrite8 = DSi::ARM7Write8;
BusWrite16 = DSi::ARM7Write16;
BusWrite32 = DSi::ARM7Write32;
} }
entry->Enabled = true; else
NumCheatCodes++;*/ {
BusRead8 = NDS::ARM7Read8;
BusRead16 = NDS::ARM7Read16;
BusRead32 = NDS::ARM7Read32;
BusWrite8 = NDS::ARM7Write8;
BusWrite16 = NDS::ARM7Write16;
BusWrite32 = NDS::ARM7Write32;
}
}
void SetCodeFile(ARCodeFile* file)
{
CodeFile = file;
} }
@ -147,9 +85,9 @@ D2000000 00000000)";
case ((x)+0x08): case ((x)+0x09): case ((x)+0x0A): case ((x)+0x0B): \ case ((x)+0x08): case ((x)+0x09): case ((x)+0x0A): case ((x)+0x0B): \
case ((x)+0x0C): case ((x)+0x0D): case ((x)+0x0E): case ((x)+0x0F) case ((x)+0x0C): case ((x)+0x0D): case ((x)+0x0E): case ((x)+0x0F)
void RunCheat(CheatEntry* entry) void RunCheat(ARCode& arcode)
{ {
u32* code = &entry->Code[0]; u32* code = &arcode.Code[0];
u32 offset = 0; u32 offset = 0;
u32 datareg = 0; u32 datareg = 0;
@ -166,9 +104,11 @@ void RunCheat(CheatEntry* entry)
for (;;) for (;;)
{ {
if (code >= &arcode.Code[arcode.CodeLen])
break;
u32 a = *code++; u32 a = *code++;
u32 b = *code++; u32 b = *code++;
if ((a|b) == 0) break;
u8 op = a >> 24; u8 op = a >> 24;
@ -179,7 +119,7 @@ void RunCheat(CheatEntry* entry)
if ((op & 0xF0) == 0xE0) if ((op & 0xF0) == 0xE0)
{ {
for (u32 i = 0; i < b; i += 8) for (u32 i = 0; i < b; i += 8)
*code += 2; code += 2;
} }
continue; continue;
@ -189,15 +129,15 @@ void RunCheat(CheatEntry* entry)
switch (op) switch (op)
{ {
case16(0x00): // 32-bit write case16(0x00): // 32-bit write
NDS::ARM7Write32((a & 0x0FFFFFFF) + offset, b); BusWrite32((a & 0x0FFFFFFF) + offset, b);
break; break;
case16(0x10): // 16-bit write case16(0x10): // 16-bit write
NDS::ARM7Write16((a & 0x0FFFFFFF) + offset, b & 0xFFFF); BusWrite16((a & 0x0FFFFFFF) + offset, b & 0xFFFF);
break; break;
case16(0x20): // 8-bit write case16(0x20): // 8-bit write
NDS::ARM7Write8((a & 0x0FFFFFFF) + offset, b & 0xFF); BusWrite8((a & 0x0FFFFFFF) + offset, b & 0xFF);
break; break;
case16(0x30): // IF b > u32[a] case16(0x30): // IF b > u32[a]
@ -205,7 +145,7 @@ void RunCheat(CheatEntry* entry)
condstack <<= 1; condstack <<= 1;
condstack |= cond; condstack |= cond;
u32 chk = NDS::ARM7Read32(a & 0x0FFFFFFF); u32 chk = BusRead32(a & 0x0FFFFFFF);
cond = (b > chk) ? 1:0; cond = (b > chk) ? 1:0;
} }
@ -216,7 +156,7 @@ void RunCheat(CheatEntry* entry)
condstack <<= 1; condstack <<= 1;
condstack |= cond; condstack |= cond;
u32 chk = NDS::ARM7Read32(a & 0x0FFFFFFF); u32 chk = BusRead32(a & 0x0FFFFFFF);
cond = (b < chk) ? 1:0; cond = (b < chk) ? 1:0;
} }
@ -227,7 +167,7 @@ void RunCheat(CheatEntry* entry)
condstack <<= 1; condstack <<= 1;
condstack |= cond; condstack |= cond;
u32 chk = NDS::ARM7Read32(a & 0x0FFFFFFF); u32 chk = BusRead32(a & 0x0FFFFFFF);
cond = (b == chk) ? 1:0; cond = (b == chk) ? 1:0;
} }
@ -238,7 +178,7 @@ void RunCheat(CheatEntry* entry)
condstack <<= 1; condstack <<= 1;
condstack |= cond; condstack |= cond;
u32 chk = NDS::ARM7Read32(a & 0x0FFFFFFF); u32 chk = BusRead32(a & 0x0FFFFFFF);
cond = (b != chk) ? 1:0; cond = (b != chk) ? 1:0;
} }
@ -249,7 +189,7 @@ void RunCheat(CheatEntry* entry)
condstack <<= 1; condstack <<= 1;
condstack |= cond; condstack |= cond;
u16 val = NDS::ARM7Read16(a & 0x0FFFFFFF); u16 val = BusRead16(a & 0x0FFFFFFF);
u16 chk = ~(b >> 16); u16 chk = ~(b >> 16);
chk &= val; chk &= val;
@ -262,7 +202,7 @@ void RunCheat(CheatEntry* entry)
condstack <<= 1; condstack <<= 1;
condstack |= cond; condstack |= cond;
u16 val = NDS::ARM7Read16(a & 0x0FFFFFFF); u16 val = BusRead16(a & 0x0FFFFFFF);
u16 chk = ~(b >> 16); u16 chk = ~(b >> 16);
chk &= val; chk &= val;
@ -275,7 +215,7 @@ void RunCheat(CheatEntry* entry)
condstack <<= 1; condstack <<= 1;
condstack |= cond; condstack |= cond;
u16 val = NDS::ARM7Read16(a & 0x0FFFFFFF); u16 val = BusRead16(a & 0x0FFFFFFF);
u16 chk = ~(b >> 16); u16 chk = ~(b >> 16);
chk &= val; chk &= val;
@ -288,7 +228,7 @@ void RunCheat(CheatEntry* entry)
condstack <<= 1; condstack <<= 1;
condstack |= cond; condstack |= cond;
u16 val = NDS::ARM7Read16(a & 0x0FFFFFFF); u16 val = BusRead16(a & 0x0FFFFFFF);
u16 chk = ~(b >> 16); u16 chk = ~(b >> 16);
chk &= val; chk &= val;
@ -297,7 +237,7 @@ void RunCheat(CheatEntry* entry)
break; break;
case16(0xB0): // offset = u32[a + offset] case16(0xB0): // offset = u32[a + offset]
offset = NDS::ARM7Read32((a & 0x0FFFFFFF) + offset); offset = BusRead32((a & 0x0FFFFFFF) + offset);
break; break;
case 0xC0: // FOR 0..b case 0xC0: // FOR 0..b
@ -334,7 +274,7 @@ void RunCheat(CheatEntry* entry)
break; break;
case 0xC6: // u32[b] = offset case 0xC6: // u32[b] = offset
NDS::ARM7Write32(b, offset); BusWrite32(b, offset);
break; break;
case 0xD0: // ENDIF case 0xD0: // ENDIF
@ -383,30 +323,30 @@ void RunCheat(CheatEntry* entry)
break; break;
case 0xD6: // u32[b+offset] = datareg / offset += 4 case 0xD6: // u32[b+offset] = datareg / offset += 4
NDS::ARM7Write32(b + offset, datareg); BusWrite32(b + offset, datareg);
offset += 4; offset += 4;
break; break;
case 0xD7: // u16[b+offset] = datareg / offset += 2 case 0xD7: // u16[b+offset] = datareg / offset += 2
NDS::ARM7Write16(b + offset, datareg & 0xFFFF); BusWrite16(b + offset, datareg & 0xFFFF);
offset += 2; offset += 2;
break; break;
case 0xD8: // u8[b+offset] = datareg / offset += 1 case 0xD8: // u8[b+offset] = datareg / offset += 1
NDS::ARM7Write8(b + offset, datareg & 0xFF); BusWrite8(b + offset, datareg & 0xFF);
offset += 1; offset += 1;
break; break;
case 0xD9: // datareg = u32[b+offset] case 0xD9: // datareg = u32[b+offset]
datareg = NDS::ARM7Read32(b + offset); datareg = BusRead32(b + offset);
break; break;
case 0xDA: // datareg = u16[b+offset] case 0xDA: // datareg = u16[b+offset]
datareg = NDS::ARM7Read16(b + offset); datareg = BusRead16(b + offset);
break; break;
case 0xDB: // datareg = u8[b+offset] case 0xDB: // datareg = u8[b+offset]
datareg = NDS::ARM7Read8(b + offset); datareg = BusRead8(b + offset);
break; break;
case 0xDC: // offset += b case 0xDC: // offset += b
@ -421,23 +361,23 @@ void RunCheat(CheatEntry* entry)
u32 bytesleft = b; u32 bytesleft = b;
while (bytesleft >= 8) while (bytesleft >= 8)
{ {
NDS::ARM7Write32(dstaddr, *code++); dstaddr += 4; BusWrite32(dstaddr, *code++); dstaddr += 4;
NDS::ARM7Write32(dstaddr, *code++); dstaddr += 4; BusWrite32(dstaddr, *code++); dstaddr += 4;
bytesleft -= 8; bytesleft -= 8;
} }
if (bytesleft > 0) if (bytesleft > 0)
{ {
u8* leftover = (u8*)code; u8* leftover = (u8*)code;
*code += 2; code += 2;
if (bytesleft >= 4) if (bytesleft >= 4)
{ {
NDS::ARM7Write32(dstaddr, *(u32*)leftover); dstaddr += 4; BusWrite32(dstaddr, *(u32*)leftover); dstaddr += 4;
leftover += 4; leftover += 4;
bytesleft -= 4; bytesleft -= 4;
} }
while (bytesleft > 0) while (bytesleft > 0)
{ {
NDS::ARM7Write8(dstaddr, *leftover++); dstaddr++; BusWrite8(dstaddr, *leftover++); dstaddr++;
bytesleft--; bytesleft--;
} }
} }
@ -453,14 +393,14 @@ void RunCheat(CheatEntry* entry)
u32 bytesleft = b; u32 bytesleft = b;
while (bytesleft >= 4) while (bytesleft >= 4)
{ {
NDS::ARM7Write32(dstaddr, NDS::ARM7Read32(srcaddr)); BusWrite32(dstaddr, BusRead32(srcaddr));
srcaddr += 4; srcaddr += 4;
dstaddr += 4; dstaddr += 4;
bytesleft -= 4; bytesleft -= 4;
} }
while (bytesleft > 0) while (bytesleft > 0)
{ {
NDS::ARM7Write8(dstaddr, NDS::ARM7Read8(srcaddr)); BusWrite8(dstaddr, BusRead8(srcaddr));
srcaddr++; srcaddr++;
dstaddr++; dstaddr++;
bytesleft--; bytesleft--;
@ -477,13 +417,19 @@ void RunCheat(CheatEntry* entry)
void RunCheats() void RunCheats()
{ {
// TODO: make it disableable in general if (!CodeFile) return;
for (u32 i = 0; i < NumCheatCodes; i++) for (ARCodeCatList::iterator i = CodeFile->Categories.begin(); i != CodeFile->Categories.end(); i++)
{ {
CheatEntry* entry = &CheatCodes[i]; ARCodeCat& cat = *i;
if (entry->Enabled)
RunCheat(entry); for (ARCodeList::iterator j = cat.Codes.begin(); j != cat.Codes.end(); j++)
{
ARCode& code = *j;
if (code.Enabled)
RunCheat(code);
}
} }
} }

View File

@ -19,6 +19,8 @@
#ifndef ARENGINE_H #ifndef ARENGINE_H
#define ARENGINE_H #define ARENGINE_H
#include "ARCodeFile.h"
namespace AREngine namespace AREngine
{ {
@ -26,6 +28,8 @@ bool Init();
void DeInit(); void DeInit();
void Reset(); void Reset();
void SetCodeFile(ARCodeFile* file);
void RunCheats(); void RunCheats();
} }

View File

@ -24,7 +24,10 @@
#include "types.h" #include "types.h"
#include "NDS.h" #include "NDS.h"
#define ROR(x, n) (((x) >> (n)) | ((x) << (32-(n)))) inline u32 ROR(u32 x, u32 n)
{
return (x >> (n&0x1F)) | (x << ((32-n)&0x1F));
}
enum enum
{ {

View File

@ -38,6 +38,14 @@ namespace ARMJIT
Compiler* JITCompiler; Compiler* JITCompiler;
std::unordered_map<u32, JitBlock*> JitBlocks9;
std::unordered_map<u32, JitBlock*> JitBlocks7;
std::unordered_map<u32, JitBlock*> RestoreCandidates;
TinyVector<u32> InvalidLiterals;
AddressRange CodeIndexITCM[ITCMPhysicalSize / 512]; AddressRange CodeIndexITCM[ITCMPhysicalSize / 512];
AddressRange CodeIndexMainRAM[NDS::MainRAMMaxSize / 512]; AddressRange CodeIndexMainRAM[NDS::MainRAMMaxSize / 512];
AddressRange CodeIndexSWRAM[NDS::SharedWRAMSize / 512]; AddressRange CodeIndexSWRAM[NDS::SharedWRAMSize / 512];
@ -52,9 +60,6 @@ AddressRange CodeIndexNWRAM_A[DSi::NWRAMSize / 512];
AddressRange CodeIndexNWRAM_B[DSi::NWRAMSize / 512]; AddressRange CodeIndexNWRAM_B[DSi::NWRAMSize / 512];
AddressRange CodeIndexNWRAM_C[DSi::NWRAMSize / 512]; AddressRange CodeIndexNWRAM_C[DSi::NWRAMSize / 512];
std::unordered_map<u32, JitBlock*> JitBlocks9;
std::unordered_map<u32, JitBlock*> JitBlocks7;
u64 FastBlockLookupITCM[ITCMPhysicalSize / 2]; u64 FastBlockLookupITCM[ITCMPhysicalSize / 2];
u64 FastBlockLookupMainRAM[NDS::MainRAMMaxSize / 2]; u64 FastBlockLookupMainRAM[NDS::MainRAMMaxSize / 2];
u64 FastBlockLookupSWRAM[NDS::SharedWRAMSize / 2]; u64 FastBlockLookupSWRAM[NDS::SharedWRAMSize / 2];
@ -146,8 +151,6 @@ u32 LocaliseCodeAddress(u32 num, u32 addr)
return 0; return 0;
} }
TinyVector<u32> InvalidLiterals;
template <typename T, int ConsoleType> template <typename T, int ConsoleType>
T SlowRead9(u32 addr, ARMv5* cpu) T SlowRead9(u32 addr, ARMv5* cpu)
{ {
@ -286,97 +289,6 @@ void SlowBlockTransfer7(u32 addr, u64* data, u32 num)
INSTANTIATE_SLOWMEM(0) INSTANTIATE_SLOWMEM(0)
INSTANTIATE_SLOWMEM(1) INSTANTIATE_SLOWMEM(1)
template <typename K, typename V, int Size, V InvalidValue>
struct UnreliableHashTable
{
struct Bucket
{
K KeyA, KeyB;
V ValA, ValB;
};
Bucket Table[Size];
void Reset()
{
for (int i = 0; i < Size; i++)
{
Table[i].ValA = Table[i].ValB = InvalidValue;
}
}
UnreliableHashTable()
{
Reset();
}
V Insert(K key, V value)
{
u32 slot = XXH3_64bits(&key, sizeof(K)) & (Size - 1);
Bucket* bucket = &Table[slot];
if (bucket->ValA == value || bucket->ValB == value)
{
return InvalidValue;
}
else if (bucket->ValA == InvalidValue)
{
bucket->KeyA = key;
bucket->ValA = value;
}
else if (bucket->ValB == InvalidValue)
{
bucket->KeyB = key;
bucket->ValB = value;
}
else
{
V prevVal = bucket->ValB;
bucket->KeyB = bucket->KeyA;
bucket->ValB = bucket->ValA;
bucket->KeyA = key;
bucket->ValA = value;
return prevVal;
}
return InvalidValue;
}
void Remove(K key)
{
u32 slot = XXH3_64bits(&key, sizeof(K)) & (Size - 1);
Bucket* bucket = &Table[slot];
if (bucket->KeyA == key && bucket->ValA != InvalidValue)
{
bucket->ValA = InvalidValue;
if (bucket->ValB != InvalidValue)
{
bucket->KeyA = bucket->KeyB;
bucket->ValA = bucket->ValB;
bucket->ValB = InvalidValue;
}
}
if (bucket->KeyB == key && bucket->ValB != InvalidValue)
bucket->ValB = InvalidValue;
}
V LookUp(K addr)
{
u32 slot = XXH3_64bits(&addr, 4) & (Size - 1);
Bucket* bucket = &Table[slot];
if (bucket->ValA != InvalidValue && bucket->KeyA == addr)
return bucket->ValA;
if (bucket->ValB != InvalidValue && bucket->KeyB == addr)
return bucket->ValB;
return InvalidValue;
}
};
UnreliableHashTable<u32, JitBlock*, 0x800, nullptr> RestoreCandidates;
void Init() void Init()
{ {
JITCompiler = new Compiler(); JITCompiler = new Compiler();
@ -568,7 +480,7 @@ InterpreterFunc InterpretARM[ARMInstrInfo::ak_Count] =
F_ALU(CMN,), F_ALU(CMN,),
F(MUL), F(MLA), F(UMULL), F(UMLAL), F(SMULL), F(SMLAL), F(SMLAxy), F(SMLAWy), F(SMULWy), F(SMLALxy), F(SMULxy), F(MUL), F(MLA), F(UMULL), F(UMLAL), F(SMULL), F(SMLAL), F(SMLAxy), F(SMLAWy), F(SMULWy), F(SMLALxy), F(SMULxy),
F(CLZ), F(QADD), F(QDADD), F(QSUB), F(QDSUB), F(CLZ), F(QADD), F(QSUB), F(QDADD), F(QDSUB),
F_MEM_WB(STR), F_MEM_WB(STR),
F_MEM_WB(STRB), F_MEM_WB(STRB),
@ -622,6 +534,20 @@ InterpreterFunc InterpretTHUMB[ARMInstrInfo::tk_Count] =
}; };
#undef F #undef F
void RetireJitBlock(JitBlock* block)
{
auto it = RestoreCandidates.find(block->InstrHash);
if (it != RestoreCandidates.end())
{
delete it->second;
it->second = block;
}
else
{
RestoreCandidates[block->InstrHash] = block;
}
}
void CompileBlock(ARM* cpu) void CompileBlock(ARM* cpu)
{ {
bool thumb = cpu->CPSR & 0x20; bool thumb = cpu->CPSR & 0x20;
@ -659,10 +585,7 @@ void CompileBlock(ARM* cpu)
} }
// some memory has been remapped // some memory has been remapped
JitBlock* prevBlock = RestoreCandidates.Insert(existingBlockIt->second->InstrHash, existingBlockIt->second); RetireJitBlock(existingBlockIt->second);
if (prevBlock)
delete prevBlock;
map.erase(existingBlockIt); map.erase(existingBlockIt);
} }
@ -906,11 +829,13 @@ void CompileBlock(ARM* cpu)
u32 literalHash = (u32)XXH3_64bits(literalValues, numLiterals * 4); u32 literalHash = (u32)XXH3_64bits(literalValues, numLiterals * 4);
u32 instrHash = (u32)XXH3_64bits(instrValues, i * 4); u32 instrHash = (u32)XXH3_64bits(instrValues, i * 4);
JitBlock* prevBlock = RestoreCandidates.LookUp(instrHash); auto prevBlockIt = RestoreCandidates.find(instrHash);
JitBlock* prevBlock = NULL;
bool mayRestore = true; bool mayRestore = true;
if (prevBlock) if (prevBlockIt != RestoreCandidates.end())
{ {
RestoreCandidates.Remove(instrHash); prevBlock = prevBlockIt->second;
RestoreCandidates.erase(prevBlockIt);
mayRestore = prevBlock->StartAddr == blockAddr && prevBlock->LiteralHash == literalHash; mayRestore = prevBlock->StartAddr == blockAddr && prevBlock->LiteralHash == literalHash;
@ -932,7 +857,6 @@ void CompileBlock(ARM* cpu)
else else
{ {
mayRestore = false; mayRestore = false;
prevBlock = NULL;
} }
JitBlock* block; JitBlock* block;
@ -1078,9 +1002,7 @@ void InvalidateByAddr(u32 localAddr)
if (!literalInvalidation) if (!literalInvalidation)
{ {
JitBlock* prevBlock = RestoreCandidates.Insert(block->InstrHash, block); RetireJitBlock(block);
if (prevBlock)
delete prevBlock;
} }
else else
{ {
@ -1165,21 +1087,13 @@ void ResetBlockCache()
InvalidLiterals.Clear(); InvalidLiterals.Clear();
for (int i = 0; i < ARMJIT_Memory::memregions_Count; i++) for (int i = 0; i < ARMJIT_Memory::memregions_Count; i++)
memset(FastBlockLookupRegions[i], 0xFF, CodeRegionSizes[i] * sizeof(u64) / 2);
RestoreCandidates.Reset();
for (int i = 0; i < sizeof(RestoreCandidates.Table)/sizeof(RestoreCandidates.Table[0]); i++)
{ {
if (RestoreCandidates.Table[i].ValA) if (FastBlockLookupRegions[i])
{ memset(FastBlockLookupRegions[i], 0xFF, CodeRegionSizes[i] * sizeof(u64) / 2);
delete RestoreCandidates.Table[i].ValA;
RestoreCandidates.Table[i].ValA = NULL;
}
if (RestoreCandidates.Table[i].ValA)
{
delete RestoreCandidates.Table[i].ValB;
RestoreCandidates.Table[i].ValB = NULL;
}
} }
for (auto it = RestoreCandidates.begin(); it != RestoreCandidates.end(); it++)
delete it->second;
RestoreCandidates.clear();
for (auto it : JitBlocks9) for (auto it : JitBlocks9)
{ {
JitBlock* block = it.second; JitBlock* block = it.second;

View File

@ -436,7 +436,7 @@ void Compiler::A_Comp_GetOp2(bool S, Op2& op2)
Comp_AddCycles_C(); Comp_AddCycles_C();
u32 shift = (CurInstr.Instr >> 7) & 0x1E; u32 shift = (CurInstr.Instr >> 7) & 0x1E;
u32 imm = ROR(CurInstr.Instr & 0xFF, shift); u32 imm = ::ROR(CurInstr.Instr & 0xFF, shift);
if (S && shift && (CurInstr.SetFlags & 0x2)) if (S && shift && (CurInstr.SetFlags & 0x2))
{ {
@ -447,7 +447,7 @@ void Compiler::A_Comp_GetOp2(bool S, Op2& op2)
ANDI2R(RCPSR, RCPSR, ~(1 << 29)); ANDI2R(RCPSR, RCPSR, ~(1 << 29));
} }
op2 = Op2(ROR(CurInstr.Instr & 0xFF, (CurInstr.Instr >> 7) & 0x1E)); op2 = Op2(imm);
} }
else else
{ {
@ -523,7 +523,7 @@ void Compiler::A_Comp_ALUMovOp()
case ST_LSL: LSL(rd, op2.Reg.Rm, op2.Reg.ShiftAmount); break; case ST_LSL: LSL(rd, op2.Reg.Rm, op2.Reg.ShiftAmount); break;
case ST_LSR: LSR(rd, op2.Reg.Rm, op2.Reg.ShiftAmount); break; case ST_LSR: LSR(rd, op2.Reg.Rm, op2.Reg.ShiftAmount); break;
case ST_ASR: ASR(rd, op2.Reg.Rm, op2.Reg.ShiftAmount); break; case ST_ASR: ASR(rd, op2.Reg.Rm, op2.Reg.ShiftAmount); break;
case ST_ROR: ROR_(rd, op2.Reg.Rm, op2.Reg.ShiftAmount); break; case ST_ROR: ROR(rd, op2.Reg.Rm, op2.Reg.ShiftAmount); break;
} }
} }
else else

View File

@ -76,7 +76,7 @@ void Compiler::A_Comp_MSR()
if (CurInstr.Instr & (1 << 25)) if (CurInstr.Instr & (1 << 25))
{ {
val = W0; val = W0;
MOVI2R(val, ROR((CurInstr.Instr & 0xFF), ((CurInstr.Instr >> 7) & 0x1E))); MOVI2R(val, ::ROR((CurInstr.Instr & 0xFF), ((CurInstr.Instr >> 7) & 0x1E)));
} }
else else
{ {

View File

@ -1,5 +1,5 @@
#ifndef ARMJIT_COMPILER_H #ifndef ARMJIT_A64_COMPILER_H
#define ARMJIT_COMPILER_H #define ARMJIT_A64_COMPILER_H
#include "../ARM.h" #include "../ARM.h"
#include "../ARMJIT.h" #include "../ARMJIT.h"
@ -266,4 +266,4 @@ public:
} }
#endif #endif

View File

@ -42,7 +42,7 @@ s64 Compiler::RewriteMemAccess(u64 pc)
return patch.PatchOffset; return patch.PatchOffset;
} }
printf("this is a JIT bug! %08x\n", __builtin_bswap32(*(u32*)pc)); printf("this is a JIT bug! %08x\n", __builtin_bswap32(*(u32*)pc));
assert(false); abort();
} }
bool Compiler::Comp_MemLoadLiteral(int size, bool signExtend, int rd, u32 addr) bool Compiler::Comp_MemLoadLiteral(int size, bool signExtend, int rd, u32 addr)
@ -65,7 +65,7 @@ bool Compiler::Comp_MemLoadLiteral(int size, bool signExtend, int rd, u32 addr)
if (size == 32) if (size == 32)
{ {
CurCPU->DataRead32(addr & ~0x3, &val); CurCPU->DataRead32(addr & ~0x3, &val);
val = ROR(val, (addr & 0x3) << 3); val = ::ROR(val, (addr & 0x3) << 3);
} }
else if (size == 16) else if (size == 16)
{ {
@ -151,7 +151,7 @@ void Compiler::Comp_MemAccess(int rd, int rn, Op2 offset, int size, int flags)
{ {
if (offset.Reg.ShiftType == ST_ROR) if (offset.Reg.ShiftType == ST_ROR)
{ {
ROR_(W0, offset.Reg.Rm, offset.Reg.ShiftAmount); ROR(W0, offset.Reg.Rm, offset.Reg.ShiftAmount);
offset = Op2(W0); offset = Op2(W0);
} }
@ -220,7 +220,7 @@ void Compiler::Comp_MemAccess(int rd, int rn, Op2 offset, int size, int flags)
if (size == 32) if (size == 32)
{ {
if (staticAddress & 0x3) if (staticAddress & 0x3)
ROR_(rdMapped, W0, (staticAddress & 0x3) << 3); ROR(rdMapped, W0, (staticAddress & 0x3) << 3);
else else
MOV(rdMapped, W0); MOV(rdMapped, W0);
} }
@ -807,4 +807,4 @@ void Compiler::T_Comp_LDMIA_STMIA()
} }
} }
} }

View File

@ -1,3 +1,6 @@
#ifndef ARMJIT_COMPILER_H
#define ARMJIT_COMPILER_H
#if defined(__x86_64__) #if defined(__x86_64__)
#include "ARMJIT_x64/ARMJIT_Compiler.h" #include "ARMJIT_x64/ARMJIT_Compiler.h"
#elif defined(__aarch64__) #elif defined(__aarch64__)
@ -9,4 +12,6 @@
namespace ARMJIT namespace ARMJIT
{ {
extern Compiler* JITCompiler; extern Compiler* JITCompiler;
} }
#endif

View File

@ -279,6 +279,7 @@ bool UnmapFromRange(u32 addr, u32 num, u32 offset, u32 size)
#endif #endif
} }
#ifndef __SWITCH__
void SetCodeProtectionRange(u32 addr, u32 size, u32 num, int protection) void SetCodeProtectionRange(u32 addr, u32 size, u32 num, int protection)
{ {
u8* dst = (u8*)(num == 0 ? FastMem9Start : FastMem7Start) + addr; u8* dst = (u8*)(num == 0 ? FastMem9Start : FastMem7Start) + addr;
@ -303,6 +304,7 @@ void SetCodeProtectionRange(u32 addr, u32 size, u32 num, int protection)
mprotect(dst, size, posixProt); mprotect(dst, size, posixProt);
#endif #endif
} }
#endif
struct Mapping struct Mapping
{ {
@ -524,8 +526,8 @@ bool MapAtAddress(u32 addr)
{ {
u32 sectionOffset = offset; u32 sectionOffset = offset;
bool hasCode = isExecutable && ARMJIT::PageContainsCode(&range[offset / 512]); bool hasCode = isExecutable && ARMJIT::PageContainsCode(&range[offset / 512]);
while ((!isExecutable || ARMJIT::PageContainsCode(&range[offset / 512]) == hasCode) while (offset < mirrorSize
&& offset < mirrorSize && (!isExecutable || ARMJIT::PageContainsCode(&range[offset / 512]) == hasCode)
&& (!skipDTCM || mirrorStart + offset != NDS::ARM9->DTCMBase)) && (!skipDTCM || mirrorStart + offset != NDS::ARM9->DTCMBase))
{ {
assert(states[(mirrorStart + offset) >> 12] == memstate_Unmapped); assert(states[(mirrorStart + offset) >> 12] == memstate_Unmapped);
@ -773,6 +775,7 @@ bool GetMirrorLocation(int region, u32 num, u32 addr, u32& memoryOffset, u32& mi
{ {
mirrorStart = addr & ~0xFFFFF; mirrorStart = addr & ~0xFFFFF;
mirrorSize = 0x100000; mirrorSize = 0x100000;
return true;
} }
return false; return false;
case memregion_VWRAM: case memregion_VWRAM:
@ -1007,7 +1010,7 @@ void WifiWrite32(u32 addr, u32 val)
u32 WifiRead32(u32 addr) u32 WifiRead32(u32 addr)
{ {
return Wifi::Read(addr) | (Wifi::Read(addr + 2) << 16); return (u32)Wifi::Read(addr) | ((u32)Wifi::Read(addr + 2) << 16);
} }
template <typename T> template <typename T>

View File

@ -61,7 +61,8 @@ public:
} }
} }
assert("Welp!"); printf("this is a JIT bug! LoadRegister failed\n");
abort();
} }
void PutLiteral(int reg, u32 val) void PutLiteral(int reg, u32 val)

View File

@ -110,7 +110,7 @@ OpArg Compiler::A_Comp_GetALUOp2(bool S, bool& carryUsed)
Comp_AddCycles_C(); Comp_AddCycles_C();
u32 shift = (CurInstr.Instr >> 7) & 0x1E; u32 shift = (CurInstr.Instr >> 7) & 0x1E;
u32 imm = ROR(CurInstr.Instr & 0xFF, shift); u32 imm = ::ROR(CurInstr.Instr & 0xFF, shift);
carryUsed = false; carryUsed = false;
if (S && shift) if (S && shift)
@ -209,7 +209,8 @@ void Compiler::A_Comp_Arith()
Comp_ArithTriOp(&Compiler::AND, rd, rn, op2, carryUsed, sFlag|opSymmetric|opInvertOp2); Comp_ArithTriOp(&Compiler::AND, rd, rn, op2, carryUsed, sFlag|opSymmetric|opInvertOp2);
break; break;
default: default:
assert("unimplemented"); printf("this is a JIT bug! %04x\n", op);
abort();
} }
if (CurInstr.A_Reg(12) == 15) if (CurInstr.A_Reg(12) == 15)
@ -493,7 +494,7 @@ OpArg Compiler::Comp_RegShiftReg(int op, Gen::OpArg rs, Gen::OpArg rm, bool S, b
{ {
if (S) if (S)
BT(32, R(RSCRATCH), Imm8(31)); BT(32, R(RSCRATCH), Imm8(31));
ROR_(32, R(RSCRATCH), R(ECX)); ROR(32, R(RSCRATCH), R(ECX));
if (S) if (S)
SETcc(CC_C, R(RSCRATCH2)); SETcc(CC_C, R(RSCRATCH2));
} }
@ -555,7 +556,7 @@ OpArg Compiler::Comp_RegShiftImm(int op, int amount, OpArg rm, bool S, bool& car
case 3: // ROR case 3: // ROR
MOV(32, R(RSCRATCH), rm); MOV(32, R(RSCRATCH), rm);
if (amount > 0) if (amount > 0)
ROR_(32, R(RSCRATCH), Imm8(amount)); ROR(32, R(RSCRATCH), Imm8(amount));
else else
{ {
BT(32, R(RCPSR), Imm8(29)); BT(32, R(RCPSR), Imm8(29));
@ -566,7 +567,7 @@ OpArg Compiler::Comp_RegShiftImm(int op, int amount, OpArg rm, bool S, bool& car
return R(RSCRATCH); return R(RSCRATCH);
} }
assert(false); abort();
} }
void Compiler::T_Comp_ShiftImm() void Compiler::T_Comp_ShiftImm()
@ -779,4 +780,4 @@ void Compiler::T_Comp_RelAddr()
MOV(32, rd, Imm32((R15 & ~2) + offset)); MOV(32, rd, Imm32((R15 & ~2) + offset));
} }
} }

View File

@ -106,7 +106,7 @@ void Compiler::A_Comp_MSR()
Comp_AddCycles_C(); Comp_AddCycles_C();
OpArg val = CurInstr.Instr & (1 << 25) OpArg val = CurInstr.Instr & (1 << 25)
? Imm32(ROR((CurInstr.Instr & 0xFF), ((CurInstr.Instr >> 7) & 0x1E))) ? Imm32(::ROR((CurInstr.Instr & 0xFF), ((CurInstr.Instr >> 7) & 0x1E)))
: MapReg(CurInstr.A_Reg(0)); : MapReg(CurInstr.A_Reg(0));
u32 mask = 0; u32 mask = 0;

View File

@ -1,5 +1,5 @@
#ifndef ARMJIT_COMPILER_H #ifndef ARMJIT_X64_COMPILER_H
#define ARMJIT_COMPILER_H #define ARMJIT_X64_COMPILER_H
#include "../dolphin/x64Emitter.h" #include "../dolphin/x64Emitter.h"
@ -252,4 +252,4 @@ public:
} }
#endif #endif

View File

@ -39,7 +39,7 @@ s32 Compiler::RewriteMemAccess(u64 pc)
return patch.Offset; return patch.Offset;
} }
printf("this is a JIT bug %x\n", pc); printf("this is a JIT bug %llx\n", pc);
abort(); abort();
} }
@ -73,7 +73,7 @@ bool Compiler::Comp_MemLoadLiteral(int size, bool signExtend, int rd, u32 addr)
if (size == 32) if (size == 32)
{ {
CurCPU->DataRead32(addr & ~0x3, &val); CurCPU->DataRead32(addr & ~0x3, &val);
val = ROR(val, (addr & 0x3) << 3); val = ::ROR(val, (addr & 0x3) << 3);
} }
else if (size == 16) else if (size == 16)
{ {
@ -225,13 +225,13 @@ void Compiler::Comp_MemAccess(int rd, int rn, const Op2& op2, int size, int flag
if (addrIsStatic) if (addrIsStatic)
{ {
if (staticAddress & 0x3) if (staticAddress & 0x3)
ROR_(32, rdMapped, Imm8((staticAddress & 0x3) * 8)); ROR(32, rdMapped, Imm8((staticAddress & 0x3) * 8));
} }
else else
{ {
AND(32, R(RSCRATCH3), Imm8(0x3)); AND(32, R(RSCRATCH3), Imm8(0x3));
SHL(32, R(RSCRATCH3), Imm8(3)); SHL(32, R(RSCRATCH3), Imm8(3));
ROR_(32, rdMapped, R(RSCRATCH3)); ROR(32, rdMapped, R(RSCRATCH3));
} }
} }
} }
@ -270,7 +270,7 @@ void Compiler::Comp_MemAccess(int rd, int rn, const Op2& op2, int size, int flag
{ {
MOV(32, rdMapped, R(RSCRATCH)); MOV(32, rdMapped, R(RSCRATCH));
if (staticAddress & 0x3) if (staticAddress & 0x3)
ROR_(32, rdMapped, Imm8((staticAddress & 0x3) * 8)); ROR(32, rdMapped, Imm8((staticAddress & 0x3) * 8));
} }
else else
{ {
@ -819,4 +819,4 @@ void Compiler::T_Comp_LDMIA_STMIA()
ADD(32, rb, Imm8(offset)); ADD(32, rb, Imm8(offset));
} }
} }

View File

@ -3,7 +3,7 @@ project(core)
set (CMAKE_CXX_STANDARD 14) set (CMAKE_CXX_STANDARD 14)
add_library(core STATIC add_library(core STATIC
ARCodeList.cpp ARCodeFile.cpp
AREngine.cpp AREngine.cpp
ARM.cpp ARM.cpp
ARM_InstrTable.h ARM_InstrTable.h
@ -26,16 +26,12 @@ add_library(core STATIC
FIFO.h FIFO.h
GBACart.cpp GBACart.cpp
GPU.cpp GPU.cpp
GPU_OpenGL.cpp
GPU_OpenGL_shaders.h
GPU2D.cpp GPU2D.cpp
GPU3D.cpp GPU3D.cpp
GPU3D_OpenGL.cpp
GPU3D_OpenGL_shaders.h
GPU3D_Soft.cpp GPU3D_Soft.cpp
melonDLDI.h
NDS.cpp NDS.cpp
NDSCart.cpp NDSCart.cpp
OpenGLSupport.cpp
Platform.h Platform.h
ROMList.h ROMList.h
RTC.cpp RTC.cpp
@ -51,6 +47,16 @@ add_library(core STATIC
xxhash/xxhash.c xxhash/xxhash.c
) )
if (ENABLE_OGLRENDERER)
target_sources(core PRIVATE
GPU_OpenGL.cpp
GPU_OpenGL_shaders.h
GPU3D_OpenGL.cpp
GPU3D_OpenGL_shaders.h
OpenGLSupport.cpp
)
endif()
if (ENABLE_JIT) if (ENABLE_JIT)
enable_language(ASM) enable_language(ASM)
@ -94,9 +100,16 @@ if (ENABLE_JIT)
endif() endif()
endif() endif()
if (ENABLE_OGLRENDERER)
if (WIN32) if (WIN32)
target_link_libraries(core ole32 comctl32 ws2_32 opengl32) target_link_libraries(core ole32 comctl32 ws2_32 opengl32)
else()
target_link_libraries(core GL EGL)
endif()
else() else()
target_link_libraries(core GL EGL) if (WIN32)
endif() target_link_libraries(core ole32 comctl32 ws2_32)
else()
target_link_libraries(core)
endif()
endif()

View File

@ -616,11 +616,11 @@ void ARMv5::CP15Write(u32 id, u32 val)
case 0xF00: case 0xF00:
//printf("cache debug index register %08X\n", val); //printf("cache debug index register %08X\n", val);
return; return;
case 0xF10: case 0xF10:
//printf("cache debug instruction tag %08X\n", val); //printf("cache debug instruction tag %08X\n", val);
return; return;
case 0xF20: case 0xF20:
//printf("cache debug data tag %08X\n", val); //printf("cache debug data tag %08X\n", val);
return; return;
@ -632,7 +632,7 @@ void ARMv5::CP15Write(u32 id, u32 val)
case 0xF40: case 0xF40:
//printf("cache debug data cache %08X\n", val); //printf("cache debug data cache %08X\n", val);
return; return;
} }
if ((id & 0xF00) == 0xF00) // test/debug shit? if ((id & 0xF00) == 0xF00) // test/debug shit?

View File

@ -31,16 +31,22 @@ const char* kConfigFile = "melonDS.ini";
char BIOS9Path[1024]; char BIOS9Path[1024];
char BIOS7Path[1024]; char BIOS7Path[1024];
char FirmwarePath[1024]; char FirmwarePath[1024];
int DLDIEnable;
char DLDISDPath[1024];
char DSiBIOS9Path[1024]; char DSiBIOS9Path[1024];
char DSiBIOS7Path[1024]; char DSiBIOS7Path[1024];
char DSiFirmwarePath[1024]; char DSiFirmwarePath[1024];
char DSiNANDPath[1024]; char DSiNANDPath[1024];
int DSiSDEnable;
char DSiSDPath[1024];
int RandomizeMAC;
#ifdef JIT_ENABLED #ifdef JIT_ENABLED
int JIT_Enable = false; int JIT_Enable = false;
int JIT_MaxBlockSize = 32; int JIT_MaxBlockSize = 32;
int JIT_BranchOptimisations = 2; int JIT_BranchOptimisations = true;
int JIT_LiteralOptimisations = true; int JIT_LiteralOptimisations = true;
int JIT_FastMemory = true; int JIT_FastMemory = true;
#endif #endif
@ -50,16 +56,22 @@ ConfigEntry ConfigFile[] =
{"BIOS9Path", 1, BIOS9Path, 0, "", 1023}, {"BIOS9Path", 1, BIOS9Path, 0, "", 1023},
{"BIOS7Path", 1, BIOS7Path, 0, "", 1023}, {"BIOS7Path", 1, BIOS7Path, 0, "", 1023},
{"FirmwarePath", 1, FirmwarePath, 0, "", 1023}, {"FirmwarePath", 1, FirmwarePath, 0, "", 1023},
{"DLDIEnable", 0, &DLDIEnable, 0, NULL, 0},
{"DLDISDPath", 1, DLDISDPath, 0, "", 1023},
{"DSiBIOS9Path", 1, DSiBIOS9Path, 0, "", 1023}, {"DSiBIOS9Path", 1, DSiBIOS9Path, 0, "", 1023},
{"DSiBIOS7Path", 1, DSiBIOS7Path, 0, "", 1023}, {"DSiBIOS7Path", 1, DSiBIOS7Path, 0, "", 1023},
{"DSiFirmwarePath", 1, DSiFirmwarePath, 0, "", 1023}, {"DSiFirmwarePath", 1, DSiFirmwarePath, 0, "", 1023},
{"DSiNANDPath", 1, DSiNANDPath, 0, "", 1023}, {"DSiNANDPath", 1, DSiNANDPath, 0, "", 1023},
{"DSiSDEnable", 0, &DSiSDEnable, 0, NULL, 0},
{"DSiSDPath", 1, DSiSDPath, 0, "", 1023},
{"RandomizeMAC", 0, &RandomizeMAC, 0, NULL, 0},
#ifdef JIT_ENABLED #ifdef JIT_ENABLED
{"JIT_Enable", 0, &JIT_Enable, 0, NULL, 0}, {"JIT_Enable", 0, &JIT_Enable, 0, NULL, 0},
{"JIT_MaxBlockSize", 0, &JIT_MaxBlockSize, 32, NULL, 0}, {"JIT_MaxBlockSize", 0, &JIT_MaxBlockSize, 32, NULL, 0},
{"JIT_BranchOptimisations", 0, &JIT_BranchOptimisations, 2, NULL, 0}, {"JIT_BranchOptimisations", 0, &JIT_BranchOptimisations, 1, NULL, 0},
{"JIT_LiteralOptimisations", 0, &JIT_LiteralOptimisations, 1, NULL, 0}, {"JIT_LiteralOptimisations", 0, &JIT_LiteralOptimisations, 1, NULL, 0},
{"JIT_FastMemory", 0, &JIT_FastMemory, 1, NULL, 0}, {"JIT_FastMemory", 0, &JIT_FastMemory, 1, NULL, 0},
#endif #endif
@ -104,7 +116,7 @@ void Load()
while (!feof(f)) while (!feof(f))
{ {
fgets(linebuf, 1024, f); fgets(linebuf, 1024, f);
int ret = sscanf(linebuf, "%31[A-Za-z_0-9]=%[^\t\n]", entryname, entryval); int ret = sscanf(linebuf, "%31[A-Za-z_0-9]=%[^\t\r\n]", entryname, entryval);
entryname[31] = '\0'; entryname[31] = '\0';
if (ret < 2) continue; if (ret < 2) continue;
@ -157,7 +169,7 @@ void Save()
if (entry->Type == 0) if (entry->Type == 0)
fprintf(f, "%s=%d\n", entry->Name, *(int*)entry->Value); fprintf(f, "%s=%d\n", entry->Name, *(int*)entry->Value);
else else
fprintf(f, "%s=%s\n", entry->Name, entry->Value); fprintf(f, "%s=%s\n", entry->Name, (char*)entry->Value);
entry++; entry++;
} }

View File

@ -45,11 +45,17 @@ void Save();
extern char BIOS9Path[1024]; extern char BIOS9Path[1024];
extern char BIOS7Path[1024]; extern char BIOS7Path[1024];
extern char FirmwarePath[1024]; extern char FirmwarePath[1024];
extern int DLDIEnable;
extern char DLDISDPath[1024];
extern char DSiBIOS9Path[1024]; extern char DSiBIOS9Path[1024];
extern char DSiBIOS7Path[1024]; extern char DSiBIOS7Path[1024];
extern char DSiFirmwarePath[1024]; extern char DSiFirmwarePath[1024];
extern char DSiNANDPath[1024]; extern char DSiNANDPath[1024];
extern int DSiSDEnable;
extern char DSiSDPath[1024];
extern int RandomizeMAC;
#ifdef JIT_ENABLED #ifdef JIT_ENABLED
extern int JIT_Enable; extern int JIT_Enable;

View File

@ -73,6 +73,8 @@ void DMA::Reset()
SrcAddrInc = 0; SrcAddrInc = 0;
DstAddrInc = 0; DstAddrInc = 0;
Stall = false;
Running = false; Running = false;
InProgress = false; InProgress = false;
@ -111,8 +113,8 @@ void DMA::DoSavestate(Savestate* file)
file->Var32(&DstAddrInc); file->Var32(&DstAddrInc);
file->Var32(&Running); file->Var32(&Running);
file->Var32((u32*)&InProgress); file->Bool32(&InProgress);
file->Var32((u32*)&IsGXFIFODMA); file->Bool32(&IsGXFIFODMA);
} }
void DMA::WriteCnt(u32 val) void DMA::WriteCnt(u32 val)

View File

@ -699,20 +699,37 @@ void MapNWRAMRange(u32 cpu, u32 num, u32 val)
} }
} }
void ApplyNewRAMSize(u32 size)
{
switch (size)
{
case 0:
case 1:
NDS::MainRAMMask = 0x3FFFFF;
printf("RAM: 4MB\n");
break;
case 2:
case 3: // TODO: debug console w/ 32MB?
NDS::MainRAMMask = 0xFFFFFF;
printf("RAM: 16MB\n");
break;
}
}
void Set_SCFG_Clock9(u16 val) void Set_SCFG_Clock9(u16 val)
{ {
SCFG_Clock9 = val & 0x0187;
return;
NDS::ARM9Timestamp >>= NDS::ARM9ClockShift; NDS::ARM9Timestamp >>= NDS::ARM9ClockShift;
NDS::ARM9Target >>= NDS::ARM9ClockShift;
printf("CLOCK9=%04X\n", val); printf("CLOCK9=%04X\n", val);
SCFG_Clock9 = val & 0x0187; SCFG_Clock9 = val & 0x0187;
if (SCFG_Clock9 & (1<<0)) NDS::ARM9ClockShift = 2; if (SCFG_Clock9 & (1<<0)) NDS::ARM9ClockShift = 2;
else NDS::ARM9ClockShift = 1; else NDS::ARM9ClockShift = 1;
NDS::ARM9Timestamp <<= NDS::ARM9ClockShift; NDS::ARM9Timestamp <<= NDS::ARM9ClockShift;
NDS::ARM9Target <<= NDS::ARM9ClockShift;
NDS::ARM9->UpdateRegionTimings(0x00000000, 0xFFFFFFFF); NDS::ARM9->UpdateRegionTimings(0x00000000, 0xFFFFFFFF);
} }
@ -895,6 +912,20 @@ void ARM9Write8(u32 addr, u8 val)
case 0x04000000: case 0x04000000:
ARM9IOWrite8(addr, val); ARM9IOWrite8(addr, val);
return; return;
case 0x06000000:
if (!(SCFG_EXT[0] & (1<<13))) return;
#ifdef JIT_ENABLED
ARMJIT::CheckAndInvalidate<0, ARMJIT_Memory::memregion_VRAM>(addr);
#endif
switch (addr & 0x00E00000)
{
case 0x00000000: GPU::WriteVRAM_ABG<u8>(addr, val); return;
case 0x00200000: GPU::WriteVRAM_BBG<u8>(addr, val); return;
case 0x00400000: GPU::WriteVRAM_AOBJ<u8>(addr, val); return;
case 0x00600000: GPU::WriteVRAM_BOBJ<u8>(addr, val); return;
default: GPU::WriteVRAM_LCDC<u8>(addr, val); return;
}
} }
return NDS::ARM9Write8(addr, val); return NDS::ARM9Write8(addr, val);
@ -1549,25 +1580,37 @@ void ARM9IOWrite32(u32 addr, u32 val)
switch (addr) switch (addr)
{ {
case 0x04004008: case 0x04004008:
SCFG_EXT[0] &= ~0x8007F19F;
SCFG_EXT[0] |= (val & 0x8007F19F);
SCFG_EXT[1] &= ~0x0000F080;
SCFG_EXT[1] |= (val & 0x0000F080);
printf("SCFG_EXT = %08X / %08X (val9 %08X)\n", SCFG_EXT[0], SCFG_EXT[1], val);
/*switch ((SCFG_EXT[0] >> 14) & 0x3)
{ {
case 0: u32 oldram = (SCFG_EXT[0] >> 14) & 0x3;
case 1: u32 newram = (val >> 14) & 0x3;
NDS::MainRAMMask = 0x3FFFFF;
printf("RAM: 4MB\n"); SCFG_EXT[0] &= ~0x8007F19F;
break; SCFG_EXT[0] |= (val & 0x8007F19F);
case 2: SCFG_EXT[1] &= ~0x0000F080;
case 3: // TODO: debug console w/ 32MB? SCFG_EXT[1] |= (val & 0x0000F080);
NDS::MainRAMMask = 0xFFFFFF; printf("SCFG_EXT = %08X / %08X (val9 %08X)\n", SCFG_EXT[0], SCFG_EXT[1], val);
printf("RAM: 16MB\n"); /*switch ((SCFG_EXT[0] >> 14) & 0x3)
break; {
}*/ case 0:
printf("from %08X, ARM7 %08X, %08X\n", NDS::GetPC(0), NDS::GetPC(1), NDS::ARM7->R[1]); case 1:
NDS::MainRAMMask = 0x3FFFFF;
printf("RAM: 4MB\n");
//baziderp=true;
break;
case 2:
case 3: // TODO: debug console w/ 32MB?
NDS::MainRAMMask = 0xFFFFFF;
printf("RAM: 16MB\n");
break;
}*/
// HAX!!
// a change to the RAM size setting is supposed to apply immediately (it does so on hardware)
// however, doing so will cause DS-mode app startup to break, because the change happens while the ARM7
// is still busy clearing/relocating shit
//if (newram != oldram)
// NDS::ScheduleEvent(NDS::Event_DSi_RAMSizeChange, false, 512*512*512, ApplyNewRAMSize, newram);
printf("from %08X, ARM7 %08X, %08X\n", NDS::GetPC(0), NDS::GetPC(1), NDS::ARM7->R[1]);
}
return; return;
case 0x04004040: case 0x04004040:
@ -1660,7 +1703,7 @@ u8 ARM7IORead8(u32 addr)
case 0x04004501: return DSi_I2C::Cnt; case 0x04004501: return DSi_I2C::Cnt;
case 0x04004D00: if (SCFG_BIOS & (1<<10)) return 0; return ConsoleID & 0xFF; case 0x04004D00: if (SCFG_BIOS & (1<<10)) return 0; return ConsoleID & 0xFF;
case 0x04004fD01: if (SCFG_BIOS & (1<<10)) return 0; return (ConsoleID >> 8) & 0xFF; case 0x04004D01: if (SCFG_BIOS & (1<<10)) return 0; return (ConsoleID >> 8) & 0xFF;
case 0x04004D02: if (SCFG_BIOS & (1<<10)) return 0; return (ConsoleID >> 16) & 0xFF; case 0x04004D02: if (SCFG_BIOS & (1<<10)) return 0; return (ConsoleID >> 16) & 0xFF;
case 0x04004D03: if (SCFG_BIOS & (1<<10)) return 0; return (ConsoleID >> 24) & 0xFF; case 0x04004D03: if (SCFG_BIOS & (1<<10)) return 0; return (ConsoleID >> 24) & 0xFF;
case 0x04004D04: if (SCFG_BIOS & (1<<10)) return 0; return (ConsoleID >> 32) & 0xFF; case 0x04004D04: if (SCFG_BIOS & (1<<10)) return 0; return (ConsoleID >> 32) & 0xFF;

View File

@ -52,6 +52,10 @@ u8 KeyY[4][16];
u8 CurKey[16]; u8 CurKey[16];
u8 CurMAC[16]; u8 CurMAC[16];
// output MAC for CCM encrypt
u8 OutputMAC[16];
bool OutputMACDue;
AES_ctx Ctx; AES_ctx Ctx;
@ -129,6 +133,9 @@ void Reset()
memset(CurKey, 0, sizeof(CurKey)); memset(CurKey, 0, sizeof(CurKey));
memset(CurMAC, 0, sizeof(CurMAC)); memset(CurMAC, 0, sizeof(CurMAC));
memset(OutputMAC, 0, sizeof(OutputMAC));
OutputMACDue = false;
// initialize keys // initialize keys
// slot 0: modcrypt // slot 0: modcrypt
@ -272,6 +279,8 @@ void WriteCnt(u32 val)
// transfer start (checkme) // transfer start (checkme)
RemBlocks = BlkCnt >> 16; RemBlocks = BlkCnt >> 16;
OutputMACDue = false;
if (AESMode == 0 && (!(val & (1<<20)))) printf("AES: CCM-DECRYPT MAC FROM WRFIFO, TODO\n"); if (AESMode == 0 && (!(val & (1<<20)))) printf("AES: CCM-DECRYPT MAC FROM WRFIFO, TODO\n");
if (RemBlocks > 0) if (RemBlocks > 0)
@ -347,6 +356,15 @@ u32 ReadOutputFIFO()
DSi::CheckNDMAs(1, 0x2B); DSi::CheckNDMAs(1, 0x2B);
else else
DSi::StopNDMAs(1, 0x2B); DSi::StopNDMAs(1, 0x2B);
if (OutputMACDue && OutputFIFO->Level() <= 12)
{
OutputFIFO->Write(*(u32*)&OutputMAC[0]);
OutputFIFO->Write(*(u32*)&OutputMAC[4]);
OutputFIFO->Write(*(u32*)&OutputMAC[8]);
OutputFIFO->Write(*(u32*)&OutputMAC[12]);
OutputMACDue = false;
}
} }
return ret; return ret;
@ -429,13 +447,8 @@ void Update()
Ctx.Iv[15] = 0x00; Ctx.Iv[15] = 0x00;
AES_CTR_xcrypt_buffer(&Ctx, CurMAC, 16); AES_CTR_xcrypt_buffer(&Ctx, CurMAC, 16);
u8 finalmac[16]; Swap16(OutputMAC, CurMAC);
Swap16(finalmac, CurMAC); OutputMACDue = true;
OutputFIFO->Write(*(u32*)&finalmac[0]);
OutputFIFO->Write(*(u32*)&finalmac[4]);
OutputFIFO->Write(*(u32*)&finalmac[8]);
OutputFIFO->Write(*(u32*)&finalmac[12]);
// CHECKME // CHECKME
Cnt &= ~(1<<21); Cnt &= ~(1<<21);

View File

@ -140,7 +140,7 @@ u16 DSi_Camera::ReadReg(u16 addr)
case 0x301A: return ((~StandbyCnt) & 0x4000) >> 12; case 0x301A: return ((~StandbyCnt) & 0x4000) >> 12;
} }
printf("DSi_Camera%d: unknown read %04X\n", Num, addr); //printf("DSi_Camera%d: unknown read %04X\n", Num, addr);
return 0; return 0;
} }
@ -162,5 +162,5 @@ void DSi_Camera::WriteReg(u16 addr, u16 val)
return; return;
} }
printf("DSi_Camera%d: unknown write %04X %04X\n", Num, addr, val); //printf("DSi_Camera%d: unknown write %04X %04X\n", Num, addr, val);
} }

View File

@ -165,6 +165,36 @@ void DSi_NWifi::Reset()
printf("NWifi MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", printf("NWifi MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
u8 type = SPI_Firmware::GetNWifiVersion();
switch (type)
{
case 1: // AR6002
ROMID = 0x20000188;
ChipID = 0x02000001;
HostIntAddr = 0x00500400;
break;
case 2: // AR6013
ROMID = 0x23000024;
ChipID = 0x0D000000;
HostIntAddr = 0x00520000;
break;
case 3: // AR6014 (3DS)
ROMID = 0x2300006F;
ChipID = 0x0D000001;
HostIntAddr = 0x00520000;
printf("NWifi: hardware is 3DS type, unchecked\n");
break;
default:
printf("NWifi: unknown hardware type %02X, assuming AR6002\n");
ROMID = 0x20000188;
ChipID = 0x02000001;
HostIntAddr = 0x00500400;
break;
}
memset(EEPROM, 0, 0x400); memset(EEPROM, 0, 0x400);
*(u32*)&EEPROM[0x000] = 0x300; *(u32*)&EEPROM[0x000] = 0x300;
@ -755,8 +785,7 @@ void DSi_NWifi::BMI_Command()
case 0x08: // BMI_GET_TARGET_ID case 0x08: // BMI_GET_TARGET_ID
MB_Write32(4, 0xFFFFFFFF); MB_Write32(4, 0xFFFFFFFF);
MB_Write32(4, 0x0000000C); MB_Write32(4, 0x0000000C);
//MB_Write32(4, 0x20000118); MB_Write32(4, ROMID);
MB_Write32(4, 0x23000024); // ROM version (TODO: how to determine correct one?)
MB_Write32(4, 0x00000002); MB_Write32(4, 0x00000002);
return; return;
@ -1436,7 +1465,7 @@ u32 DSi_NWifi::WindowRead(u32 addr)
{ {
printf("NWifi: window read %08X\n", addr); printf("NWifi: window read %08X\n", addr);
if ((addr & 0xFFFF00) == 0x520000) if ((addr & 0xFFFF00) == HostIntAddr)
{ {
// RAM host interest area // RAM host interest area
// TODO: different base based on hardware version // TODO: different base based on hardware version
@ -1462,9 +1491,7 @@ u32 DSi_NWifi::WindowRead(u32 addr)
switch (addr) switch (addr)
{ {
case 0x40EC: // chip ID case 0x40EC: // chip ID
// 0D000000 / 0D000001 == AR6013 return ChipID;
// TODO: check firmware.bin to determine the correct value
return 0x0D000001;
// SOC_RESET_CAUSE // SOC_RESET_CAUSE
case 0x40C0: return 2; case 0x40C0: return 2;

View File

@ -127,6 +127,10 @@ private:
u32 WindowData, WindowReadAddr, WindowWriteAddr; u32 WindowData, WindowReadAddr, WindowWriteAddr;
u32 ROMID;
u32 ChipID;
u32 HostIntAddr;
u8 EEPROM[0x400]; u8 EEPROM[0x400];
u32 EEPROMReady; u32 EEPROMReady;

View File

@ -117,13 +117,19 @@ void DSi_SDHost::Reset()
if (Num == 0) if (Num == 0)
{ {
// TODO: eventually pull from host filesystem DSi_MMCStorage* sd;
/*DSi_MMCStorage* sd = new DSi_MMCStorage(this, false, "sd.bin"); DSi_MMCStorage* mmc;
u8 sd_cid[16] = {0xBD, 0x12, 0x34, 0x56, 0x78, 0x03, 0x4D, 0x30, 0x30, 0x46, 0x50, 0x41, 0x00, 0x00, 0x15, 0x00};
sd->SetCID(sd_cid);*/
DSi_MMCStorage* sd = NULL;
DSi_MMCStorage* mmc = new DSi_MMCStorage(this, true, Config::DSiNANDPath); if (Config::DSiSDEnable)
{
sd = new DSi_MMCStorage(this, false, Config::DSiSDPath);
u8 sd_cid[16] = {0xBD, 0x12, 0x34, 0x56, 0x78, 0x03, 0x4D, 0x30, 0x30, 0x46, 0x50, 0x41, 0x00, 0x00, 0x15, 0x00};
sd->SetCID(sd_cid);
}
else
sd = nullptr;
mmc = new DSi_MMCStorage(this, true, Config::DSiNANDPath);
mmc->SetCID(DSi::eMMC_CID); mmc->SetCID(DSi::eMMC_CID);
Ports[0] = sd; Ports[0] = sd;
@ -429,14 +435,14 @@ u16 DSi_SDHost::Read(u32 addr)
if (!Num) if (!Num)
{ {
if (Ports[0]) // basic check of whether the SD card is inserted if (Ports[0]) // basic check of whether the SD card is inserted
ret |= 0x0030; ret |= 0x00B0;
else else
ret |= 0x0008; ret |= 0x0008;
} }
else else
{ {
// SDIO wifi is always inserted, I guess // SDIO wifi is always inserted, I guess
ret |= 0x0030; ret |= 0x00B0;
} }
return ret; return ret;
} }

View File

@ -103,7 +103,7 @@ class DSi_SDDevice
{ {
public: public:
DSi_SDDevice(DSi_SDHost* host) { Host = host; IRQ = false; } DSi_SDDevice(DSi_SDHost* host) { Host = host; IRQ = false; }
~DSi_SDDevice() {} virtual ~DSi_SDDevice() {}
virtual void Reset() = 0; virtual void Reset() = 0;

View File

@ -280,6 +280,7 @@ void AssignFramebuffers()
void InitRenderer(int renderer) void InitRenderer(int renderer)
{ {
#ifdef OGLRENDERER_ENABLED
if (renderer == 1) if (renderer == 1)
{ {
if (!GLCompositor::Init()) if (!GLCompositor::Init())
@ -292,8 +293,8 @@ void InitRenderer(int renderer)
renderer = 0; renderer = 0;
} }
} }
else
if (renderer == 0) #endif
{ {
GPU3D::SoftRenderer::Init(); GPU3D::SoftRenderer::Init();
} }
@ -308,11 +309,13 @@ void DeInitRenderer()
{ {
GPU3D::SoftRenderer::DeInit(); GPU3D::SoftRenderer::DeInit();
} }
#ifdef OGLRENDERER_ENABLED
else else
{ {
GPU3D::GLRenderer::DeInit(); GPU3D::GLRenderer::DeInit();
GLCompositor::DeInit(); GLCompositor::DeInit();
} }
#endif
} }
void ResetRenderer() void ResetRenderer()
@ -321,11 +324,13 @@ void ResetRenderer()
{ {
GPU3D::SoftRenderer::Reset(); GPU3D::SoftRenderer::Reset();
} }
#ifdef OGLRENDERER_ENABLED
else else
{ {
GLCompositor::Reset(); GLCompositor::Reset();
GPU3D::GLRenderer::Reset(); GPU3D::GLRenderer::Reset();
} }
#endif
} }
void SetRenderSettings(int renderer, RenderSettings& settings) void SetRenderSettings(int renderer, RenderSettings& settings)
@ -364,11 +369,13 @@ void SetRenderSettings(int renderer, RenderSettings& settings)
{ {
GPU3D::SoftRenderer::SetRenderSettings(settings); GPU3D::SoftRenderer::SetRenderSettings(settings);
} }
#ifdef OGLRENDERER_ENABLED
else else
{ {
GLCompositor::SetRenderSettings(settings); GLCompositor::SetRenderSettings(settings);
GPU3D::GLRenderer::SetRenderSettings(settings); GPU3D::GLRenderer::SetRenderSettings(settings);
} }
#endif
} }
@ -1055,7 +1062,9 @@ void StartScanline(u32 line)
GPU2D_B->VBlank(); GPU2D_B->VBlank();
GPU3D::VBlank(); GPU3D::VBlank();
#ifdef OGLRENDERER_ENABLED
if (Accelerated) GLCompositor::RenderFrame(); if (Accelerated) GLCompositor::RenderFrame();
#endif
} }
else if (VCount == 144) else if (VCount == 144)
{ {

View File

@ -79,6 +79,7 @@ typedef struct
bool Soft_Threaded; bool Soft_Threaded;
int GL_ScaleFactor; int GL_ScaleFactor;
bool GL_BetterPolygons;
} RenderSettings; } RenderSettings;
@ -436,6 +437,7 @@ void SetDispStat(u32 cpu, u16 val);
void SetVCount(u16 val); void SetVCount(u16 val);
#ifdef OGLRENDERER_ENABLED
namespace GLCompositor namespace GLCompositor
{ {
@ -449,6 +451,7 @@ void RenderFrame();
void BindOutputTexture(); void BindOutputTexture();
} }
#endif
} }

View File

@ -35,9 +35,6 @@
// * [Gericom] bit15 is used as bottom green bit for palettes. TODO: check where this applies. // * [Gericom] bit15 is used as bottom green bit for palettes. TODO: check where this applies.
// tested on the normal BG palette and applies there // tested on the normal BG palette and applies there
// //
// oh also, changing DISPCNT bit16-17 midframe doesn't work (ignored? applied for next frame?)
// TODO, eventually: check whether other DISPCNT bits can be changed midframe
//
// for VRAM display mode, VRAM must be mapped to LCDC // for VRAM display mode, VRAM must be mapped to LCDC
// //
// FIFO display mode: // FIFO display mode:
@ -78,7 +75,10 @@
// * for rotscaled sprites: coordinates that are inside the sprite are clamped to the sprite region // * for rotscaled sprites: coordinates that are inside the sprite are clamped to the sprite region
// after being transformed for mosaic // after being transformed for mosaic
// TODO: find which parts of DISPCNT are latched. for example, not possible to change video mode midframe. // TODO: master brightness, display capture and mainmem FIFO are separate circuitry, distinct from
// the tile renderers.
// for example these aren't affected by POWCNT GPU-disable bits.
// to model the hardware more accurately, the relevant logic should be moved to GPU.cpp.
GPU2D::GPU2D(u32 num) GPU2D::GPU2D(u32 num)
@ -102,6 +102,7 @@ GPU2D::~GPU2D()
void GPU2D::Reset() void GPU2D::Reset()
{ {
Enabled = false;
DispCnt = 0; DispCnt = 0;
memset(BGCnt, 0, 4*2); memset(BGCnt, 0, 4*2);
memset(BGXPos, 0, 4*2); memset(BGXPos, 0, 4*2);
@ -309,8 +310,6 @@ u32 GPU2D::Read32(u32 addr)
void GPU2D::Write8(u32 addr, u8 val) void GPU2D::Write8(u32 addr, u8 val)
{ {
if (!Enabled) return;
switch (addr & 0x00000FFF) switch (addr & 0x00000FFF)
{ {
case 0x000: case 0x000:
@ -329,7 +328,12 @@ void GPU2D::Write8(u32 addr, u8 val)
DispCnt = (DispCnt & 0x00FFFFFF) | (val << 24); DispCnt = (DispCnt & 0x00FFFFFF) | (val << 24);
if (Num) DispCnt &= 0xC0B1FFF7; if (Num) DispCnt &= 0xC0B1FFF7;
return; return;
}
if (!Enabled) return;
switch (addr & 0x00000FFF)
{
case 0x008: BGCnt[0] = (BGCnt[0] & 0xFF00) | val; return; case 0x008: BGCnt[0] = (BGCnt[0] & 0xFF00) | val; return;
case 0x009: BGCnt[0] = (BGCnt[0] & 0x00FF) | (val << 8); return; case 0x009: BGCnt[0] = (BGCnt[0] & 0x00FF) | (val << 8); return;
case 0x00A: BGCnt[1] = (BGCnt[1] & 0xFF00) | val; return; case 0x00A: BGCnt[1] = (BGCnt[1] & 0xFF00) | val; return;
@ -405,8 +409,6 @@ void GPU2D::Write8(u32 addr, u8 val)
void GPU2D::Write16(u32 addr, u16 val) void GPU2D::Write16(u32 addr, u16 val)
{ {
if (!Enabled) return;
switch (addr & 0x00000FFF) switch (addr & 0x00000FFF)
{ {
case 0x000: case 0x000:
@ -418,6 +420,22 @@ void GPU2D::Write16(u32 addr, u16 val)
if (Num) DispCnt &= 0xC0B1FFF7; if (Num) DispCnt &= 0xC0B1FFF7;
return; return;
case 0x068:
DispFIFO[DispFIFOWritePtr] = val;
return;
case 0x06A:
DispFIFO[DispFIFOWritePtr+1] = val;
DispFIFOWritePtr += 2;
DispFIFOWritePtr &= 0xF;
return;
case 0x06C: MasterBrightness = val; return;
}
if (!Enabled) return;
switch (addr & 0x00000FFF)
{
case 0x008: BGCnt[0] = val; return; case 0x008: BGCnt[0] = val; return;
case 0x00A: BGCnt[1] = val; return; case 0x00A: BGCnt[1] = val; return;
case 0x00C: BGCnt[2] = val; return; case 0x00C: BGCnt[2] = val; return;
@ -526,17 +544,6 @@ void GPU2D::Write16(u32 addr, u16 val)
EVY = val & 0x1F; EVY = val & 0x1F;
if (EVY > 16) EVY = 16; if (EVY > 16) EVY = 16;
return; return;
case 0x068:
DispFIFO[DispFIFOWritePtr] = val;
return;
case 0x06A:
DispFIFO[DispFIFOWritePtr+1] = val;
DispFIFOWritePtr += 2;
DispFIFOWritePtr &= 0xF;
return;
case 0x06C: MasterBrightness = val; return;
} }
//printf("unknown GPU write16 %08X %04X\n", addr, val); //printf("unknown GPU write16 %08X %04X\n", addr, val);
@ -544,8 +551,6 @@ void GPU2D::Write16(u32 addr, u16 val)
void GPU2D::Write32(u32 addr, u32 val) void GPU2D::Write32(u32 addr, u32 val)
{ {
if (!Enabled) return;
switch (addr & 0x00000FFF) switch (addr & 0x00000FFF)
{ {
case 0x000: case 0x000:
@ -553,6 +558,24 @@ void GPU2D::Write32(u32 addr, u32 val)
if (Num) DispCnt &= 0xC0B1FFF7; if (Num) DispCnt &= 0xC0B1FFF7;
return; return;
case 0x064:
// TODO: check what happens when writing to it during display
// esp. if a capture is happening
CaptureCnt = val & 0xEF3F1F1F;
return;
case 0x068:
DispFIFO[DispFIFOWritePtr] = val & 0xFFFF;
DispFIFO[DispFIFOWritePtr+1] = val >> 16;
DispFIFOWritePtr += 2;
DispFIFOWritePtr &= 0xF;
return;
}
if (!Enabled) return;
switch (addr & 0x00000FFF)
{
case 0x028: case 0x028:
if (val & 0x08000000) val |= 0xF0000000; if (val & 0x08000000) val |= 0xF0000000;
BGXRef[0] = val; BGXRef[0] = val;
@ -574,19 +597,6 @@ void GPU2D::Write32(u32 addr, u32 val)
BGYRef[1] = val; BGYRef[1] = val;
if (GPU::VCount < 192) BGYRefInternal[1] = BGYRef[1]; if (GPU::VCount < 192) BGYRefInternal[1] = BGYRef[1];
return; return;
case 0x064:
// TODO: check what happens when writing to it during display
// esp. if a capture is happening
CaptureCnt = val & 0xEF3F1F1F;
return;
case 0x068:
DispFIFO[DispFIFOWritePtr] = val & 0xFFFF;
DispFIFO[DispFIFOWritePtr+1] = val >> 16;
DispFIFOWritePtr += 2;
DispFIFOWritePtr &= 0xF;
return;
} }
Write16(addr, val&0xFFFF); Write16(addr, val&0xFFFF);
@ -805,7 +815,6 @@ void GPU2D::DrawScanline(u32 line)
int i = 0; int i = 0;
for (; i < (stride & ~1); i+=2) for (; i < (stride & ~1); i+=2)
*(u64*)&dst[i] = *(u64*)&BGOBJLine[i]; *(u64*)&dst[i] = *(u64*)&BGOBJLine[i];
if (stride & 1) dst[i] = BGOBJLine[i];
} }
break; break;
@ -940,6 +949,7 @@ void GPU2D::VBlankEnd()
//OBJMosaicY = 0; //OBJMosaicY = 0;
//OBJMosaicYCount = 0; //OBJMosaicYCount = 0;
#ifdef OGLRENDERER_ENABLED
if (Accelerated) if (Accelerated)
{ {
if ((Num == 0) && (CaptureCnt & (1<<31)) && (((CaptureCnt >> 29) & 0x3) != 1)) if ((Num == 0) && (CaptureCnt & (1<<31)) && (((CaptureCnt >> 29) & 0x3) != 1))
@ -947,6 +957,7 @@ void GPU2D::VBlankEnd()
GPU3D::GLRenderer::PrepareCaptureFrame(); GPU3D::GLRenderer::PrepareCaptureFrame();
} }
} }
#endif
} }

View File

@ -401,8 +401,33 @@ void DoSavestate(Savestate* file)
file->Var32(&NumTestCommands); file->Var32(&NumTestCommands);
file->Var32(&DispCnt); file->Var32(&DispCnt);
file->Var8(&AlphaRefVal);
file->Var8(&AlphaRef); file->Var8(&AlphaRef);
file->VarArray(ToonTable, 32*2);
file->VarArray(EdgeTable, 8*2);
file->Var32(&FogColor);
file->Var32(&FogOffset);
file->VarArray(FogDensityTable, 32);
file->Var32(&ClearAttr1);
file->Var32(&ClearAttr2);
file->Var32(&RenderDispCnt);
file->Var8(&RenderAlphaRef);
file->VarArray(RenderToonTable, 32*2);
file->VarArray(RenderEdgeTable, 8*2);
file->Var32(&RenderFogColor);
file->Var32(&RenderFogOffset);
file->Var32(&RenderFogShift);
file->VarArray(RenderFogDensityTable, 34);
file->Var32(&RenderClearAttr1);
file->Var32(&RenderClearAttr2);
file->Var32(&ZeroDotWLimit); file->Var32(&ZeroDotWLimit);
file->Var32(&GXStat); file->Var32(&GXStat);
@ -445,7 +470,7 @@ void DoSavestate(Savestate* file)
file->VarArray(vtx->Color, sizeof(s32)*3); file->VarArray(vtx->Color, sizeof(s32)*3);
file->VarArray(vtx->TexCoords, sizeof(s16)*2); file->VarArray(vtx->TexCoords, sizeof(s16)*2);
file->Var32((u32*)&vtx->Clipped); file->Bool32(&vtx->Clipped);
file->VarArray(vtx->FinalPosition, sizeof(s32)*2); file->VarArray(vtx->FinalPosition, sizeof(s32)*2);
file->VarArray(vtx->FinalColor, sizeof(s32)*3); file->VarArray(vtx->FinalColor, sizeof(s32)*3);
@ -471,9 +496,6 @@ void DoSavestate(Savestate* file)
file->Var32(&NumPolygons); file->Var32(&NumPolygons);
file->Var32(&NumOpaquePolygons); file->Var32(&NumOpaquePolygons);
file->Var32(&ClearAttr1);
file->Var32(&ClearAttr2);
file->Var32(&FlushRequest); file->Var32(&FlushRequest);
file->Var32(&FlushAttributes); file->Var32(&FlushAttributes);
@ -485,7 +507,7 @@ void DoSavestate(Savestate* file)
file->VarArray(vtx->Color, sizeof(s32)*3); file->VarArray(vtx->Color, sizeof(s32)*3);
file->VarArray(vtx->TexCoords, sizeof(s16)*2); file->VarArray(vtx->TexCoords, sizeof(s16)*2);
file->Var32((u32*)&vtx->Clipped); file->Bool32(&vtx->Clipped);
file->VarArray(vtx->FinalPosition, sizeof(s32)*2); file->VarArray(vtx->FinalPosition, sizeof(s32)*2);
file->VarArray(vtx->FinalColor, sizeof(s32)*3); file->VarArray(vtx->FinalColor, sizeof(s32)*3);
@ -523,17 +545,17 @@ void DoSavestate(Savestate* file)
file->VarArray(poly->FinalZ, sizeof(s32)*10); file->VarArray(poly->FinalZ, sizeof(s32)*10);
file->VarArray(poly->FinalW, sizeof(s32)*10); file->VarArray(poly->FinalW, sizeof(s32)*10);
file->Var32((u32*)&poly->WBuffer); file->Bool32(&poly->WBuffer);
file->Var32(&poly->Attr); file->Var32(&poly->Attr);
file->Var32(&poly->TexParam); file->Var32(&poly->TexParam);
file->Var32(&poly->TexPalette); file->Var32(&poly->TexPalette);
file->Var32((u32*)&poly->FacingView); file->Bool32(&poly->FacingView);
file->Var32((u32*)&poly->Translucent); file->Bool32(&poly->Translucent);
file->Var32((u32*)&poly->IsShadowMask); file->Bool32(&poly->IsShadowMask);
file->Var32((u32*)&poly->IsShadow); file->Bool32(&poly->IsShadow);
if (file->IsAtleastVersion(4, 1)) if (file->IsAtleastVersion(4, 1))
file->Var32((u32*)&poly->Type); file->Var32((u32*)&poly->Type);
@ -2506,13 +2528,19 @@ void VBlank()
void VCount215() void VCount215()
{ {
if (GPU::Renderer == 0) SoftRenderer::RenderFrame(); if (GPU::Renderer == 0) SoftRenderer::RenderFrame();
#ifdef OGLRENDERER_ENABLED
else GLRenderer::RenderFrame(); else GLRenderer::RenderFrame();
#endif
} }
u32* GetLine(int line) u32* GetLine(int line)
{ {
if (GPU::Renderer == 0) return SoftRenderer::GetLine(line); if (GPU::Renderer == 0) return SoftRenderer::GetLine(line);
#ifdef OGLRENDERER_ENABLED
else return GLRenderer::GetLine(line); else return GLRenderer::GetLine(line);
#else
return NULL;
#endif
} }

View File

@ -139,6 +139,7 @@ u32* GetLine(int line);
} }
#ifdef OGLRENDERER_ENABLED
namespace GLRenderer namespace GLRenderer
{ {
@ -154,6 +155,7 @@ u32* GetLine(int line);
void SetupAccelFrame(); void SetupAccelFrame();
} }
#endif
} }

View File

@ -113,7 +113,7 @@ GLuint TexMemID;
GLuint TexPalMemID; GLuint TexPalMemID;
int ScaleFactor; int ScaleFactor;
bool Antialias; bool BetterPolygons;
int ScreenW, ScreenH; int ScreenW, ScreenH;
GLuint FramebufferTex[8]; GLuint FramebufferTex[8];
@ -342,9 +342,6 @@ bool Init()
SetupDefaultTexParams(FramebufferTex[5]); SetupDefaultTexParams(FramebufferTex[5]);
SetupDefaultTexParams(FramebufferTex[7]); SetupDefaultTexParams(FramebufferTex[7]);
// downscale framebuffer for antialiased mode
SetupDefaultTexParams(FramebufferTex[2]);
// downscale framebuffer for display capture (always 256x192) // downscale framebuffer for display capture (always 256x192)
SetupDefaultTexParams(FramebufferTex[3]); SetupDefaultTexParams(FramebufferTex[3]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 192, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 192, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
@ -372,6 +369,8 @@ bool Init()
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1, 1024, 48, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, NULL); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1, 1024, 48, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, NULL);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
return true; return true;
} }
@ -404,52 +403,27 @@ void Reset()
void SetRenderSettings(GPU::RenderSettings& settings) void SetRenderSettings(GPU::RenderSettings& settings)
{ {
int scale = settings.GL_ScaleFactor; int scale = settings.GL_ScaleFactor;
bool antialias = false; // REMOVE ME!
if (antialias) scale *= 2;
ScaleFactor = scale; ScaleFactor = scale;
Antialias = antialias; BetterPolygons = settings.GL_BetterPolygons;
ScreenW = 256 * scale; ScreenW = 256 * scale;
ScreenH = 192 * scale; ScreenH = 192 * scale;
if (!antialias) glBindTexture(GL_TEXTURE_2D, FramebufferTex[0]);
{ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ScreenW, ScreenH, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, FramebufferTex[0]); glBindTexture(GL_TEXTURE_2D, FramebufferTex[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ScreenW, ScreenH, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ScreenW, ScreenH, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, FramebufferTex[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ScreenW, ScreenH, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glBindTexture(GL_TEXTURE_2D, FramebufferTex[4]);
glBindTexture(GL_TEXTURE_2D, FramebufferTex[2]); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, ScreenW, ScreenH, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glBindTexture(GL_TEXTURE_2D, FramebufferTex[5]);
glBindTexture(GL_TEXTURE_2D, FramebufferTex[4]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, ScreenW, ScreenH, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, ScreenW, ScreenH, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
//glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH32F_STENCIL8, ScreenW, ScreenH, 0, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, NULL); glBindTexture(GL_TEXTURE_2D, FramebufferTex[6]);
glBindTexture(GL_TEXTURE_2D, FramebufferTex[5]); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, ScreenW, ScreenH, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
//glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8UI, ScreenW, ScreenH, 0, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, NULL); glBindTexture(GL_TEXTURE_2D, FramebufferTex[7]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, ScreenW, ScreenH, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, ScreenW, ScreenH, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, FramebufferTex[6]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, 1, 1, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
glBindTexture(GL_TEXTURE_2D, FramebufferTex[7]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8UI, 1, 1, 0, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, NULL);
}
else
{
glBindTexture(GL_TEXTURE_2D, FramebufferTex[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ScreenW/2, ScreenH/2, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, FramebufferTex[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ScreenW/2, ScreenH/2, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, FramebufferTex[2]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ScreenW, ScreenH, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, FramebufferTex[4]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, ScreenW/2, ScreenH/2, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
glBindTexture(GL_TEXTURE_2D, FramebufferTex[5]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8UI, ScreenW/2, ScreenH/2, 0, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, FramebufferTex[6]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, ScreenW, ScreenH, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
glBindTexture(GL_TEXTURE_2D, FramebufferTex[7]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8UI, ScreenW, ScreenH, 0, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, NULL);
}
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferID[3]); glBindFramebuffer(GL_FRAMEBUFFER, FramebufferID[3]);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, FramebufferTex[3], 0); glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, FramebufferTex[3], 0);
@ -464,12 +438,6 @@ void SetRenderSettings(GPU::RenderSettings& settings)
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferID[1]); glBindFramebuffer(GL_FRAMEBUFFER, FramebufferID[1]);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, FramebufferTex[1], 0); glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, FramebufferTex[1], 0);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, FramebufferTex[4], 0);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, FramebufferTex[5], 0);
glDrawBuffers(2, fbassign);
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferID[2]);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, FramebufferTex[2], 0);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, FramebufferTex[6], 0); glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, FramebufferTex[6], 0);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, FramebufferTex[7], 0); glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, FramebufferTex[7], 0);
glDrawBuffers(2, fbassign); glDrawBuffers(2, fbassign);
@ -479,6 +447,8 @@ void SetRenderSettings(GPU::RenderSettings& settings)
glBindBuffer(GL_PIXEL_PACK_BUFFER, PixelbufferID); glBindBuffer(GL_PIXEL_PACK_BUFFER, PixelbufferID);
glBufferData(GL_PIXEL_PACK_BUFFER, 256*192*4, NULL, GL_DYNAMIC_READ); glBufferData(GL_PIXEL_PACK_BUFFER, 256*192*4, NULL, GL_DYNAMIC_READ);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
//glLineWidth(scale); //glLineWidth(scale);
//glLineWidth(1.5); //glLineWidth(1.5);
} }
@ -527,6 +497,67 @@ void SetupPolygon(RendererPolygon* rp, Polygon* polygon)
} }
} }
u32* SetupVertex(Polygon* poly, int vid, Vertex* vtx, u32 vtxattr, u32* vptr)
{
u32 z = poly->FinalZ[vid];
u32 w = poly->FinalW[vid];
u32 alpha = (poly->Attr >> 16) & 0x1F;
// Z should always fit within 16 bits, so it's okay to do this
u32 zshift = 0;
while (z > 0xFFFF) { z >>= 1; zshift++; }
u32 x, y;
if (ScaleFactor > 1)
{
x = (vtx->HiresPosition[0] * ScaleFactor) >> 4;
y = (vtx->HiresPosition[1] * ScaleFactor) >> 4;
}
else
{
x = vtx->FinalPosition[0];
y = vtx->FinalPosition[1];
}
// correct nearly-vertical edges that would look vertical on the DS
/*{
int vtopid = vid - 1;
if (vtopid < 0) vtopid = poly->NumVertices-1;
Vertex* vtop = poly->Vertices[vtopid];
if (vtop->FinalPosition[1] >= vtx->FinalPosition[1])
{
vtopid = vid + 1;
if (vtopid >= poly->NumVertices) vtopid = 0;
vtop = poly->Vertices[vtopid];
}
if ((vtop->FinalPosition[1] < vtx->FinalPosition[1]) &&
(vtx->FinalPosition[0] == vtop->FinalPosition[0]-1))
{
if (ScaleFactor > 1)
x = (vtop->HiresPosition[0] * ScaleFactor) >> 4;
else
x = vtop->FinalPosition[0];
}
}*/
*vptr++ = x | (y << 16);
*vptr++ = z | (w << 16);
*vptr++ = (vtx->FinalColor[0] >> 1) |
((vtx->FinalColor[1] >> 1) << 8) |
((vtx->FinalColor[2] >> 1) << 16) |
(alpha << 24);
*vptr++ = (u16)vtx->TexCoords[0] | ((u16)vtx->TexCoords[1] << 16);
*vptr++ = vtxattr | (zshift << 16);
*vptr++ = poly->TexParam;
*vptr++ = poly->TexPalette;
return vptr;
}
void BuildPolygons(RendererPolygon* polygons, int npolys) void BuildPolygons(RendererPolygon* polygons, int npolys)
{ {
u32* vptr = &VertexBuffer[0]; u32* vptr = &VertexBuffer[0];
@ -564,43 +595,16 @@ void BuildPolygons(RendererPolygon* polygons, int npolys)
{ {
Vertex* vtx = poly->Vertices[j]; Vertex* vtx = poly->Vertices[j];
u32 z = poly->FinalZ[j];
u32 w = poly->FinalW[j];
// Z should always fit within 16 bits, so it's okay to do this
u32 zshift = 0;
while (z > 0xFFFF) { z >>= 1; zshift++; }
u32 x, y;
if (ScaleFactor > 1)
{
x = (vtx->HiresPosition[0] * ScaleFactor) >> 4;
y = (vtx->HiresPosition[1] * ScaleFactor) >> 4;
}
else
{
x = vtx->FinalPosition[0];
y = vtx->FinalPosition[1];
}
if (j > 0) if (j > 0)
{ {
if (lastx == x && lasty == y) continue; if (lastx == vtx->FinalPosition[0] &&
lasty == vtx->FinalPosition[1]) continue;
} }
*vptr++ = x | (y << 16); lastx = vtx->FinalPosition[0];
*vptr++ = z | (w << 16); lasty = vtx->FinalPosition[1];
*vptr++ = (vtx->FinalColor[0] >> 1) | vptr = SetupVertex(poly, j, vtx, vtxattr, vptr);
((vtx->FinalColor[1] >> 1) << 8) |
((vtx->FinalColor[2] >> 1) << 16) |
(alpha << 24);
*vptr++ = (u16)vtx->TexCoords[0] | ((u16)vtx->TexCoords[1] << 16);
*vptr++ = vtxattr | (zshift << 16);
*vptr++ = poly->TexParam;
*vptr++ = poly->TexPalette;
*iptr++ = vidx; *iptr++ = vidx;
rp->NumIndices++; rp->NumIndices++;
@ -610,57 +614,148 @@ void BuildPolygons(RendererPolygon* polygons, int npolys)
if (nout >= 2) break; if (nout >= 2) break;
} }
} }
else else if (poly->NumVertices == 3) // regular triangle
{ {
rp->PrimType = GL_TRIANGLES; rp->PrimType = GL_TRIANGLES;
for (int j = 0; j < poly->NumVertices; j++) for (int j = 0; j < 3; j++)
{ {
Vertex* vtx = poly->Vertices[j]; Vertex* vtx = poly->Vertices[j];
u32 z = poly->FinalZ[j]; vptr = SetupVertex(poly, j, vtx, vtxattr, vptr);
u32 w = poly->FinalW[j]; vidx++;
}
// Z should always fit within 16 bits, so it's okay to do this // build a triangle
*iptr++ = vidx_first;
*iptr++ = vidx - 2;
*iptr++ = vidx - 1;
rp->NumIndices += 3;
}
else // quad, pentagon, etc
{
rp->PrimType = GL_TRIANGLES;
if (!BetterPolygons)
{
// regular triangle-splitting
for (int j = 0; j < poly->NumVertices; j++)
{
Vertex* vtx = poly->Vertices[j];
vptr = SetupVertex(poly, j, vtx, vtxattr, vptr);
if (j >= 2)
{
// build a triangle
*iptr++ = vidx_first;
*iptr++ = vidx - 1;
*iptr++ = vidx;
rp->NumIndices += 3;
}
vidx++;
}
}
else
{
// attempt at 'better' splitting
// this doesn't get rid of the error while splitting a bigger polygon into triangles
// but we can attempt to reduce it
u32 cX = 0, cY = 0;
float cZ = 0;
float cW = 0;
float cR = 0, cG = 0, cB = 0;
float cS = 0, cT = 0;
for (int j = 0; j < poly->NumVertices; j++)
{
Vertex* vtx = poly->Vertices[j];
cX += vtx->HiresPosition[0];
cY += vtx->HiresPosition[1];
float fw = (float)poly->FinalW[j] * poly->NumVertices;
cW += 1.0f / fw;
if (poly->WBuffer) cZ += poly->FinalZ[j] / fw;
else cZ += poly->FinalZ[j];
cR += (vtx->FinalColor[0] >> 1) / fw;
cG += (vtx->FinalColor[1] >> 1) / fw;
cB += (vtx->FinalColor[2] >> 1) / fw;
cS += vtx->TexCoords[0] / fw;
cT += vtx->TexCoords[1] / fw;
}
cX /= poly->NumVertices;
cY /= poly->NumVertices;
cW = 1.0f / cW;
if (poly->WBuffer) cZ *= cW;
else cZ /= poly->NumVertices;
cR *= cW;
cG *= cW;
cB *= cW;
cS *= cW;
cT *= cW;
cX = (cX * ScaleFactor) >> 4;
cY = (cY * ScaleFactor) >> 4;
u32 w = (u32)cW;
u32 z = (u32)cZ;
u32 zshift = 0; u32 zshift = 0;
while (z > 0xFFFF) { z >>= 1; zshift++; } while (z > 0xFFFF) { z >>= 1; zshift++; }
u32 x, y; // build center vertex
if (ScaleFactor > 1) *vptr++ = cX | (cY << 16);
{
x = (vtx->HiresPosition[0] * ScaleFactor) >> 4;
y = (vtx->HiresPosition[1] * ScaleFactor) >> 4;
}
else
{
x = vtx->FinalPosition[0];
y = vtx->FinalPosition[1];
}
*vptr++ = x | (y << 16);
*vptr++ = z | (w << 16); *vptr++ = z | (w << 16);
*vptr++ = (vtx->FinalColor[0] >> 1) | *vptr++ = (u32)cR |
((vtx->FinalColor[1] >> 1) << 8) | ((u32)cG << 8) |
((vtx->FinalColor[2] >> 1) << 16) | ((u32)cB << 16) |
(alpha << 24); (alpha << 24);
*vptr++ = (u16)vtx->TexCoords[0] | ((u16)vtx->TexCoords[1] << 16); *vptr++ = (u16)cS | ((u16)cT << 16);
*vptr++ = vtxattr | (zshift << 16); *vptr++ = vtxattr | (zshift << 16);
*vptr++ = poly->TexParam; *vptr++ = poly->TexParam;
*vptr++ = poly->TexPalette; *vptr++ = poly->TexPalette;
if (j >= 2) vidx++;
// build the final polygon
for (int j = 0; j < poly->NumVertices; j++)
{ {
// build a triangle Vertex* vtx = poly->Vertices[j];
*iptr++ = vidx_first;
*iptr++ = vidx - 1; vptr = SetupVertex(poly, j, vtx, vtxattr, vptr);
*iptr++ = vidx;
rp->NumIndices += 3; if (j >= 1)
{
// build a triangle
*iptr++ = vidx_first;
*iptr++ = vidx - 1;
*iptr++ = vidx;
rp->NumIndices += 3;
}
vidx++;
} }
vidx++; *iptr++ = vidx_first;
*iptr++ = vidx - 1;
*iptr++ = vidx_first + 1;
rp->NumIndices += 3;
} }
} }
@ -741,6 +836,10 @@ void RenderSceneChunk(int y, int h)
GLboolean fogenable = (RenderDispCnt & (1<<7)) ? GL_TRUE : GL_FALSE; GLboolean fogenable = (RenderDispCnt & (1<<7)) ? GL_TRUE : GL_FALSE;
// TODO: proper 'equal' depth test!
// (has margin of +-0x200 in Z-buffer mode, +-0xFF in W-buffer mode)
// for now we're using GL_LEQUAL to make it work to some extent
// pass 1: opaque pixels // pass 1: opaque pixels
UseRenderShader(flags); UseRenderShader(flags);
@ -759,8 +858,10 @@ void RenderSceneChunk(int y, int h)
if (rp->PolyData->IsShadowMask) { i++; continue; } if (rp->PolyData->IsShadowMask) { i++; continue; }
// zorp if (rp->PolyData->Attr & (1<<14))
glDepthFunc(GL_LESS); glDepthFunc(GL_LEQUAL);
else
glDepthFunc(GL_LESS);
u32 polyattr = rp->PolyData->Attr; u32 polyattr = rp->PolyData->Attr;
u32 polyid = (polyattr >> 24) & 0x3F; u32 polyid = (polyattr >> 24) & 0x3F;
@ -845,8 +946,10 @@ void RenderSceneChunk(int y, int h)
{ {
UseRenderShader(flags | RenderFlag_Trans); UseRenderShader(flags | RenderFlag_Trans);
// zorp if (rp->PolyData->Attr & (1<<14))
glDepthFunc(GL_LESS); glDepthFunc(GL_LEQUAL);
else
glDepthFunc(GL_LESS);
u32 polyattr = rp->PolyData->Attr; u32 polyattr = rp->PolyData->Attr;
u32 polyid = (polyattr >> 24) & 0x3F; u32 polyid = (polyattr >> 24) & 0x3F;
@ -936,8 +1039,10 @@ void RenderSceneChunk(int y, int h)
if (!(polyattr & (1<<15))) transfog = fogenable; if (!(polyattr & (1<<15))) transfog = fogenable;
else transfog = GL_FALSE; else transfog = GL_FALSE;
// zorp if (rp->PolyData->Attr & (1<<14))
glDepthFunc(GL_LESS); glDepthFunc(GL_LEQUAL);
else
glDepthFunc(GL_LESS);
if (rp->PolyData->IsShadow) if (rp->PolyData->IsShadow)
{ {
@ -1003,9 +1108,9 @@ void RenderSceneChunk(int y, int h)
glStencilMask(0); glStencilMask(0);
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, FramebufferTex[4]); glBindTexture(GL_TEXTURE_2D, FramebufferTex[FrontBuffer ? 6 : 4]);
glActiveTexture(GL_TEXTURE1); glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, FramebufferTex[5]); glBindTexture(GL_TEXTURE_2D, FramebufferTex[FrontBuffer ? 7 : 5]);
glBindBuffer(GL_ARRAY_BUFFER, ClearVertexBufferID); glBindBuffer(GL_ARRAY_BUFFER, ClearVertexBufferID);
glBindVertexArray(ClearVertexArrayID); glBindVertexArray(ClearVertexArrayID);
@ -1055,8 +1160,8 @@ void RenderFrame()
{ {
CurShaderID = -1; CurShaderID = -1;
if (Antialias) glBindFramebuffer(GL_FRAMEBUFFER, FramebufferID[2]); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
else glBindFramebuffer(GL_FRAMEBUFFER, FramebufferID[FrontBuffer]); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, FramebufferID[FrontBuffer]);
ShaderConfig.uScreenSize[0] = ScreenW; ShaderConfig.uScreenSize[0] = ScreenW;
ShaderConfig.uScreenSize[1] = ScreenH; ShaderConfig.uScreenSize[1] = ScreenH;
@ -1218,14 +1323,6 @@ void RenderFrame()
RenderSceneChunk(0, 192); RenderSceneChunk(0, 192);
} }
if (Antialias)
{
glBindFramebuffer(GL_READ_FRAMEBUFFER, FramebufferID[2]);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, FramebufferID[FrontBuffer]);
glBlitFramebuffer(0, 0, ScreenW, ScreenH, 0, 0, ScreenW/2, ScreenH/2, GL_COLOR_BUFFER_BIT, GL_LINEAR);
}
//glBindFramebuffer(GL_FRAMEBUFFER, FramebufferID[FrontBuffer]);
FrontBuffer = FrontBuffer ? 0 : 1; FrontBuffer = FrontBuffer ? 0 : 1;
} }

View File

@ -121,6 +121,8 @@ bool Init()
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
return true; return true;
} }
@ -157,12 +159,15 @@ void SetRenderSettings(RenderSettings& settings)
glBindFramebuffer(GL_FRAMEBUFFER, CompScreenOutputFB); glBindFramebuffer(GL_FRAMEBUFFER, CompScreenOutputFB);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, CompScreenOutputTex, 0); glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, CompScreenOutputTex, 0);
glDrawBuffers(1, fbassign); glDrawBuffers(1, fbassign);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
} }
void RenderFrame() void RenderFrame()
{ {
glBindFramebuffer(GL_FRAMEBUFFER, CompScreenOutputFB); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, CompScreenOutputFB);
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST); glDisable(GL_STENCIL_TEST);

View File

@ -775,7 +775,7 @@ bool DoSavestate(Savestate* file)
file->Var8(&WRAMCnt); file->Var8(&WRAMCnt);
file->Var32((u32*)&RunningGame); file->Bool32(&RunningGame);
if (!file->Saving) if (!file->Saving)
{ {
@ -1124,6 +1124,11 @@ void MicInputFrame(s16* data, int samples)
return SPI_TSC::MicInputFrame(data, samples); return SPI_TSC::MicInputFrame(data, samples);
} }
int ImportSRAM(u8* data, u32 length)
{
return NDSCart::ImportSRAM(data, length);
}
void Halt() void Halt()
{ {
@ -1817,15 +1822,16 @@ void debug(u32 param)
fwrite(&val, 4, 1, shit); fwrite(&val, 4, 1, shit);
} }
fclose(shit);*/ fclose(shit);*/
FILE* FILE*
shit = fopen("debug/dump9.bin", "wb"); shit = fopen("debug/picto9.bin", "wb");
for (u32 i = 0x02000000; i < 0x04000000; i+=4) for (u32 i = 0x02000000; i < 0x04000000; i+=4)
{ {
u32 val = DSi::ARM9Read32(i); u32 val = DSi::ARM9Read32(i);
fwrite(&val, 4, 1, shit); fwrite(&val, 4, 1, shit);
} }
fclose(shit); fclose(shit);
shit = fopen("debug/dump7.bin", "wb"); shit = fopen("debug/picto7.bin", "wb");
for (u32 i = 0x02000000; i < 0x04000000; i+=4) for (u32 i = 0x02000000; i < 0x04000000; i+=4)
{ {
u32 val = DSi::ARM7Read32(i); u32 val = DSi::ARM7Read32(i);
@ -2536,7 +2542,8 @@ void ARM7Write8(u32 addr, u8 val)
return; return;
} }
printf("unknown arm7 write8 %08X %02X @ %08X\n", addr, val, ARM7->R[15]); if (ARM7->R[15] > 0x00002F30) // ARM7 BIOS bug
printf("unknown arm7 write8 %08X %02X @ %08X\n", addr, val, ARM7->R[15]);
} }
void ARM7Write16(u32 addr, u16 val) void ARM7Write16(u32 addr, u16 val)
@ -3454,6 +3461,10 @@ void ARM9IOWrite32(u32 addr, u32 val)
PowerControl9 = val & 0x820F; PowerControl9 = val & 0x820F;
GPU::SetPowerCnt(PowerControl9); GPU::SetPowerCnt(PowerControl9);
return; return;
case 0x04100010:
NDSCart::WriteROMData(val);
return;
} }
if (addr >= 0x04000000 && addr < 0x04000060) if (addr >= 0x04000000 && addr < 0x04000060)
@ -3744,7 +3755,7 @@ void ARM7IOWrite8(u32 addr, u8 val)
return; return;
case 0x04000301: case 0x04000301:
val & 0xC0; val &= 0xC0;
if (val == 0x40) printf("!! GBA MODE NOT SUPPORTED\n"); if (val == 0x40) printf("!! GBA MODE NOT SUPPORTED\n");
else if (val == 0x80) ARM7->Halt(1); else if (val == 0x80) ARM7->Halt(1);
else if (val == 0xC0) EnterSleepMode(); else if (val == 0xC0) EnterSleepMode();

View File

@ -47,6 +47,8 @@ enum
Event_DSi_SDIOTransfer, Event_DSi_SDIOTransfer,
Event_DSi_NWifi, Event_DSi_NWifi,
Event_DSi_RAMSizeChange,
Event_MAX Event_MAX
}; };
@ -209,6 +211,8 @@ void SetLidClosed(bool closed);
void MicInputFrame(s16* data, int samples); void MicInputFrame(s16* data, int samples);
int ImportSRAM(u8* data, u32 length);
void ScheduleEvent(u32 id, bool periodic, s32 delay, void (*func)(u32), u32 param); void ScheduleEvent(u32 id, bool periodic, s32 delay, void (*func)(u32), u32 param);
void CancelEvent(u32 id); void CancelEvent(u32 id);

View File

@ -25,7 +25,9 @@
#include "CRC32.h" #include "CRC32.h"
#include "DSi_AES.h" #include "DSi_AES.h"
#include "Platform.h" #include "Platform.h"
#include "Config.h"
#include "ROMList.h" #include "ROMList.h"
#include "melonDLDI.h"
namespace NDSCart_SRAM namespace NDSCart_SRAM
@ -464,11 +466,13 @@ u16 SPICnt;
u32 ROMCnt; u32 ROMCnt;
u8 ROMCommand[8]; u8 ROMCommand[8];
u32 ROMDataOut; u32 ROMData;
u8 DataOut[0x4000]; u8 TransferData[0x4000];
u32 DataOutPos; u32 TransferPos;
u32 DataOutLen; u32 TransferLen;
u32 TransferDir;
u8 TransferCmd[8];
bool CartInserted; bool CartInserted;
u8* CartROM; u8* CartROM;
@ -478,6 +482,8 @@ u32 CartID;
bool CartIsHomebrew; bool CartIsHomebrew;
bool CartIsDSi; bool CartIsDSi;
FILE* CartSD;
u32 CmdEncMode; u32 CmdEncMode;
u32 DataEncMode; u32 DataEncMode;
@ -489,6 +495,7 @@ u64 Key2_Y;
void ROMCommand_Retail(u8* cmd); void ROMCommand_Retail(u8* cmd);
void ROMCommand_RetailNAND(u8* cmd); void ROMCommand_RetailNAND(u8* cmd);
void ROMCommand_Homebrew(u8* cmd);
void (*ROMCommandHandler)(u8* cmd); void (*ROMCommandHandler)(u8* cmd);
@ -615,6 +622,8 @@ bool Init()
CartROM = NULL; CartROM = NULL;
CartSD = NULL;
return true; return true;
} }
@ -622,6 +631,8 @@ void DeInit()
{ {
if (CartROM) delete[] CartROM; if (CartROM) delete[] CartROM;
if (CartSD) fclose(CartSD);
NDSCart_SRAM::DeInit(); NDSCart_SRAM::DeInit();
} }
@ -635,6 +646,9 @@ void Reset()
CartIsHomebrew = false; CartIsHomebrew = false;
CartIsDSi = false; CartIsDSi = false;
if (CartSD) fclose(CartSD);
CartSD = NULL;
ROMCommandHandler = NULL; ROMCommandHandler = NULL;
NDSCart_SRAM::Reset(); NDSCart_SRAM::Reset();
@ -650,11 +664,13 @@ void DoSavestate(Savestate* file)
file->Var32(&ROMCnt); file->Var32(&ROMCnt);
file->VarArray(ROMCommand, 8); file->VarArray(ROMCommand, 8);
file->Var32(&ROMDataOut); file->Var32(&ROMData);
file->VarArray(DataOut, 0x4000); file->VarArray(TransferData, 0x4000);
file->Var32(&DataOutPos); file->Var32(&TransferPos);
file->Var32(&DataOutLen); file->Var32(&TransferLen);
file->Var32(&TransferDir);
file->VarArray(TransferCmd, 8);
// cart inserted/len/ROM/etc should be already populated // cart inserted/len/ROM/etc should be already populated
// savestate should be loaded after the right game is loaded // savestate should be loaded after the right game is loaded
@ -670,10 +686,8 @@ void DoSavestate(Savestate* file)
} }
void ApplyDLDIPatch() void ApplyDLDIPatch(const u8* patch, u32 len)
{ {
// TODO: embed patches? let the user choose? default to some builtin driver?
u32 offset = *(u32*)&CartROM[0x20]; u32 offset = *(u32*)&CartROM[0x20];
u32 size = *(u32*)&CartROM[0x2C]; u32 size = *(u32*)&CartROM[0x2C];
@ -696,23 +710,7 @@ void ApplyDLDIPatch()
return; return;
} }
printf("DLDI shit found at %08X (%08X)\n", dldioffset, offset+dldioffset); printf("DLDI structure found at %08X (%08X)\n", dldioffset, offset+dldioffset);
FILE* f = fopen("dldi.bin", "rb");
if (!f)
{
printf("no DLDI patch available. oh well\n");
return;
}
u32 dldisize;
fseek(f, 0, SEEK_END);
dldisize = ftell(f);
fseek(f, 0, SEEK_SET);
u8* patch = new u8[dldisize];
fread(patch, dldisize, 1, f);
fclose(f);
if (*(u32*)&patch[0] != 0xBF8DA5ED || if (*(u32*)&patch[0] != 0xBF8DA5ED ||
*(u32*)&patch[4] != 0x69684320 || *(u32*)&patch[4] != 0x69684320 ||
@ -743,7 +741,7 @@ void ApplyDLDIPatch()
u32 patchsize = 1 << patch[0x0D]; u32 patchsize = 1 << patch[0x0D];
u32 patchend = patchbase + patchsize; u32 patchend = patchbase + patchsize;
memcpy(&binary[dldioffset], patch, dldisize); memcpy(&binary[dldioffset], patch, len);
*(u32*)&binary[dldioffset+0x40] += delta; *(u32*)&binary[dldioffset+0x40] += delta;
*(u32*)&binary[dldioffset+0x44] += delta; *(u32*)&binary[dldioffset+0x44] += delta;
@ -807,7 +805,6 @@ void ApplyDLDIPatch()
memset(&binary[dldioffset+fixstart], 0, fixend-fixstart); memset(&binary[dldioffset+fixstart], 0, fixend-fixstart);
} }
delete[] patch;
printf("applied DLDI patch\n"); printf("applied DLDI patch\n");
} }
@ -987,11 +984,13 @@ bool LoadROM(const char* path, const char* sram, bool direct)
Key1_Encrypt((u32*)&CartROM[arm9base]); Key1_Encrypt((u32*)&CartROM[arm9base]);
} }
} }
else }
{
CartIsHomebrew = true; if ((arm9base < 0x4000) || (gamecode == 0x23232323))
//ApplyDLDIPatch(); {
} CartIsHomebrew = true;
if (Config::DLDIEnable)
ApplyDLDIPatch(melonDLDI, sizeof(melonDLDI));
} }
if (direct) if (direct)
@ -1005,7 +1004,9 @@ bool LoadROM(const char* path, const char* sram, bool direct)
CartInserted = true; CartInserted = true;
// TODO: support more fancy cart types (homebrew?, flashcarts, etc) // TODO: support more fancy cart types (homebrew?, flashcarts, etc)
if (CartID & 0x08000000) if (CartIsHomebrew)
ROMCommandHandler = ROMCommand_Homebrew;
else if (CartID & 0x08000000)
ROMCommandHandler = ROMCommand_RetailNAND; ROMCommandHandler = ROMCommand_RetailNAND;
else else
ROMCommandHandler = ROMCommand_Retail; ROMCommandHandler = ROMCommand_Retail;
@ -1017,6 +1018,13 @@ bool LoadROM(const char* path, const char* sram, bool direct)
printf("Save file: %s\n", sram); printf("Save file: %s\n", sram);
NDSCart_SRAM::LoadSave(sram, romparams.SaveMemType); NDSCart_SRAM::LoadSave(sram, romparams.SaveMemType);
if (CartIsHomebrew && Config::DLDIEnable)
{
CartSD = Platform::OpenLocalFile(Config::DLDISDPath, "r+b");
}
else
CartSD = NULL;
return true; return true;
} }
@ -1026,6 +1034,19 @@ void RelocateSave(const char* path, bool write)
NDSCart_SRAM::RelocateSave(path, write); NDSCart_SRAM::RelocateSave(path, write);
} }
int ImportSRAM(const u8* data, u32 length)
{
memcpy(NDSCart_SRAM::SRAM, data, std::min(length, NDSCart_SRAM::SRAMLength));
FILE* f = Platform::OpenFile(NDSCart_SRAM::SRAMPath, "wb");
if (f)
{
fwrite(NDSCart_SRAM::SRAM, NDSCart_SRAM::SRAMLength, 1, f);
fclose(f);
}
return length - NDSCart_SRAM::SRAMLength;
}
void ResetCart() void ResetCart()
{ {
// CHECKME: what if there is a transfer in progress? // CHECKME: what if there is a transfer in progress?
@ -1034,14 +1055,17 @@ void ResetCart()
ROMCnt = 0; ROMCnt = 0;
memset(ROMCommand, 0, 8); memset(ROMCommand, 0, 8);
ROMDataOut = 0; ROMData = 0;
Key2_X = 0; Key2_X = 0;
Key2_Y = 0; Key2_Y = 0;
memset(DataOut, 0, 0x4000); memset(TransferData, 0, 0x4000);
DataOutPos = 0; TransferPos = 0;
DataOutLen = 0; TransferLen = 0;
TransferDir = 0;
memset(TransferCmd, 0, 8);
TransferCmd[0] = 0xFF;
CmdEncMode = 0; CmdEncMode = 0;
DataEncMode = 0; DataEncMode = 0;
@ -1055,7 +1079,7 @@ void ReadROM(u32 addr, u32 len, u32 offset)
if ((addr+len) > CartROMSize) if ((addr+len) > CartROMSize)
len = CartROMSize - addr; len = CartROMSize - addr;
memcpy(DataOut+offset, CartROM+addr, len); memcpy(TransferData+offset, CartROM+addr, len);
} }
void ReadROM_B7(u32 addr, u32 len, u32 offset) void ReadROM_B7(u32 addr, u32 len, u32 offset)
@ -1069,7 +1093,7 @@ void ReadROM_B7(u32 addr, u32 len, u32 offset)
addr = 0x8000 + (addr & 0x1FF); addr = 0x8000 + (addr & 0x1FF);
} }
memcpy(DataOut+offset, CartROM+addr, len); memcpy(TransferData+offset, CartROM+addr, len);
} }
@ -1079,16 +1103,41 @@ void ROMEndTransfer(u32 param)
if (SPICnt & (1<<14)) if (SPICnt & (1<<14))
NDS::SetIRQ((NDS::ExMemCnt[0]>>11)&0x1, NDS::IRQ_CartSendDone); NDS::SetIRQ((NDS::ExMemCnt[0]>>11)&0x1, NDS::IRQ_CartSendDone);
if (TransferDir == 1)
{
// finish a write
u8* cmd = TransferCmd;
switch (cmd[0])
{
case 0xC1:
{
u32 sector = (cmd[1]<<24) | (cmd[2]<<16) | (cmd[3]<<8) | cmd[4];
u64 addr = sector * 0x200ULL;
if (CartSD)
{
fseek(CartSD, addr, SEEK_SET);
fwrite(TransferData, TransferLen, 1, CartSD);
}
}
break;
}
}
} }
void ROMPrepareData(u32 param) void ROMPrepareData(u32 param)
{ {
if (DataOutPos >= DataOutLen) if (TransferDir == 0)
ROMDataOut = 0; {
else if (TransferPos >= TransferLen)
ROMDataOut = *(u32*)&DataOut[DataOutPos]; ROMData = 0;
else
ROMData = *(u32*)&TransferData[TransferPos];
DataOutPos += 4; TransferPos += 4;
}
ROMCnt |= (1<<23); ROMCnt |= (1<<23);
@ -1106,16 +1155,16 @@ void ROMCommand_Retail(u8* cmd)
case 0xB7: case 0xB7:
{ {
u32 addr = (cmd[1]<<24) | (cmd[2]<<16) | (cmd[3]<<8) | cmd[4]; u32 addr = (cmd[1]<<24) | (cmd[2]<<16) | (cmd[3]<<8) | cmd[4];
memset(DataOut, 0, DataOutLen); memset(TransferData, 0, TransferLen);
if (((addr + DataOutLen - 1) >> 12) != (addr >> 12)) if (((addr + TransferLen - 1) >> 12) != (addr >> 12))
{ {
u32 len1 = 0x1000 - (addr & 0xFFF); u32 len1 = 0x1000 - (addr & 0xFFF);
ReadROM_B7(addr, len1, 0); ReadROM_B7(addr, len1, 0);
ReadROM_B7(addr+len1, DataOutLen-len1, len1); ReadROM_B7(addr+len1, TransferLen-len1, len1);
} }
else else
ReadROM_B7(addr, DataOutLen, 0); ReadROM_B7(addr, TransferLen, 0);
} }
break; break;
@ -1136,8 +1185,8 @@ void ROMCommand_RetailNAND(u8* cmd)
// Jam with the Band stores words 6-9 of this at 0x02131BB0 // Jam with the Band stores words 6-9 of this at 0x02131BB0
// it doesn't seem to use those anywhere later // it doesn't seem to use those anywhere later
for (u32 pos = 0; pos < DataOutLen; pos += 4) for (u32 pos = 0; pos < TransferLen; pos += 4)
*(u32*)&DataOut[pos] = 0; *(u32*)&TransferData[pos] = 0;
} }
break; break;
@ -1150,16 +1199,16 @@ void ROMCommand_RetailNAND(u8* cmd)
case 0xB7: case 0xB7:
{ {
u32 addr = (cmd[1]<<24) | (cmd[2]<<16) | (cmd[3]<<8) | cmd[4]; u32 addr = (cmd[1]<<24) | (cmd[2]<<16) | (cmd[3]<<8) | cmd[4];
memset(DataOut, 0, DataOutLen); memset(TransferData, 0, TransferLen);
if (((addr + DataOutLen - 1) >> 12) != (addr >> 12)) if (((addr + TransferLen - 1) >> 12) != (addr >> 12))
{ {
u32 len1 = 0x1000 - (addr & 0xFFF); u32 len1 = 0x1000 - (addr & 0xFFF);
ReadROM_B7(addr, len1, 0); ReadROM_B7(addr, len1, 0);
ReadROM_B7(addr+len1, DataOutLen-len1, len1); ReadROM_B7(addr+len1, TransferLen-len1, len1);
} }
else else
ReadROM_B7(addr, DataOutLen, 0); ReadROM_B7(addr, TransferLen, 0);
} }
break; break;
@ -1169,13 +1218,59 @@ void ROMCommand_RetailNAND(u8* cmd)
// * bit7: busy? error? // * bit7: busy? error?
// * bit5: accessing savemem // * bit5: accessing savemem
for (u32 pos = 0; pos < DataOutLen; pos += 4) for (u32 pos = 0; pos < TransferLen; pos += 4)
*(u32*)&DataOut[pos] = NDSCart_SRAM::StatusReg * 0x01010101; *(u32*)&TransferData[pos] = NDSCart_SRAM::StatusReg * 0x01010101;
} }
break; break;
default: default:
printf("unknown NAND command %02X %04Xn", cmd[0], DataOutLen); printf("unknown NAND command %02X %04Xn", cmd[0], TransferLen);
break;
}
}
void ROMCommand_Homebrew(u8* cmd)
{
switch (cmd[0])
{
case 0xB7:
{
u32 addr = (cmd[1]<<24) | (cmd[2]<<16) | (cmd[3]<<8) | cmd[4];
memset(TransferData, 0, TransferLen);
if (((addr + TransferLen - 1) >> 12) != (addr >> 12))
{
u32 len1 = 0x1000 - (addr & 0xFFF);
ReadROM_B7(addr, len1, 0);
ReadROM_B7(addr+len1, TransferLen-len1, len1);
}
else
ReadROM_B7(addr, TransferLen, 0);
}
break;
case 0xC0: // SD read
{
u32 sector = (cmd[1]<<24) | (cmd[2]<<16) | (cmd[3]<<8) | cmd[4];
u64 addr = sector * 0x200ULL;
if (CartSD)
{
fseek(CartSD, addr, SEEK_SET);
fread(TransferData, TransferLen, 1, CartSD);
}
}
break;
case 0xC1: // SD write
{
TransferDir = 1;
memcpy(TransferCmd, cmd, 8);
}
break;
default:
printf("unknown homebrew cart command %02X\n", cmd[0]);
break; break;
} }
} }
@ -1215,8 +1310,8 @@ void WriteROMCnt(u32 val)
else if (datasize > 0) else if (datasize > 0)
datasize = 0x100 << datasize; datasize = 0x100 << datasize;
DataOutPos = 0; TransferPos = 0;
DataOutLen = datasize; TransferLen = datasize;
// handle KEY1 encryption as needed. // handle KEY1 encryption as needed.
// KEY2 encryption is implemented in hardware and doesn't need to be handled. // KEY2 encryption is implemented in hardware and doesn't need to be handled.
@ -1242,28 +1337,32 @@ void WriteROMCnt(u32 val)
cmd[4], cmd[5], cmd[6], cmd[7], cmd[4], cmd[5], cmd[6], cmd[7],
datasize);*/ datasize);*/
// default is read
// commands that do writes will change this
TransferDir = 0;
switch (cmd[0]) switch (cmd[0])
{ {
case 0x9F: case 0x9F:
memset(DataOut, 0xFF, DataOutLen); memset(TransferData, 0xFF, TransferLen);
break; break;
case 0x00: case 0x00:
memset(DataOut, 0, DataOutLen); memset(TransferData, 0, TransferLen);
if (DataOutLen > 0x1000) if (TransferLen > 0x1000)
{ {
ReadROM(0, 0x1000, 0); ReadROM(0, 0x1000, 0);
for (u32 pos = 0x1000; pos < DataOutLen; pos += 0x1000) for (u32 pos = 0x1000; pos < TransferLen; pos += 0x1000)
memcpy(DataOut+pos, DataOut, 0x1000); memcpy(TransferData+pos, TransferData, 0x1000);
} }
else else
ReadROM(0, DataOutLen, 0); ReadROM(0, TransferLen, 0);
break; break;
case 0x90: case 0x90:
case 0xB8: case 0xB8:
for (u32 pos = 0; pos < DataOutLen; pos += 4) for (u32 pos = 0; pos < TransferLen; pos += 4)
*(u32*)&DataOut[pos] = CartID; *(u32*)&TransferData[pos] = CartID;
break; break;
case 0x3C: case 0x3C:
@ -1292,8 +1391,8 @@ void WriteROMCnt(u32 val)
break; break;
case 0x10: case 0x10:
for (u32 pos = 0; pos < DataOutLen; pos += 4) for (u32 pos = 0; pos < TransferLen; pos += 4)
*(u32*)&DataOut[pos] = CartID; *(u32*)&TransferData[pos] = CartID;
break; break;
case 0x20: case 0x20:
@ -1343,29 +1442,52 @@ void WriteROMCnt(u32 val)
NDS::ScheduleEvent(NDS::Event_ROMTransfer, false, xfercycle*(cmddelay+4), ROMPrepareData, 0); NDS::ScheduleEvent(NDS::Event_ROMTransfer, false, xfercycle*(cmddelay+4), ROMPrepareData, 0);
} }
void AdvanceROMTransfer()
{
ROMCnt &= ~(1<<23);
if (TransferPos < TransferLen)
{
u32 xfercycle = (ROMCnt & (1<<27)) ? 8 : 5;
u32 delay = 4;
if (!(ROMCnt & (1<<30)))
{
if (!(TransferPos & 0x1FF))
delay += ((ROMCnt >> 16) & 0x3F);
}
NDS::ScheduleEvent(NDS::Event_ROMTransfer, false, xfercycle*delay, ROMPrepareData, 0);
}
else
ROMEndTransfer(0);
}
u32 ReadROMData() u32 ReadROMData()
{ {
if (ROMCnt & (1<<23)) if (ROMCnt & (1<<23))
{ {
ROMCnt &= ~(1<<23); AdvanceROMTransfer();
if (DataOutPos < DataOutLen)
{
u32 xfercycle = (ROMCnt & (1<<27)) ? 8 : 5;
u32 delay = 4;
if (!(ROMCnt & (1<<30)))
{
if (!(DataOutPos & 0x1FF))
delay += ((ROMCnt >> 16) & 0x3F);
}
NDS::ScheduleEvent(NDS::Event_ROMTransfer, false, xfercycle*delay, ROMPrepareData, 0);
}
else
ROMEndTransfer(0);
} }
return ROMDataOut; return ROMData;
}
void WriteROMData(u32 val)
{
ROMData = val;
if (ROMCnt & (1<<23))
{
if (TransferDir == 1)
{
if (TransferPos < TransferLen)
*(u32*)&TransferData[TransferPos] = ROMData;
TransferPos += 4;
}
AdvanceROMTransfer();
}
} }

View File

@ -48,10 +48,13 @@ void DecryptSecureArea(u8* out);
bool LoadROM(const char* path, const char* sram, bool direct); bool LoadROM(const char* path, const char* sram, bool direct);
void RelocateSave(const char* path, bool write); void RelocateSave(const char* path, bool write);
int ImportSRAM(const u8* data, u32 length);
void ResetCart(); void ResetCart();
void WriteROMCnt(u32 val); void WriteROMCnt(u32 val);
u32 ReadROMData(); u32 ReadROMData();
void WriteROMData(u32 val);
void WriteSPICnt(u16 val); void WriteSPICnt(u16 val);
u8 ReadSPIData(); u8 ReadSPIData();

View File

@ -16,6 +16,9 @@
with melonDS. If not, see http://www.gnu.org/licenses/. with melonDS. If not, see http://www.gnu.org/licenses/.
*/ */
// Required by MinGW to enable localtime_r in time.h
#define _POSIX_THREAD_SAFE_FUNCTIONS
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
@ -125,31 +128,29 @@ void ByteIn(u8 val)
case 0x20: case 0x20:
{ {
time_t timestamp; time_t timestamp = time(NULL);
struct tm* timedata; struct tm timedata;
time(&timestamp); localtime_r(&timestamp, &timedata);
timedata = localtime(&timestamp);
Output[0] = BCD(timedata->tm_year - 100); Output[0] = BCD(timedata.tm_year - 100);
Output[1] = BCD(timedata->tm_mon + 1); Output[1] = BCD(timedata.tm_mon + 1);
Output[2] = BCD(timedata->tm_mday); Output[2] = BCD(timedata.tm_mday);
Output[3] = BCD(timedata->tm_wday); Output[3] = BCD(timedata.tm_wday);
Output[4] = BCD(timedata->tm_hour); Output[4] = BCD(timedata.tm_hour);
Output[5] = BCD(timedata->tm_min); Output[5] = BCD(timedata.tm_min);
Output[6] = BCD(timedata->tm_sec); Output[6] = BCD(timedata.tm_sec);
} }
break; break;
case 0x60: case 0x60:
{ {
time_t timestamp; time_t timestamp = time(NULL);
struct tm* timedata; struct tm timedata;
time(&timestamp); localtime_r(&timestamp, &timedata);
timedata = localtime(&timestamp);
Output[0] = BCD(timedata->tm_hour); Output[0] = BCD(timedata.tm_hour);
Output[1] = BCD(timedata->tm_min); Output[1] = BCD(timedata.tm_min);
Output[2] = BCD(timedata->tm_sec); Output[2] = BCD(timedata.tm_sec);
} }
break; break;

View File

@ -179,24 +179,25 @@ void Reset()
//Firmware[userdata+0x64] &= 0xBF; //Firmware[userdata+0x64] &= 0xBF;
*(u16*)&Firmware[userdata+0x72] = CRC16(&Firmware[userdata], 0x70, 0xFFFF); *(u16*)&Firmware[userdata+0x72] = CRC16(&Firmware[userdata], 0x70, 0xFFFF);
if (Config::RandomizeMAC)
{
// replace MAC address with random address
Firmware[0x36] = 0x00;
Firmware[0x37] = 0x09;
Firmware[0x38] = 0xBF;
Firmware[0x39] = rand()&0xFF;
Firmware[0x3A] = rand()&0xFF;
Firmware[0x3B] = rand()&0xFF;
*(u16*)&Firmware[0x2A] = CRC16(&Firmware[0x2C], *(u16*)&Firmware[0x2C], 0x0000);
}
} }
#if 0
// replace MAC address with random address
// TODO: make optional?
Firmware[0x36] = 0x00;
Firmware[0x37] = 0x09;
Firmware[0x38] = 0xBF;
Firmware[0x39] = rand()&0xFF;
Firmware[0x3A] = rand()&0xFF;
Firmware[0x3B] = rand()&0xFF;
#endif
printf("MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", printf("MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",
Firmware[0x36], Firmware[0x37], Firmware[0x38], Firmware[0x36], Firmware[0x37], Firmware[0x38],
Firmware[0x39], Firmware[0x3A], Firmware[0x3B]); Firmware[0x39], Firmware[0x3A], Firmware[0x3B]);
//*(u16*)&Firmware[0x2A] = CRC16(&Firmware[0x2C], *(u16*)&Firmware[0x2C], 0x0000);
// verify shit // verify shit
printf("FW: WIFI CRC16 = %s\n", VerifyCRC16(0x0000, 0x2C, *(u16*)&Firmware[0x2C], 0x2A)?"GOOD":"BAD"); printf("FW: WIFI CRC16 = %s\n", VerifyCRC16(0x0000, 0x2C, *(u16*)&Firmware[0x2C], 0x2A)?"GOOD":"BAD");
printf("FW: AP1 CRC16 = %s\n", VerifyCRC16(0x0000, 0x7FA00&FirmwareMask, 0xFE, 0x7FAFE&FirmwareMask)?"GOOD":"BAD"); printf("FW: AP1 CRC16 = %s\n", VerifyCRC16(0x0000, 0x7FA00&FirmwareMask, 0xFE, 0x7FAFE&FirmwareMask)?"GOOD":"BAD");
@ -241,6 +242,7 @@ void SetupDirectBoot()
u8 GetConsoleType() { return Firmware[0x1D]; } u8 GetConsoleType() { return Firmware[0x1D]; }
u8 GetWifiVersion() { return Firmware[0x2F]; } u8 GetWifiVersion() { return Firmware[0x2F]; }
u8 GetNWifiVersion() { return Firmware[0x1FD]; } // for DSi; will return 0xFF on a DS
u8 GetRFVersion() { return Firmware[0x40]; } u8 GetRFVersion() { return Firmware[0x40]; }
u8* GetWifiMAC() { return &Firmware[0x36]; } u8* GetWifiMAC() { return &Firmware[0x36]; }

View File

@ -28,6 +28,7 @@ void SetupDirectBoot();
u8 GetConsoleType(); u8 GetConsoleType();
u8 GetWifiVersion(); u8 GetWifiVersion();
u8 GetNWifiVersion();
u8 GetRFVersion(); u8 GetRFVersion();
u8* GetWifiMAC(); u8* GetWifiMAC();

View File

@ -420,6 +420,8 @@ void Channel::Run(s32* buf, u32 samples)
{ {
if (!(Cnt & (1<<31))) return; if (!(Cnt & (1<<31))) return;
if ((type < 3) && ((Length+LoopPos) < 16)) return;
if (KeyOn) if (KeyOn)
{ {
Start(); Start();

View File

@ -261,6 +261,22 @@ void Savestate::Var64(u64* var)
} }
} }
void Savestate::Bool32(bool* var)
{
// for compability
if (Saving)
{
u32 val = *var;
Var32(&val);
}
else
{
u32 val;
Var32(&val);
*var = val != 0;
}
}
void Savestate::VarArray(void* data, u32 len) void Savestate::VarArray(void* data, u32 len)
{ {
if (Error) return; if (Error) return;
@ -273,4 +289,4 @@ void Savestate::VarArray(void* data, u32 len)
{ {
fread(data, len, 1, file); fread(data, len, 1, file);
} }
} }

View File

@ -46,6 +46,8 @@ public:
void Var32(u32* var); void Var32(u32* var);
void Var64(u64* var); void Var64(u64* var);
void Bool32(bool* var);
void VarArray(void* data, u32 len); void VarArray(void* data, u32 len);
bool IsAtleastVersion(u32 major, u32 minor) bool IsAtleastVersion(u32 major, u32 minor)

View File

@ -237,7 +237,7 @@ void DoSavestate(Savestate* file)
file->Var64(&USCounter); file->Var64(&USCounter);
file->Var64(&USCompare); file->Var64(&USCompare);
file->Var32((u32*)&BlockBeaconIRQ14); file->Bool32(&BlockBeaconIRQ14);
file->Var32(&ComStatus); file->Var32(&ComStatus);
file->Var32(&TXCurSlot); file->Var32(&TXCurSlot);
@ -816,6 +816,9 @@ bool CheckRX(bool block)
if (!(IOPORT(W_RXCnt) & 0x8000)) if (!(IOPORT(W_RXCnt) & 0x8000))
return false; return false;
if (IOPORT(W_RXBufBegin) == IOPORT(W_RXBufEnd))
return false;
u16 framelen; u16 framelen;
u16 framectl; u16 framectl;
u8 txrate; u8 txrate;
@ -1049,7 +1052,7 @@ void USTimer(u32 param)
if (!(RXTime & RXHalfwordTimeMask)) if (!(RXTime & RXHalfwordTimeMask))
{ {
u16 addr = IOPORT(W_RXTXAddr) << 1; u16 addr = IOPORT(W_RXTXAddr) << 1;
*(u16*)&RAM[addr] = *(u16*)&RXBuffer[RXBufferPtr]; if (addr < 0x1FFF) *(u16*)&RAM[addr] = *(u16*)&RXBuffer[RXBufferPtr];
IncrementRXAddr(addr); IncrementRXAddr(addr);
RXBufferPtr += 2; RXBufferPtr += 2;
@ -1146,7 +1149,7 @@ void RFTransfer_Type3()
// TODO: wifi waitstates // TODO: wifi waitstates
u16 Read(u32 addr) u16 Read(u32 addr)
{ {//printf("WIFI READ %08X\n", addr);
if (addr >= 0x04810000) if (addr >= 0x04810000)
return 0; return 0;
@ -1236,7 +1239,7 @@ u16 Read(u32 addr)
} }
void Write(u32 addr, u16 val) void Write(u32 addr, u16 val)
{ {//printf("WIFI WRITE %08X %04X\n", addr, val);
if (addr >= 0x04810000) if (addr >= 0x04810000)
return; return;

View File

@ -1631,7 +1631,7 @@ void ARM64XEmitter::ASR(ARM64Reg Rd, ARM64Reg Rm, int shift)
int bits = Is64Bit(Rd) ? 64 : 32; int bits = Is64Bit(Rd) ? 64 : 32;
SBFM(Rd, Rm, shift, bits - 1); SBFM(Rd, Rm, shift, bits - 1);
} }
void ARM64XEmitter::ROR_(ARM64Reg Rd, ARM64Reg Rm, int shift) void ARM64XEmitter::ROR(ARM64Reg Rd, ARM64Reg Rm, int shift)
{ {
EXTR(Rd, Rm, Rm, shift); EXTR(Rd, Rm, Rm, shift);
} }

View File

@ -727,7 +727,7 @@ public:
void LSR(ARM64Reg Rd, ARM64Reg Rm, int shift); void LSR(ARM64Reg Rd, ARM64Reg Rm, int shift);
void LSL(ARM64Reg Rd, ARM64Reg Rm, int shift); void LSL(ARM64Reg Rd, ARM64Reg Rm, int shift);
void ASR(ARM64Reg Rd, ARM64Reg Rm, int shift); void ASR(ARM64Reg Rd, ARM64Reg Rm, int shift);
void ROR_(ARM64Reg Rd, ARM64Reg Rm, int shift); void ROR(ARM64Reg Rd, ARM64Reg Rm, int shift);
// Logical (immediate) // Logical (immediate)
void AND(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms, bool invert = false); void AND(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms, bool invert = false);

View File

@ -1214,7 +1214,7 @@ void XEmitter::ROL(int bits, const OpArg& dest, const OpArg& shift)
{ {
WriteShift(bits, dest, shift, 0); WriteShift(bits, dest, shift, 0);
} }
void XEmitter::ROR_(int bits, const OpArg& dest, const OpArg& shift) void XEmitter::ROR(int bits, const OpArg& dest, const OpArg& shift)
{ {
WriteShift(bits, dest, shift, 1); WriteShift(bits, dest, shift, 1);
} }

View File

@ -489,7 +489,7 @@ public:
// Shift // Shift
void ROL(int bits, const OpArg& dest, const OpArg& shift); void ROL(int bits, const OpArg& dest, const OpArg& shift);
void ROR_(int bits, const OpArg& dest, const OpArg& shift); void ROR(int bits, const OpArg& dest, const OpArg& shift);
void RCL(int bits, const OpArg& dest, const OpArg& shift); void RCL(int bits, const OpArg& dest, const OpArg& shift);
void RCR(int bits, const OpArg& dest, const OpArg& shift); void RCR(int bits, const OpArg& dest, const OpArg& shift);
void SHL(int bits, const OpArg& dest, const OpArg& shift); void SHL(int bits, const OpArg& dest, const OpArg& shift);

View File

@ -67,6 +67,9 @@ extern bool SavestateLoaded;
// initialize the ROM handling utility // initialize the ROM handling utility
void Init_ROM(); void Init_ROM();
// deinitialize the ROM handling utility
void DeInit_ROM();
// load the BIOS/firmware and boot from it // load the BIOS/firmware and boot from it
int LoadBIOS(); int LoadBIOS();
@ -97,6 +100,12 @@ bool SaveState(const char* filename);
// undo the latest savestate load // undo the latest savestate load
void UndoStateLoad(); void UndoStateLoad();
// imports savedata from an external file. Returns the difference between the filesize and the SRAM size
int ImportSRAM(const char* filename);
// enable or disable cheats
void EnableCheats(bool enable);
// setup the display layout based on the provided display size and parameters // setup the display layout based on the provided display size and parameters
// * screenWidth/screenHeight: size of the host display // * screenWidth/screenHeight: size of the host display

View File

@ -27,6 +27,8 @@
#include "NDS.h" #include "NDS.h"
#include "GBACart.h" #include "GBACart.h"
#include "AREngine.h"
namespace Frontend namespace Frontend
{ {
@ -37,6 +39,9 @@ char PrevSRAMPath[ROMSlot_MAX][1024]; // for savestate 'undo load'
bool SavestateLoaded; bool SavestateLoaded;
ARCodeFile* CheatFile;
bool CheatsOn;
void Init_ROM() void Init_ROM()
{ {
@ -48,6 +53,18 @@ void Init_ROM()
memset(SRAMPath[ROMSlot_GBA], 0, 1024); memset(SRAMPath[ROMSlot_GBA], 0, 1024);
memset(PrevSRAMPath[ROMSlot_NDS], 0, 1024); memset(PrevSRAMPath[ROMSlot_NDS], 0, 1024);
memset(PrevSRAMPath[ROMSlot_GBA], 0, 1024); memset(PrevSRAMPath[ROMSlot_GBA], 0, 1024);
CheatFile = nullptr;
CheatsOn = false;
}
void DeInit_ROM()
{
if (CheatFile)
{
delete CheatFile;
CheatFile = nullptr;
}
} }
// TODO: currently, when failing to load a ROM for whatever reason, we attempt // TODO: currently, when failing to load a ROM for whatever reason, we attempt
@ -198,6 +215,32 @@ int VerifyDSiNAND()
return Load_OK; return Load_OK;
} }
void LoadCheats()
{
if (CheatFile)
{
delete CheatFile;
CheatFile = nullptr;
}
char filename[1024];
if (ROMPath[ROMSlot_NDS][0] != '\0')
{
strncpy(filename, ROMPath[ROMSlot_NDS], 1023);
filename[1023] = '\0';
strncpy(filename + strlen(ROMPath[ROMSlot_NDS]) - 3, "mch", 3);
}
else
{
strncpy(filename, "firmware.mch", 1023);
}
// TODO: check for error (malformed cheat file, ...)
CheatFile = new ARCodeFile(filename);
AREngine::SetCodeFile(CheatsOn ? CheatFile : nullptr);
}
int LoadBIOS() int LoadBIOS()
{ {
int res; int res;
@ -235,6 +278,8 @@ int LoadBIOS()
SavestateLoaded = false; SavestateLoaded = false;
LoadCheats();
return Load_OK; return Load_OK;
} }
@ -295,6 +340,8 @@ int LoadROM(const char* file, int slot)
{ {
SavestateLoaded = false; SavestateLoaded = false;
LoadCheats();
// Reload the inserted GBA cartridge (if any) // Reload the inserted GBA cartridge (if any)
// TODO: report failure there?? // TODO: report failure there??
if (ROMPath[ROMSlot_GBA][0] != '\0') NDS::LoadGBAROM(ROMPath[ROMSlot_GBA], SRAMPath[ROMSlot_GBA]); if (ROMPath[ROMSlot_GBA][0] != '\0') NDS::LoadGBAROM(ROMPath[ROMSlot_GBA], SRAMPath[ROMSlot_GBA]);
@ -387,6 +434,8 @@ int Reset()
return Load_ROMLoadError; return Load_ROMLoadError;
} }
LoadCheats();
return Load_OK; return Load_OK;
} }
@ -539,4 +588,26 @@ void UndoStateLoad()
} }
} }
int ImportSRAM(const char* filename)
{
FILE* file = fopen(filename, "rb");
fseek(file, 0, SEEK_END);
u32 size = ftell(file);
u8* importData = new u8[size];
rewind(file);
fread(importData, size, 1, file);
fclose(file);
int diff = NDS::ImportSRAM(importData, size);
delete[] importData;
return diff;
}
void EnableCheats(bool enable)
{
CheatsOn = enable;
if (CheatFile)
AREngine::SetCodeFile(CheatsOn ? CheatFile : nullptr);
}
} }

View File

@ -3,6 +3,7 @@ project(qt_sdl)
SET(SOURCES_QT_SDL SET(SOURCES_QT_SDL
main.cpp main.cpp
main_shaders.h main_shaders.h
CheatsDialog.cpp
EmuSettingsDialog.cpp EmuSettingsDialog.cpp
InputConfigDialog.cpp InputConfigDialog.cpp
VideoSettingsDialog.cpp VideoSettingsDialog.cpp

View File

@ -0,0 +1,412 @@
/*
Copyright 2016-2020 Arisotura
This file is part of melonDS.
melonDS is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option)
any later version.
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with melonDS. If not, see http://www.gnu.org/licenses/.
*/
#include <stdio.h>
#include <QFileDialog>
#include <QMessageBox>
#include "types.h"
#include "Platform.h"
#include "Config.h"
#include "PlatformConfig.h"
#include "CheatsDialog.h"
#include "ui_CheatsDialog.h"
CheatsDialog* CheatsDialog::currentDlg = nullptr;
extern char* EmuDirectory;
namespace Frontend { extern ARCodeFile* CheatFile; }
CheatsDialog::CheatsDialog(QWidget* parent) : QDialog(parent), ui(new Ui::CheatsDialog)
{
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);
codeFile = Frontend::CheatFile;
QStandardItemModel* model = new QStandardItemModel();
ui->tvCodeList->setModel(model);
connect(model, &QStandardItemModel::itemChanged, this, &CheatsDialog::onCheatEntryModified);
connect(ui->tvCodeList->selectionModel(), &QItemSelectionModel::selectionChanged, this, &CheatsDialog::onCheatSelectionChanged);
{
QStandardItem* root = model->invisibleRootItem();
for (ARCodeCatList::iterator i = codeFile->Categories.begin(); i != codeFile->Categories.end(); i++)
{
ARCodeCat& cat = *i;
QStandardItem* catitem = new QStandardItem(cat.Name);
catitem->setEditable(true);
catitem->setData(QVariant::fromValue(i));
root->appendRow(catitem);
for (ARCodeList::iterator j = cat.Codes.begin(); j != cat.Codes.end(); j++)
{
ARCode& code = *j;
QStandardItem* codeitem = new QStandardItem(code.Name);
codeitem->setEditable(true);
codeitem->setCheckable(true);
codeitem->setCheckState(code.Enabled ? Qt::Checked : Qt::Unchecked);
codeitem->setData(QVariant::fromValue(j));
catitem->appendRow(codeitem);
}
}
}
ui->txtCode->setPlaceholderText("");
codeChecker = new ARCodeChecker(ui->txtCode->document());
ui->btnNewARCode->setEnabled(false);
ui->btnDeleteCode->setEnabled(false);
ui->txtCode->setEnabled(false);
}
CheatsDialog::~CheatsDialog()
{
QAbstractItemModel* model = ui->tvCodeList->model();
ui->tvCodeList->setModel(nullptr);
delete model;
delete codeChecker;
delete ui;
}
void CheatsDialog::on_CheatsDialog_accepted()
{
codeFile->Save();
closeDlg();
}
void CheatsDialog::on_CheatsDialog_rejected()
{
codeFile->Load();
closeDlg();
}
void CheatsDialog::on_btnNewCat_clicked()
{
QStandardItem* root = ((QStandardItemModel*)ui->tvCodeList->model())->invisibleRootItem();
ARCodeCat cat;
cat.Codes.clear();
memset(cat.Name, 0, 128);
strncpy(cat.Name, "(new category)", 127);
codeFile->Categories.push_back(cat);
ARCodeCatList::iterator id = codeFile->Categories.end(); id--;
QStandardItem* catitem = new QStandardItem(cat.Name);
catitem->setEditable(true);
catitem->setData(QVariant::fromValue(id));
root->appendRow(catitem);
ui->tvCodeList->selectionModel()->select(catitem->index(), QItemSelectionModel::ClearAndSelect);
ui->tvCodeList->edit(catitem->index());
}
void CheatsDialog::on_btnNewARCode_clicked()
{
QModelIndexList indices = ui->tvCodeList->selectionModel()->selectedIndexes();
if (indices.isEmpty())
{
// ????
return;
}
QStandardItemModel* model = (QStandardItemModel*)ui->tvCodeList->model();
QStandardItem* item = model->itemFromIndex(indices.first());
QStandardItem* parentitem;
QVariant data = item->data();
if (data.canConvert<ARCodeCatList::iterator>())
{
parentitem = item;
}
else if (data.canConvert<ARCodeList::iterator>())
{
parentitem = item->parent();
}
else
{
printf("what?? :(\n");
return;
}
ARCodeCatList::iterator it_cat = parentitem->data().value<ARCodeCatList::iterator>();
ARCodeCat& cat = *it_cat;
ARCode code;
memset(code.Name, 0, 128);
strncpy(code.Name, "(new AR code)", 127);
code.Enabled = true;
code.CodeLen = 0;
memset(code.Code, 0, sizeof(code.Code));
cat.Codes.push_back(code);
ARCodeList::iterator id = cat.Codes.end(); id--;
QStandardItem* codeitem = new QStandardItem(code.Name);
codeitem->setEditable(true);
codeitem->setCheckable(true);
codeitem->setCheckState(code.Enabled ? Qt::Checked : Qt::Unchecked);
codeitem->setData(QVariant::fromValue(id));
parentitem->appendRow(codeitem);
ui->tvCodeList->selectionModel()->select(codeitem->index(), QItemSelectionModel::ClearAndSelect);
ui->tvCodeList->edit(codeitem->index());
}
void CheatsDialog::on_btnDeleteCode_clicked()
{
QModelIndexList indices = ui->tvCodeList->selectionModel()->selectedIndexes();
if (indices.isEmpty())
{
// ????
return;
}
QMessageBox::StandardButton res = QMessageBox::question(this,
"Confirm deletion",
"Really delete the selected item?",
QMessageBox::Yes|QMessageBox::No,
QMessageBox::No);
if (res != QMessageBox::Yes) return;
QStandardItemModel* model = (QStandardItemModel*)ui->tvCodeList->model();
QStandardItem* item = model->itemFromIndex(indices.first());
QVariant data = item->data();
if (data.canConvert<ARCodeCatList::iterator>())
{
ARCodeCatList::iterator it_cat = data.value<ARCodeCatList::iterator>();
(*it_cat).Codes.clear();
codeFile->Categories.erase(it_cat);
model->invisibleRootItem()->removeRow(item->row());
}
else if (data.canConvert<ARCodeList::iterator>())
{
ARCodeList::iterator it_code = data.value<ARCodeList::iterator>();
ARCodeCatList::iterator it_cat = item->parent()->data().value<ARCodeCatList::iterator>();
(*it_cat).Codes.erase(it_code);
item->parent()->removeRow(item->row());
}
}
void CheatsDialog::onCheatSelectionChanged(const QItemSelection& sel, const QItemSelection& desel)
{
QModelIndexList indices = sel.indexes();
if (indices.isEmpty())
{
ui->btnNewARCode->setEnabled(false);
ui->btnDeleteCode->setEnabled(false);
ui->txtCode->setEnabled(false);
ui->txtCode->setPlaceholderText("");
ui->txtCode->clear();
}
else
{
QStandardItem* item = ((QStandardItemModel*)ui->tvCodeList->model())->itemFromIndex(indices.first());
QVariant data = item->data();
if (data.canConvert<ARCodeCatList::iterator>())
{
ui->btnDeleteCode->setEnabled(true);
ui->txtCode->setEnabled(false);
ui->txtCode->setPlaceholderText("");
ui->txtCode->clear();
}
else if (data.canConvert<ARCodeList::iterator>())
{
ARCode& code = *(data.value<ARCodeList::iterator>());
ui->btnDeleteCode->setEnabled(true);
ui->txtCode->setEnabled(true);
ui->txtCode->setPlaceholderText("(enter AR code here)");
QString codestr = "";
for (u32 i = 0; i < code.CodeLen; i += 2)
{
u32 c0 = code.Code[i+0];
u32 c1 = code.Code[i+1];
//codestr += QString("%1 %2\n").arg(c0, 8, 16, '0').arg(c1, 8, 16, '0').toUpper();
codestr += QString::asprintf("%08X %08X\n", c0, c1);
}
ui->txtCode->setPlainText(codestr);
}
ui->btnNewARCode->setEnabled(true);
}
}
void CheatsDialog::onCheatEntryModified(QStandardItem* item)
{
QVariant data = item->data();
if (data.canConvert<ARCodeCatList::iterator>())
{
ARCodeCat& cat = *(data.value<ARCodeCatList::iterator>());
if (item->text().isEmpty())
{
QString oldname = QString(cat.Name);
item->setText(oldname.isEmpty() ? "(blank category name??)" : oldname);
}
else
{
strncpy(cat.Name, item->text().toStdString().c_str(), 127);
cat.Name[127] = '\0';
}
}
else if (data.canConvert<ARCodeList::iterator>())
{
ARCode& code = *(data.value<ARCodeList::iterator>());
if (item->text().isEmpty())
{
QString oldname = QString(code.Name);
item->setText(oldname.isEmpty() ? "(blank code name??)" : oldname);
}
else
{
strncpy(code.Name, item->text().toStdString().c_str(), 127);
code.Name[127] = '\0';
}
code.Enabled = (item->checkState() == Qt::Checked);
}
}
void CheatsDialog::on_txtCode_textChanged()
{
QModelIndexList indices = ui->tvCodeList->selectionModel()->selectedIndexes();
if (indices.isEmpty())
return;
QStandardItem* item = ((QStandardItemModel*)ui->tvCodeList->model())->itemFromIndex(indices.first());
QVariant data = item->data();
if (!data.canConvert<ARCodeList::iterator>())
return;
bool error = false;
u32 codeout[2*64];
u32 codelen = 0;
QString text = ui->txtCode->document()->toPlainText();
QStringList lines = text.split('\n', QString::SkipEmptyParts);
for (QStringList::iterator it = lines.begin(); it != lines.end(); it++)
{
QString line = *it;
line = line.trimmed();
if (line.isEmpty()) continue;
if (line.length() > 17)
{
error = true;
break;
}
QStringList numbers = line.split(' ');
if (numbers.length() != 2)
{
error = true;
break;
}
QStringList::iterator jt = numbers.begin();
QString s0 = *jt++;
QString s1 = *jt++;
bool c0good, c1good;
u32 c0, c1;
c0 = s0.toUInt(&c0good, 16);
c1 = s1.toUInt(&c1good, 16);
if (!c0good || !c1good)
{
error = true;
break;
}
if (codelen >= 2*64)
{
error = true;
break;
}
codeout[codelen++] = c0;
codeout[codelen++] = c1;
}
ui->btnNewCat->setEnabled(!error);
ui->btnNewARCode->setEnabled(!error);
ui->btnDeleteCode->setEnabled(!error);
ui->tvCodeList->setEnabled(!error);
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!error);
if (error) return;
ARCode& code = *(data.value<ARCodeList::iterator>());
memcpy(code.Code, codeout, codelen*sizeof(u32));
code.CodeLen = codelen;
}
void ARCodeChecker::highlightBlock(const QString& text)
{
QTextCharFormat errformat; errformat.setForeground(Qt::red);
{
QRegularExpression expr("^\\s*[0-9A-Fa-f]{1,8} [0-9A-Fa-f]{1,8}\\s*$");
QRegularExpressionMatchIterator it = expr.globalMatch(text);
if (!it.hasNext())
{
setFormat(0, text.length(), errformat);
}
}
/*{
QRegularExpression expr("[^0-9A-Fa-f\\s]+");
QRegularExpressionMatchIterator it = expr.globalMatch(text);
while (it.hasNext())
{
QRegularExpressionMatch match = it.next();
setFormat(match.capturedStart(), match.capturedLength(), errformat);
}
}
{
QRegularExpression expr("[0-9A-Fa-f]{9,}");
QRegularExpressionMatchIterator it = expr.globalMatch(text);
while (it.hasNext())
{
QRegularExpressionMatch match = it.next();
setFormat(match.capturedStart(), match.capturedLength(), errformat);
}
}*/
}

View File

@ -0,0 +1,94 @@
/*
Copyright 2016-2020 Arisotura
This file is part of melonDS.
melonDS is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option)
any later version.
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with melonDS. If not, see http://www.gnu.org/licenses/.
*/
#ifndef CHEATSDIALOG_H
#define CHEATSDIALOG_H
#include <QDialog>
#include <QAbstractItemModel>
#include <QStandardItemModel>
#include <QItemSelection>
#include <QSyntaxHighlighter>
#include "ARCodeFile.h"
Q_DECLARE_METATYPE(ARCodeList::iterator)
Q_DECLARE_METATYPE(ARCodeCatList::iterator)
namespace Ui { class CheatsDialog; }
class CheatsDialog;
class ARCodeChecker : public QSyntaxHighlighter
{
Q_OBJECT
public:
ARCodeChecker(QTextDocument* parent) : QSyntaxHighlighter(parent) {}
~ARCodeChecker() {}
protected:
void highlightBlock(const QString& text) override;
};
class CheatsDialog : public QDialog
{
Q_OBJECT
public:
explicit CheatsDialog(QWidget* parent);
~CheatsDialog();
static CheatsDialog* currentDlg;
static CheatsDialog* openDlg(QWidget* parent)
{
if (currentDlg)
{
currentDlg->activateWindow();
return currentDlg;
}
currentDlg = new CheatsDialog(parent);
currentDlg->open();
return currentDlg;
}
static void closeDlg()
{
currentDlg = nullptr;
}
private slots:
void on_CheatsDialog_accepted();
void on_CheatsDialog_rejected();
void on_btnNewCat_clicked();
void on_btnNewARCode_clicked();
void on_btnDeleteCode_clicked();
void onCheatSelectionChanged(const QItemSelection& sel, const QItemSelection& desel);
void onCheatEntryModified(QStandardItem* item);
void on_txtCode_textChanged();
private:
Ui::CheatsDialog* ui;
ARCodeFile* codeFile;
ARCodeChecker* codeChecker;
};
#endif // CHEATSDIALOG_H

View File

@ -0,0 +1,144 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CheatsDialog</class>
<widget class="QDialog" name="CheatsDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>609</width>
<height>417</height>
</rect>
</property>
<property name="windowTitle">
<string>Cheat code editor - melonDS</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<item>
<widget class="QPushButton" name="btnNewCat">
<property name="text">
<string>New category</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnNewARCode">
<property name="text">
<string>New AR code</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnDeleteCode">
<property name="text">
<string>Delete</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QTreeView" name="tvCodeList">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>2</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>200</width>
<height>0</height>
</size>
</property>
<property name="headerHidden">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="txtCode">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>3</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>200</width>
<height>0</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>CheatsDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>304</x>
<y>396</y>
</hint>
<hint type="destinationlabel">
<x>304</x>
<y>208</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>CheatsDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>304</x>
<y>396</y>
</hint>
<hint type="destinationlabel">
<x>304</x>
<y>208</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -44,11 +44,15 @@ EmuSettingsDialog::EmuSettingsDialog(QWidget* parent) : QDialog(parent), ui(new
ui->txtBIOS9Path->setText(Config::BIOS9Path); ui->txtBIOS9Path->setText(Config::BIOS9Path);
ui->txtBIOS7Path->setText(Config::BIOS7Path); ui->txtBIOS7Path->setText(Config::BIOS7Path);
ui->txtFirmwarePath->setText(Config::FirmwarePath); ui->txtFirmwarePath->setText(Config::FirmwarePath);
ui->cbDLDIEnable->setChecked(Config::DLDIEnable != 0);
ui->txtDLDISDPath->setText(Config::DLDISDPath);
ui->txtDSiBIOS9Path->setText(Config::DSiBIOS9Path); ui->txtDSiBIOS9Path->setText(Config::DSiBIOS9Path);
ui->txtDSiBIOS7Path->setText(Config::DSiBIOS7Path); ui->txtDSiBIOS7Path->setText(Config::DSiBIOS7Path);
ui->txtDSiFirmwarePath->setText(Config::DSiFirmwarePath); ui->txtDSiFirmwarePath->setText(Config::DSiFirmwarePath);
ui->txtDSiNANDPath->setText(Config::DSiNANDPath); ui->txtDSiNANDPath->setText(Config::DSiNANDPath);
ui->cbDSiSDEnable->setChecked(Config::DSiSDEnable != 0);
ui->txtDSiSDPath->setText(Config::DSiSDPath);
ui->cbxConsoleType->addItem("DS"); ui->cbxConsoleType->addItem("DS");
ui->cbxConsoleType->addItem("DSi (experimental)"); ui->cbxConsoleType->addItem("DSi (experimental)");
@ -141,10 +145,14 @@ void EmuSettingsDialog::done(int r)
std::string bios9Path = ui->txtBIOS9Path->text().toStdString(); std::string bios9Path = ui->txtBIOS9Path->text().toStdString();
std::string bios7Path = ui->txtBIOS7Path->text().toStdString(); std::string bios7Path = ui->txtBIOS7Path->text().toStdString();
std::string firmwarePath = ui->txtFirmwarePath->text().toStdString(); std::string firmwarePath = ui->txtFirmwarePath->text().toStdString();
int dldiEnable = ui->cbDLDIEnable->isChecked() ? 1:0;
std::string dldiSDPath = ui->txtDLDISDPath->text().toStdString();
std::string dsiBios9Path = ui->txtDSiBIOS9Path->text().toStdString(); std::string dsiBios9Path = ui->txtDSiBIOS9Path->text().toStdString();
std::string dsiBios7Path = ui->txtDSiBIOS7Path->text().toStdString(); std::string dsiBios7Path = ui->txtDSiBIOS7Path->text().toStdString();
std::string dsiFirmwarePath = ui->txtDSiFirmwarePath->text().toStdString(); std::string dsiFirmwarePath = ui->txtDSiFirmwarePath->text().toStdString();
std::string dsiNANDPath = ui->txtDSiNANDPath->text().toStdString(); std::string dsiNANDPath = ui->txtDSiNANDPath->text().toStdString();
int dsiSDEnable = ui->cbDSiSDEnable->isChecked() ? 1:0;
std::string dsiSDPath = ui->txtDSiSDPath->text().toStdString();
if (consoleType != Config::ConsoleType if (consoleType != Config::ConsoleType
|| directBoot != Config::DirectBoot || directBoot != Config::DirectBoot
@ -158,10 +166,14 @@ void EmuSettingsDialog::done(int r)
|| strcmp(Config::BIOS9Path, bios9Path.c_str()) != 0 || strcmp(Config::BIOS9Path, bios9Path.c_str()) != 0
|| strcmp(Config::BIOS7Path, bios7Path.c_str()) != 0 || strcmp(Config::BIOS7Path, bios7Path.c_str()) != 0
|| strcmp(Config::FirmwarePath, firmwarePath.c_str()) != 0 || strcmp(Config::FirmwarePath, firmwarePath.c_str()) != 0
|| dldiEnable != Config::DLDIEnable
|| strcmp(Config::DLDISDPath, dldiSDPath.c_str()) != 0
|| strcmp(Config::DSiBIOS9Path, dsiBios9Path.c_str()) != 0 || strcmp(Config::DSiBIOS9Path, dsiBios9Path.c_str()) != 0
|| strcmp(Config::DSiBIOS7Path, dsiBios7Path.c_str()) != 0 || strcmp(Config::DSiBIOS7Path, dsiBios7Path.c_str()) != 0
|| strcmp(Config::DSiFirmwarePath, dsiFirmwarePath.c_str()) != 0 || strcmp(Config::DSiFirmwarePath, dsiFirmwarePath.c_str()) != 0
|| strcmp(Config::DSiNANDPath, dsiNANDPath.c_str()) != 0) || strcmp(Config::DSiNANDPath, dsiNANDPath.c_str()) != 0
|| dsiSDEnable != Config::DSiSDEnable
|| strcmp(Config::DSiSDPath, dsiSDPath.c_str()) != 0)
{ {
if (RunningSomething if (RunningSomething
&& QMessageBox::warning(this, "Reset necessary to apply changes", && QMessageBox::warning(this, "Reset necessary to apply changes",
@ -172,11 +184,15 @@ void EmuSettingsDialog::done(int r)
strncpy(Config::BIOS9Path, bios9Path.c_str(), 1023); Config::BIOS9Path[1023] = '\0'; strncpy(Config::BIOS9Path, bios9Path.c_str(), 1023); Config::BIOS9Path[1023] = '\0';
strncpy(Config::BIOS7Path, bios7Path.c_str(), 1023); Config::BIOS7Path[1023] = '\0'; strncpy(Config::BIOS7Path, bios7Path.c_str(), 1023); Config::BIOS7Path[1023] = '\0';
strncpy(Config::FirmwarePath, firmwarePath.c_str(), 1023); Config::FirmwarePath[1023] = '\0'; strncpy(Config::FirmwarePath, firmwarePath.c_str(), 1023); Config::FirmwarePath[1023] = '\0';
Config::DLDIEnable = dldiEnable;
strncpy(Config::DLDISDPath, dldiSDPath.c_str(), 1023); Config::DLDISDPath[1023] = '\0';
strncpy(Config::DSiBIOS9Path, dsiBios9Path.c_str(), 1023); Config::DSiBIOS9Path[1023] = '\0'; strncpy(Config::DSiBIOS9Path, dsiBios9Path.c_str(), 1023); Config::DSiBIOS9Path[1023] = '\0';
strncpy(Config::DSiBIOS7Path, dsiBios7Path.c_str(), 1023); Config::DSiBIOS7Path[1023] = '\0'; strncpy(Config::DSiBIOS7Path, dsiBios7Path.c_str(), 1023); Config::DSiBIOS7Path[1023] = '\0';
strncpy(Config::DSiFirmwarePath, dsiFirmwarePath.c_str(), 1023); Config::DSiFirmwarePath[1023] = '\0'; strncpy(Config::DSiFirmwarePath, dsiFirmwarePath.c_str(), 1023); Config::DSiFirmwarePath[1023] = '\0';
strncpy(Config::DSiNANDPath, dsiNANDPath.c_str(), 1023); Config::DSiNANDPath[1023] = '\0'; strncpy(Config::DSiNANDPath, dsiNANDPath.c_str(), 1023); Config::DSiNANDPath[1023] = '\0';
Config::DSiSDEnable = dsiSDEnable;
strncpy(Config::DSiSDPath, dsiSDPath.c_str(), 1023); Config::DSiSDPath[1023] = '\0';
#ifdef JIT_ENABLED #ifdef JIT_ENABLED
Config::JIT_Enable = jitEnable; Config::JIT_Enable = jitEnable;
@ -260,6 +276,18 @@ void EmuSettingsDialog::on_btnDSiBIOS7Browse_clicked()
ui->txtDSiBIOS7Path->setText(file); ui->txtDSiBIOS7Path->setText(file);
} }
void EmuSettingsDialog::on_btnDLDISDBrowse_clicked()
{
QString file = QFileDialog::getOpenFileName(this,
"Select DLDI SD image...",
EmuDirectory,
"Image files (*.bin *.rom *.img);;Any file (*.*)");
if (file.isEmpty()) return;
ui->txtDLDISDPath->setText(file);
}
void EmuSettingsDialog::on_btnDSiFirmwareBrowse_clicked() void EmuSettingsDialog::on_btnDSiFirmwareBrowse_clicked()
{ {
QString file = QFileDialog::getOpenFileName(this, QString file = QFileDialog::getOpenFileName(this,
@ -284,6 +312,18 @@ void EmuSettingsDialog::on_btnDSiNANDBrowse_clicked()
ui->txtDSiNANDPath->setText(file); ui->txtDSiNANDPath->setText(file);
} }
void EmuSettingsDialog::on_btnDSiSDBrowse_clicked()
{
QString file = QFileDialog::getOpenFileName(this,
"Select DSi SD image...",
EmuDirectory,
"Image files (*.bin *.rom *.img);;Any file (*.*)");
if (file.isEmpty()) return;
ui->txtDSiSDPath->setText(file);
}
void EmuSettingsDialog::on_chkEnableJIT_toggled() void EmuSettingsDialog::on_chkEnableJIT_toggled()
{ {
bool disabled = !ui->chkEnableJIT->isChecked(); bool disabled = !ui->chkEnableJIT->isChecked();

View File

@ -42,7 +42,7 @@ public:
} }
currentDlg = new EmuSettingsDialog(parent); currentDlg = new EmuSettingsDialog(parent);
currentDlg->show(); currentDlg->open();
return currentDlg; return currentDlg;
} }
static void closeDlg() static void closeDlg()
@ -58,11 +58,13 @@ private slots:
void on_btnBIOS9Browse_clicked(); void on_btnBIOS9Browse_clicked();
void on_btnBIOS7Browse_clicked(); void on_btnBIOS7Browse_clicked();
void on_btnFirmwareBrowse_clicked(); void on_btnFirmwareBrowse_clicked();
void on_btnDLDISDBrowse_clicked();
void on_btnDSiBIOS9Browse_clicked(); void on_btnDSiBIOS9Browse_clicked();
void on_btnDSiBIOS7Browse_clicked(); void on_btnDSiBIOS7Browse_clicked();
void on_btnDSiFirmwareBrowse_clicked(); void on_btnDSiFirmwareBrowse_clicked();
void on_btnDSiNANDBrowse_clicked(); void on_btnDSiNANDBrowse_clicked();
void on_btnDSiSDBrowse_clicked();
void on_chkEnableJIT_toggled(); void on_chkEnableJIT_toggled();

View File

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>514</width> <width>575</width>
<height>359</height> <height>254</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@ -86,209 +86,242 @@
</widget> </widget>
<widget class="QWidget" name="tab_2"> <widget class="QWidget" name="tab_2">
<attribute name="title"> <attribute name="title">
<string>BIOS Files</string> <string>DS-mode</string>
</attribute> </attribute>
<layout class="QVBoxLayout" name="verticalLayout_2"> <layout class="QGridLayout" name="gridLayout">
<item> <item row="1" column="1">
<widget class="QGroupBox" name="groupBox"> <widget class="QLineEdit" name="txtBIOS7Path">
<property name="title"> <property name="whatsThis">
<string>DS mode</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;DS-mode ARM7 BIOS&lt;/p&gt;&lt;p&gt;Size should be 16 KB&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>DS firmware:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="txtFirmwarePath">
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;DS-mode firmware&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Possible firmwares:&lt;/p&gt;&lt;p&gt;* 128 KB: DS-mode firmware from a DSi or 3DS. Not bootable.&lt;/p&gt;&lt;p&gt;* 256 KB: regular DS firmware.&lt;/p&gt;&lt;p&gt;* 512 KB: iQue DS firmware.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="txtBIOS7Path">
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;DS-mode ARM7 BIOS&lt;/p&gt;&lt;p&gt;Size should be 16 KB&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="btnBIOS9Browse">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Browse...</string>
</property>
<property name="autoDefault">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QPushButton" name="btnFirmwareBrowse">
<property name="text">
<string>Browse...</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>DS ARM7 BIOS:</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>DS ARM9 BIOS:</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="btnBIOS7Browse">
<property name="text">
<string>Browse...</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="txtBIOS9Path">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>290</width>
<height>0</height>
</size>
</property>
<property name="statusTip">
<string/>
</property>
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;DS-mode ARM9 BIOS&lt;/p&gt;&lt;p&gt;Size should be 4 KB&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
</layout>
</widget> </widget>
</item> </item>
<item> <item row="2" column="1">
<widget class="QGroupBox" name="groupBox_3"> <widget class="QLineEdit" name="txtFirmwarePath">
<property name="title"> <property name="whatsThis">
<string>DSi mode</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;DS-mode firmware&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Possible firmwares:&lt;/p&gt;&lt;p&gt;* 128 KB: DS-mode firmware from a DSi or 3DS. Not bootable.&lt;/p&gt;&lt;p&gt;* 256 KB: regular DS firmware.&lt;/p&gt;&lt;p&gt;* 512 KB: iQue DS firmware.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>DS firmware:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>DS ARM7 BIOS:</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="btnBIOS7Browse">
<property name="text">
<string>Browse...</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QPushButton" name="btnFirmwareBrowse">
<property name="text">
<string>Browse...</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="btnBIOS9Browse">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Browse...</string>
</property>
<property name="autoDefault">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>DS ARM9 BIOS:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="txtBIOS9Path">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>290</width>
<height>0</height>
</size>
</property>
<property name="statusTip">
<string/>
</property>
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;DS-mode ARM9 BIOS&lt;/p&gt;&lt;p&gt;Size should be 4 KB&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="3" column="0">
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_4">
<attribute name="title">
<string>DSi-mode</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="1">
<widget class="QLineEdit" name="txtDSiBIOS7Path">
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;DSi-mode ARM7 BIOS&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Size should be 64 KB&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="5" column="2">
<widget class="QPushButton" name="btnDSiSDBrowse">
<property name="text">
<string>Browse...</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>DSi NAND:</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QPushButton" name="btnDSiNANDBrowse">
<property name="text">
<string>Browse...</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>DSi ARM7 BIOS:</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QPushButton" name="btnDSiFirmwareBrowse">
<property name="text">
<string>Browse...</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="txtDSiNANDPath">
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;DSi NAND dump&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Should have 'nocash footer' at the end&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="btnDSiBIOS9Browse">
<property name="text">
<string>Browse...</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>DSi SD card:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="txtDSiBIOS9Path">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;DSi-mode ARM9 BIOS&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Size should be 64 KB&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>DSi firmware:</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>DSi ARM9 BIOS:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="txtDSiFirmwarePath">
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;DSi-mode firmware (used for DS-mode backwards compatibility)&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Size should be 128 KB&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="txtDSiSDPath">
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;SD image file for emulating the DSi's SD card&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="3">
<widget class="QCheckBox" name="cbDSiSDEnable">
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Simulate a SD card being inserted in the DSi's SD slot. Requires a SD card image.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Enable DSi SD card</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="btnDSiBIOS7Browse">
<property name="text">
<string>Browse...</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="2">
<widget class="QPushButton" name="btnDSiBIOS9Browse">
<property name="text">
<string>Browse...</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>DSi ARM9 BIOS:</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QPushButton" name="btnDSiFirmwareBrowse">
<property name="text">
<string>Browse...</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="txtDSiBIOS7Path">
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;DSi-mode ARM7 BIOS&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Size should be 64 KB&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="txtDSiFirmwarePath">
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;DSi-mode firmware (used for DS-mode backwards compatibility)&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Size should be 128 KB&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>DSi ARM7 BIOS:</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>DSi firmware:</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="btnDSiBIOS7Browse">
<property name="text">
<string>Browse...</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="txtDSiBIOS9Path">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;DSi-mode ARM9 BIOS&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Size should be 64 KB&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>DSi NAND:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="txtDSiNANDPath">
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;DSi NAND dump&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Should have 'nocash footer' at the end&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QPushButton" name="btnDSiNANDBrowse">
<property name="text">
<string>Browse...</string>
</property>
</widget>
</item>
</layout>
</widget> </widget>
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="tab_3"> <widget class="QWidget" name="tab_3">
<attribute name="title"> <attribute name="title">
<string>CPU Emulation</string> <string>CPU emulation</string>
</attribute> </attribute>
<layout class="QFormLayout" name="formLayout_5"> <layout class="QFormLayout" name="formLayout_5">
<item row="0" column="0"> <item row="0" column="0">
@ -354,6 +387,53 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="tab_5">
<attribute name="title">
<string>DLDI</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0" colspan="3">
<widget class="QCheckBox" name="cbDLDIEnable">
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable the built-in DLDI driver, to let homebrew access files from a given SD image.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Enable DLDI (for homebrew)</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="btnDLDISDBrowse">
<property name="text">
<string>Browse...</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="txtDLDISDPath"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>DLDI SD card:</string>
</property>
</widget>
</item>
<item row="2" column="0">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget> </widget>
</item> </item>
<item> <item>
@ -369,23 +449,8 @@
</layout> </layout>
</widget> </widget>
<tabstops> <tabstops>
<tabstop>tabWidget</tabstop>
<tabstop>cbxConsoleType</tabstop> <tabstop>cbxConsoleType</tabstop>
<tabstop>chkDirectBoot</tabstop> <tabstop>chkDirectBoot</tabstop>
<tabstop>txtBIOS9Path</tabstop>
<tabstop>txtBIOS7Path</tabstop>
<tabstop>txtFirmwarePath</tabstop>
<tabstop>txtDSiBIOS9Path</tabstop>
<tabstop>txtDSiBIOS7Path</tabstop>
<tabstop>txtDSiFirmwarePath</tabstop>
<tabstop>txtDSiNANDPath</tabstop>
<tabstop>btnBIOS9Browse</tabstop>
<tabstop>btnBIOS7Browse</tabstop>
<tabstop>btnFirmwareBrowse</tabstop>
<tabstop>btnDSiBIOS9Browse</tabstop>
<tabstop>btnDSiBIOS7Browse</tabstop>
<tabstop>btnDSiFirmwareBrowse</tabstop>
<tabstop>btnDSiNANDBrowse</tabstop>
<tabstop>chkEnableJIT</tabstop> <tabstop>chkEnableJIT</tabstop>
<tabstop>spnJITMaximumBlockSize</tabstop> <tabstop>spnJITMaximumBlockSize</tabstop>
</tabstops> </tabstops>

View File

@ -98,7 +98,9 @@ int GetEventKeyVal(QKeyEvent* event)
void KeyPress(QKeyEvent* event) void KeyPress(QKeyEvent* event)
{ {
int keyHK = GetEventKeyVal(event); int keyHK = GetEventKeyVal(event);
int keyKP = keyHK & ~event->modifiers(); int keyKP = keyHK;
if (event->modifiers() != Qt::KeypadModifier)
keyKP &= ~event->modifiers();
for (int i = 0; i < 12; i++) for (int i = 0; i < 12; i++)
if (keyKP == Config::KeyMapping[i]) if (keyKP == Config::KeyMapping[i])
@ -112,7 +114,9 @@ void KeyPress(QKeyEvent* event)
void KeyRelease(QKeyEvent* event) void KeyRelease(QKeyEvent* event)
{ {
int keyHK = GetEventKeyVal(event); int keyHK = GetEventKeyVal(event);
int keyKP = keyHK & ~event->modifiers(); int keyKP = keyHK;
if (event->modifiers() != Qt::KeypadModifier)
keyKP &= ~event->modifiers();
for (int i = 0; i < 12; i++) for (int i = 0; i < 12; i++)
if (keyKP == Config::KeyMapping[i]) if (keyKP == Config::KeyMapping[i])

View File

@ -54,6 +54,7 @@ const int hk_general[] =
HK_Reset, HK_Reset,
HK_FastForward, HK_FastForward,
HK_FastForwardToggle, HK_FastForwardToggle,
HK_FullscreenToggle,
HK_Lid, HK_Lid,
HK_Mic, HK_Mic,
}; };
@ -64,6 +65,7 @@ const char* hk_general_labels[] =
"Reset", "Reset",
"Fast forward", "Fast forward",
"Toggle FPS limit", "Toggle FPS limit",
"Toggle Fullscreen",
"Close/open lid", "Close/open lid",
"Microphone", "Microphone",
}; };
@ -86,7 +88,7 @@ InputConfigDialog::InputConfigDialog(QWidget* parent) : QDialog(parent), ui(new
addonsJoyMap[i] = Config::HKJoyMapping[hk_addons[i]]; addonsJoyMap[i] = Config::HKJoyMapping[hk_addons[i]];
} }
for (int i = 0; i < 6; i++) for (int i = 0; i < 7; i++)
{ {
hkGeneralKeyMap[i] = Config::HKKeyMapping[hk_general[i]]; hkGeneralKeyMap[i] = Config::HKKeyMapping[hk_general[i]];
hkGeneralJoyMap[i] = Config::HKJoyMapping[hk_general[i]]; hkGeneralJoyMap[i] = Config::HKJoyMapping[hk_general[i]];
@ -94,7 +96,7 @@ InputConfigDialog::InputConfigDialog(QWidget* parent) : QDialog(parent), ui(new
populatePage(ui->tabInput, 12, dskeylabels, keypadKeyMap, keypadJoyMap); populatePage(ui->tabInput, 12, dskeylabels, keypadKeyMap, keypadJoyMap);
populatePage(ui->tabAddons, 2, hk_addons_labels, addonsKeyMap, addonsJoyMap); populatePage(ui->tabAddons, 2, hk_addons_labels, addonsKeyMap, addonsJoyMap);
populatePage(ui->tabHotkeysGeneral, 6, hk_general_labels, hkGeneralKeyMap, hkGeneralJoyMap); populatePage(ui->tabHotkeysGeneral, 7, hk_general_labels, hkGeneralKeyMap, hkGeneralJoyMap);
int njoy = SDL_NumJoysticks(); int njoy = SDL_NumJoysticks();
if (njoy > 0) if (njoy > 0)
@ -177,7 +179,7 @@ void InputConfigDialog::on_InputConfigDialog_accepted()
Config::HKJoyMapping[hk_addons[i]] = addonsJoyMap[i]; Config::HKJoyMapping[hk_addons[i]] = addonsJoyMap[i];
} }
for (int i = 0; i < 6; i++) for (int i = 0; i < 7; i++)
{ {
Config::HKKeyMapping[hk_general[i]] = hkGeneralKeyMap[i]; Config::HKKeyMapping[hk_general[i]] = hkGeneralKeyMap[i];
Config::HKJoyMapping[hk_general[i]] = hkGeneralJoyMap[i]; Config::HKJoyMapping[hk_general[i]] = hkGeneralJoyMap[i];
@ -226,7 +228,7 @@ void KeyMapButton::keyPressEvent(QKeyEvent* event)
{ {
if (!isChecked()) return QPushButton::keyPressEvent(event); if (!isChecked()) return QPushButton::keyPressEvent(event);
printf("KEY PRESSED = %08X %08X | %08X %08X %08X\n", event->key(), event->modifiers(), event->nativeVirtualKey(), event->nativeModifiers(), event->nativeScanCode()); printf("KEY PRESSED = %08X %08X | %08X %08X %08X\n", event->key(), (int)event->modifiers(), event->nativeVirtualKey(), event->nativeModifiers(), event->nativeScanCode());
int key = event->key(); int key = event->key();
int mod = event->modifiers(); int mod = event->modifiers();

View File

@ -64,7 +64,7 @@ private:
int keypadKeyMap[12], keypadJoyMap[12]; int keypadKeyMap[12], keypadJoyMap[12];
int addonsKeyMap[2], addonsJoyMap[2]; int addonsKeyMap[2], addonsJoyMap[2];
int hkGeneralKeyMap[6], hkGeneralJoyMap[6]; int hkGeneralKeyMap[7], hkGeneralJoyMap[7];
}; };

View File

@ -77,7 +77,7 @@ u8 PacketBuffer[2048];
void Init(int argc, char** argv) void Init(int argc, char** argv)
{ {
#if defined(__WIN32__) || defined(UNIX_PORTABLE) #if defined(__WIN32__) || defined(PORTABLE)
if (argc > 0 && strlen(argv[0]) > 0) if (argc > 0 && strlen(argv[0]) > 0)
{ {
int len = strlen(argv[0]); int len = strlen(argv[0]);
@ -137,13 +137,20 @@ FILE* OpenFile(const char* path, const char* mode, bool mustexist)
} }
QIODevice::OpenMode qmode; QIODevice::OpenMode qmode;
if (strlen(mode) > 1 && mode[0] == 'r' && mode[1] == '+') { if (strlen(mode) > 1 && mode[0] == 'r' && mode[1] == '+')
{
qmode = QIODevice::OpenModeFlag::ReadWrite; qmode = QIODevice::OpenModeFlag::ReadWrite;
} else if (strlen(mode) > 1 && mode[0] == 'w' && mode[1] == '+') { }
else if (strlen(mode) > 1 && mode[0] == 'w' && mode[1] == '+')
{
qmode = QIODevice::OpenModeFlag::Truncate | QIODevice::OpenModeFlag::ReadWrite; qmode = QIODevice::OpenModeFlag::Truncate | QIODevice::OpenModeFlag::ReadWrite;
} else if (mode[0] == 'w') { }
else if (mode[0] == 'w')
{
qmode = QIODevice::OpenModeFlag::Truncate | QIODevice::OpenModeFlag::WriteOnly; qmode = QIODevice::OpenModeFlag::Truncate | QIODevice::OpenModeFlag::WriteOnly;
} else { }
else
{
qmode = QIODevice::OpenModeFlag::ReadOnly; qmode = QIODevice::OpenModeFlag::ReadOnly;
} }
@ -167,7 +174,7 @@ FILE* OpenLocalFile(const char* path, const char* mode)
else else
{ {
#ifdef PORTABLE #ifdef PORTABLE
fullpath = path; fullpath = QString(EmuDirectory) + QDir::separator() + path;
#else #else
// Check user configuration directory // Check user configuration directory
QDir config(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation)); QDir config(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation));

View File

@ -51,7 +51,7 @@ int _3DRenderer;
int Threaded3D; int Threaded3D;
int GL_ScaleFactor; int GL_ScaleFactor;
int GL_Antialias; int GL_BetterPolygons;
int LimitFPS; int LimitFPS;
int AudioSync; int AudioSync;
@ -72,6 +72,8 @@ char MicWavPath[1024];
char LastROMFolder[1024]; char LastROMFolder[1024];
int EnableCheats;
bool EnableJIT; bool EnableJIT;
ConfigEntry PlatformConfigFile[] = ConfigEntry PlatformConfigFile[] =
@ -108,6 +110,7 @@ ConfigEntry PlatformConfigFile[] =
{"HKKey_Reset", 0, &HKKeyMapping[HK_Reset], -1, NULL, 0}, {"HKKey_Reset", 0, &HKKeyMapping[HK_Reset], -1, NULL, 0},
{"HKKey_FastForward", 0, &HKKeyMapping[HK_FastForward], -1, NULL, 0}, {"HKKey_FastForward", 0, &HKKeyMapping[HK_FastForward], -1, NULL, 0},
{"HKKey_FastForwardToggle", 0, &HKKeyMapping[HK_FastForwardToggle], -1, NULL, 0}, {"HKKey_FastForwardToggle", 0, &HKKeyMapping[HK_FastForwardToggle], -1, NULL, 0},
{"HKKey_FullscreenToggle", 0, &HKKeyMapping[HK_FullscreenToggle], -1, NULL, 0},
{"HKKey_SolarSensorDecrease", 0, &HKKeyMapping[HK_SolarSensorDecrease], -1, NULL, 0}, {"HKKey_SolarSensorDecrease", 0, &HKKeyMapping[HK_SolarSensorDecrease], -1, NULL, 0},
{"HKKey_SolarSensorIncrease", 0, &HKKeyMapping[HK_SolarSensorIncrease], -1, NULL, 0}, {"HKKey_SolarSensorIncrease", 0, &HKKeyMapping[HK_SolarSensorIncrease], -1, NULL, 0},
@ -117,6 +120,7 @@ ConfigEntry PlatformConfigFile[] =
{"HKJoy_Reset", 0, &HKJoyMapping[HK_Reset], -1, NULL, 0}, {"HKJoy_Reset", 0, &HKJoyMapping[HK_Reset], -1, NULL, 0},
{"HKJoy_FastForward", 0, &HKJoyMapping[HK_FastForward], -1, NULL, 0}, {"HKJoy_FastForward", 0, &HKJoyMapping[HK_FastForward], -1, NULL, 0},
{"HKJoy_FastForwardToggle", 0, &HKJoyMapping[HK_FastForwardToggle], -1, NULL, 0}, {"HKJoy_FastForwardToggle", 0, &HKJoyMapping[HK_FastForwardToggle], -1, NULL, 0},
{"HKJoy_FastForwardToggle", 0, &HKJoyMapping[HK_FullscreenToggle], -1, NULL, 0},
{"HKJoy_SolarSensorDecrease", 0, &HKJoyMapping[HK_SolarSensorDecrease], -1, NULL, 0}, {"HKJoy_SolarSensorDecrease", 0, &HKJoyMapping[HK_SolarSensorDecrease], -1, NULL, 0},
{"HKJoy_SolarSensorIncrease", 0, &HKJoyMapping[HK_SolarSensorIncrease], -1, NULL, 0}, {"HKJoy_SolarSensorIncrease", 0, &HKJoyMapping[HK_SolarSensorIncrease], -1, NULL, 0},
@ -133,15 +137,15 @@ ConfigEntry PlatformConfigFile[] =
{"IntegerScaling", 0, &IntegerScaling, 0, NULL, 0}, {"IntegerScaling", 0, &IntegerScaling, 0, NULL, 0},
{"ScreenFilter", 0, &ScreenFilter, 1, NULL, 0}, {"ScreenFilter", 0, &ScreenFilter, 1, NULL, 0},
{"ScreenUseGL", 0, &ScreenUseGL, 1, NULL, 0}, {"ScreenUseGL", 0, &ScreenUseGL, 0, NULL, 0},
{"ScreenVSync", 0, &ScreenVSync, 0, NULL, 0}, {"ScreenVSync", 0, &ScreenVSync, 0, NULL, 0},
{"ScreenVSyncInterval", 0, &ScreenVSyncInterval, 1, NULL, 0}, {"ScreenVSyncInterval", 0, &ScreenVSyncInterval, 1, NULL, 0},
{"3DRenderer", 0, &_3DRenderer, 1, NULL, 0}, {"3DRenderer", 0, &_3DRenderer, 0, NULL, 0},
{"Threaded3D", 0, &Threaded3D, 1, NULL, 0}, {"Threaded3D", 0, &Threaded3D, 1, NULL, 0},
{"GL_ScaleFactor", 0, &GL_ScaleFactor, 1, NULL, 0}, {"GL_ScaleFactor", 0, &GL_ScaleFactor, 1, NULL, 0},
{"GL_Antialias", 0, &GL_Antialias, 0, NULL, 0}, {"GL_BetterPolygons", 0, &GL_BetterPolygons, 0, NULL, 0},
{"LimitFPS", 0, &LimitFPS, 0, NULL, 0}, {"LimitFPS", 0, &LimitFPS, 0, NULL, 0},
{"AudioSync", 0, &AudioSync, 1, NULL, 0}, {"AudioSync", 0, &AudioSync, 1, NULL, 0},
@ -162,6 +166,8 @@ ConfigEntry PlatformConfigFile[] =
{"LastROMFolder", 1, LastROMFolder, 0, "", 1023}, {"LastROMFolder", 1, LastROMFolder, 0, "", 1023},
{"EnableCheats", 0, &EnableCheats, 0, NULL, 0},
{"", -1, NULL, 0, NULL, 0} {"", -1, NULL, 0, NULL, 0}
}; };

View File

@ -29,6 +29,7 @@ enum
HK_Reset, HK_Reset,
HK_FastForward, HK_FastForward,
HK_FastForwardToggle, HK_FastForwardToggle,
HK_FullscreenToggle,
HK_SolarSensorDecrease, HK_SolarSensorDecrease,
HK_SolarSensorIncrease, HK_SolarSensorIncrease,
HK_MAX HK_MAX
@ -64,7 +65,7 @@ extern int _3DRenderer;
extern int Threaded3D; extern int Threaded3D;
extern int GL_ScaleFactor; extern int GL_ScaleFactor;
extern int GL_Antialias; extern int GL_BetterPolygons;
extern int LimitFPS; extern int LimitFPS;
extern int AudioSync; extern int AudioSync;
@ -85,6 +86,8 @@ extern char MicWavPath[1024];
extern char LastROMFolder[1024]; extern char LastROMFolder[1024];
extern int EnableCheats;
} }
#endif // PLATFORMCONFIG_H #endif // PLATFORMCONFIG_H

View File

@ -42,6 +42,7 @@ VideoSettingsDialog::VideoSettingsDialog(QWidget* parent) : QDialog(parent), ui(
oldVSyncInterval = Config::ScreenVSyncInterval; oldVSyncInterval = Config::ScreenVSyncInterval;
oldSoftThreaded = Config::Threaded3D; oldSoftThreaded = Config::Threaded3D;
oldGLScale = Config::GL_ScaleFactor; oldGLScale = Config::GL_ScaleFactor;
oldGLBetterPolygons = Config::GL_BetterPolygons;
grp3DRenderer = new QButtonGroup(this); grp3DRenderer = new QButtonGroup(this);
grp3DRenderer->addButton(ui->rb3DSoftware, 0); grp3DRenderer->addButton(ui->rb3DSoftware, 0);
@ -49,6 +50,10 @@ VideoSettingsDialog::VideoSettingsDialog(QWidget* parent) : QDialog(parent), ui(
connect(grp3DRenderer, SIGNAL(buttonClicked(int)), this, SLOT(onChange3DRenderer(int))); connect(grp3DRenderer, SIGNAL(buttonClicked(int)), this, SLOT(onChange3DRenderer(int)));
grp3DRenderer->button(Config::_3DRenderer)->setChecked(true); grp3DRenderer->button(Config::_3DRenderer)->setChecked(true);
#ifndef OGLRENDERER_ENABLED
ui->rb3DOpenGL->setEnabled(false);
#endif
ui->cbGLDisplay->setChecked(Config::ScreenUseGL != 0); ui->cbGLDisplay->setChecked(Config::ScreenUseGL != 0);
ui->cbVSync->setChecked(Config::ScreenVSync != 0); ui->cbVSync->setChecked(Config::ScreenVSync != 0);
@ -60,6 +65,8 @@ VideoSettingsDialog::VideoSettingsDialog(QWidget* parent) : QDialog(parent), ui(
ui->cbxGLResolution->addItem(QString("%1x native (%2x%3)").arg(i).arg(256*i).arg(192*i)); ui->cbxGLResolution->addItem(QString("%1x native (%2x%3)").arg(i).arg(256*i).arg(192*i));
ui->cbxGLResolution->setCurrentIndex(Config::GL_ScaleFactor-1); ui->cbxGLResolution->setCurrentIndex(Config::GL_ScaleFactor-1);
ui->cbBetterPolygons->setChecked(Config::GL_BetterPolygons != 0);
if (!Config::ScreenVSync) if (!Config::ScreenVSync)
ui->sbVSyncInterval->setEnabled(false); ui->sbVSyncInterval->setEnabled(false);
@ -68,12 +75,14 @@ VideoSettingsDialog::VideoSettingsDialog(QWidget* parent) : QDialog(parent), ui(
ui->cbGLDisplay->setEnabled(true); ui->cbGLDisplay->setEnabled(true);
ui->cbSoftwareThreaded->setEnabled(true); ui->cbSoftwareThreaded->setEnabled(true);
ui->cbxGLResolution->setEnabled(false); ui->cbxGLResolution->setEnabled(false);
ui->cbBetterPolygons->setEnabled(false);
} }
else else
{ {
ui->cbGLDisplay->setEnabled(false); ui->cbGLDisplay->setEnabled(false);
ui->cbSoftwareThreaded->setEnabled(false); ui->cbSoftwareThreaded->setEnabled(false);
ui->cbxGLResolution->setEnabled(true); ui->cbxGLResolution->setEnabled(true);
ui->cbBetterPolygons->setEnabled(true);
} }
} }
@ -99,6 +108,7 @@ void VideoSettingsDialog::on_VideoSettingsDialog_rejected()
Config::ScreenVSyncInterval = oldVSyncInterval; Config::ScreenVSyncInterval = oldVSyncInterval;
Config::Threaded3D = oldSoftThreaded; Config::Threaded3D = oldSoftThreaded;
Config::GL_ScaleFactor = oldGLScale; Config::GL_ScaleFactor = oldGLScale;
Config::GL_BetterPolygons = oldGLBetterPolygons;
bool new_gl = (Config::ScreenUseGL != 0) || (Config::_3DRenderer != 0); bool new_gl = (Config::ScreenUseGL != 0) || (Config::_3DRenderer != 0);
emit updateVideoSettings(old_gl != new_gl); emit updateVideoSettings(old_gl != new_gl);
@ -117,12 +127,14 @@ void VideoSettingsDialog::onChange3DRenderer(int renderer)
ui->cbGLDisplay->setEnabled(true); ui->cbGLDisplay->setEnabled(true);
ui->cbSoftwareThreaded->setEnabled(true); ui->cbSoftwareThreaded->setEnabled(true);
ui->cbxGLResolution->setEnabled(false); ui->cbxGLResolution->setEnabled(false);
ui->cbBetterPolygons->setEnabled(false);
} }
else else
{ {
ui->cbGLDisplay->setEnabled(false); ui->cbGLDisplay->setEnabled(false);
ui->cbSoftwareThreaded->setEnabled(false); ui->cbSoftwareThreaded->setEnabled(false);
ui->cbxGLResolution->setEnabled(true); ui->cbxGLResolution->setEnabled(true);
ui->cbBetterPolygons->setEnabled(true);
} }
bool new_gl = (Config::ScreenUseGL != 0) || (Config::_3DRenderer != 0); bool new_gl = (Config::ScreenUseGL != 0) || (Config::_3DRenderer != 0);
@ -167,3 +179,10 @@ void VideoSettingsDialog::on_cbxGLResolution_currentIndexChanged(int idx)
emit updateVideoSettings(false); emit updateVideoSettings(false);
} }
void VideoSettingsDialog::on_cbBetterPolygons_stateChanged(int state)
{
Config::GL_BetterPolygons = (state != 0);
emit updateVideoSettings(false);
}

View File

@ -64,6 +64,7 @@ private slots:
void on_sbVSyncInterval_valueChanged(int val); void on_sbVSyncInterval_valueChanged(int val);
void on_cbxGLResolution_currentIndexChanged(int idx); void on_cbxGLResolution_currentIndexChanged(int idx);
void on_cbBetterPolygons_stateChanged(int state);
void on_cbSoftwareThreaded_stateChanged(int state); void on_cbSoftwareThreaded_stateChanged(int state);
@ -78,6 +79,7 @@ private:
int oldVSyncInterval; int oldVSyncInterval;
int oldSoftThreaded; int oldSoftThreaded;
int oldGLScale; int oldGLScale;
int oldGLBetterPolygons;
}; };
#endif // VIDEOSETTINGSDIALOG_H #endif // VIDEOSETTINGSDIALOG_H

View File

@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>482</width> <width>482</width>
<height>237</height> <height>244</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@ -43,6 +43,16 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0">
<widget class="QCheckBox" name="cbBetterPolygons">
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enabling this may help reduce distortion on quads and more complex polygons, but may also reduce performance.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Improved polygon splitting</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>

View File

@ -17,7 +17,7 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include <QFileDialog> #include <QMessageBox>
#include "types.h" #include "types.h"
#include "Platform.h" #include "Platform.h"
@ -41,6 +41,10 @@
WifiSettingsDialog* WifiSettingsDialog::currentDlg = nullptr; WifiSettingsDialog* WifiSettingsDialog::currentDlg = nullptr;
bool WifiSettingsDialog::needsReset = false;
extern bool RunningSomething;
WifiSettingsDialog::WifiSettingsDialog(QWidget* parent) : QDialog(parent), ui(new Ui::WifiSettingsDialog) WifiSettingsDialog::WifiSettingsDialog(QWidget* parent) : QDialog(parent), ui(new Ui::WifiSettingsDialog)
{ {
@ -53,6 +57,7 @@ WifiSettingsDialog::WifiSettingsDialog(QWidget* parent) : QDialog(parent), ui(ne
ui->cbDirectMode->setText("Direct mode (requires " PCAP_NAME " and ethernet connection)"); ui->cbDirectMode->setText("Direct mode (requires " PCAP_NAME " and ethernet connection)");
ui->cbBindAnyAddr->setChecked(Config::SocketBindAnyAddr != 0); ui->cbBindAnyAddr->setChecked(Config::SocketBindAnyAddr != 0);
ui->cbRandomizeMAC->setChecked(Config::RandomizeMAC != 0);
int sel = 0; int sel = 0;
for (int i = 0; i < LAN_PCap::NumAdapters; i++) for (int i = 0; i < LAN_PCap::NumAdapters; i++)
@ -77,33 +82,49 @@ WifiSettingsDialog::~WifiSettingsDialog()
delete ui; delete ui;
} }
void WifiSettingsDialog::on_WifiSettingsDialog_accepted() void WifiSettingsDialog::done(int r)
{ {
Config::SocketBindAnyAddr = ui->cbBindAnyAddr->isChecked() ? 1:0; needsReset = false;
Config::DirectLAN = ui->cbDirectMode->isChecked() ? 1:0;
int sel = ui->cbxDirectAdapter->currentIndex(); if (r == QDialog::Accepted)
if (sel < 0 || sel >= LAN_PCap::NumAdapters) sel = 0;
if (LAN_PCap::NumAdapters < 1)
{ {
Config::LANDevice[0] = '\0'; int randommac = ui->cbRandomizeMAC->isChecked() ? 1:0;
}
else if (randommac != Config::RandomizeMAC)
{ {
strncpy(Config::LANDevice, LAN_PCap::Adapters[sel].DeviceName, 127); if (RunningSomething
Config::LANDevice[127] = '\0'; && QMessageBox::warning(this, "Reset necessary to apply changes",
"The emulation will be reset for the changes to take place.",
QMessageBox::Ok, QMessageBox::Cancel) != QMessageBox::Ok)
return;
}
Config::SocketBindAnyAddr = ui->cbBindAnyAddr->isChecked() ? 1:0;
Config::RandomizeMAC = randommac;
Config::DirectLAN = ui->cbDirectMode->isChecked() ? 1:0;
int sel = ui->cbxDirectAdapter->currentIndex();
if (sel < 0 || sel >= LAN_PCap::NumAdapters) sel = 0;
if (LAN_PCap::NumAdapters < 1)
{
Config::LANDevice[0] = '\0';
}
else
{
strncpy(Config::LANDevice, LAN_PCap::Adapters[sel].DeviceName, 127);
Config::LANDevice[127] = '\0';
}
Config::Save();
needsReset = true;
} }
Config::Save(); QDialog::done(r);
closeDlg(); closeDlg();
} }
void WifiSettingsDialog::on_WifiSettingsDialog_rejected()
{
closeDlg();
}
void WifiSettingsDialog::on_cbDirectMode_stateChanged(int state) void WifiSettingsDialog::on_cbDirectMode_stateChanged(int state)
{ {
updateAdapterControls(); updateAdapterControls();

View File

@ -42,7 +42,7 @@ public:
} }
currentDlg = new WifiSettingsDialog(parent); currentDlg = new WifiSettingsDialog(parent);
currentDlg->show(); currentDlg->open();
return currentDlg; return currentDlg;
} }
static void closeDlg() static void closeDlg()
@ -50,9 +50,10 @@ public:
currentDlg = nullptr; currentDlg = nullptr;
} }
static bool needsReset;
private slots: private slots:
void on_WifiSettingsDialog_accepted(); void done(int r);
void on_WifiSettingsDialog_rejected();
void on_cbDirectMode_stateChanged(int state); void on_cbDirectMode_stateChanged(int state);
void on_cbxDirectAdapter_currentIndexChanged(int sel); void on_cbxDirectAdapter_currentIndexChanged(int sel);

View File

@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>479</width> <width>479</width>
<height>217</height> <height>240</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@ -39,6 +39,16 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="0">
<widget class="QCheckBox" name="cbRandomizeMAC">
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Randomizes the console's MAC address upon reset. Required for local multiplayer if each melonDS instance uses the same firmware file.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Randomize MAC address</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>

View File

@ -41,6 +41,7 @@
#include "main.h" #include "main.h"
#include "Input.h" #include "Input.h"
#include "CheatsDialog.h"
#include "EmuSettingsDialog.h" #include "EmuSettingsDialog.h"
#include "InputConfigDialog.h" #include "InputConfigDialog.h"
#include "VideoSettingsDialog.h" #include "VideoSettingsDialog.h"
@ -55,7 +56,9 @@
#include "NDS.h" #include "NDS.h"
#include "GBACart.h" #include "GBACart.h"
#ifdef OGLRENDERER_ENABLED
#include "OpenGLSupport.h" #include "OpenGLSupport.h"
#endif
#include "GPU.h" #include "GPU.h"
#include "SPU.h" #include "SPU.h"
#include "Wifi.h" #include "Wifi.h"
@ -120,7 +123,6 @@ void audioCallback(void* data, Uint8* stream, int len)
if (num_in < len_in-margin) if (num_in < len_in-margin)
{ {
int last = num_in-1; int last = num_in-1;
if (last < 0) last = 0;
for (int i = num_in; i < len_in-margin; i++) for (int i = num_in; i < len_in-margin; i++)
((u32*)buf_in)[i] = ((u32*)buf_in)[last]; ((u32*)buf_in)[i] = ((u32*)buf_in)[last];
@ -273,6 +275,7 @@ EmuThread::EmuThread(QObject* parent) : QThread(parent)
connect(this, SIGNAL(windowEmuPause()), mainWindow->actPause, SLOT(trigger())); connect(this, SIGNAL(windowEmuPause()), mainWindow->actPause, SLOT(trigger()));
connect(this, SIGNAL(windowEmuReset()), mainWindow->actReset, SLOT(trigger())); connect(this, SIGNAL(windowEmuReset()), mainWindow->actReset, SLOT(trigger()));
connect(this, SIGNAL(screenLayoutChange()), mainWindow->panel, SLOT(onScreenLayoutChanged())); connect(this, SIGNAL(screenLayoutChange()), mainWindow->panel, SLOT(onScreenLayoutChanged()));
connect(this, SIGNAL(windowFullscreenToggle()), mainWindow, SLOT(onFullscreenToggled()));
if (mainWindow->hasOGL) initOpenGL(); if (mainWindow->hasOGL) initOpenGL();
} }
@ -342,13 +345,17 @@ void EmuThread::run()
videoSettings.Soft_Threaded = Config::Threaded3D != 0; videoSettings.Soft_Threaded = Config::Threaded3D != 0;
videoSettings.GL_ScaleFactor = Config::GL_ScaleFactor; videoSettings.GL_ScaleFactor = Config::GL_ScaleFactor;
#ifdef OGLRENDERER_ENABLED
if (hasOGL) if (hasOGL)
{ {
oglContext->makeCurrent(oglSurface); oglContext->makeCurrent(oglSurface);
videoRenderer = OpenGL::Init() ? Config::_3DRenderer : 0; videoRenderer = OpenGL::Init() ? Config::_3DRenderer : 0;
} }
else else
#endif
{
videoRenderer = 0; videoRenderer = 0;
}
GPU::InitRenderer(videoRenderer); GPU::InitRenderer(videoRenderer);
GPU::SetRenderSettings(videoRenderer, videoSettings); GPU::SetRenderSettings(videoRenderer, videoSettings);
@ -371,6 +378,8 @@ void EmuThread::run()
if (Input::HotkeyPressed(HK_Pause)) emit windowEmuPause(); if (Input::HotkeyPressed(HK_Pause)) emit windowEmuPause();
if (Input::HotkeyPressed(HK_Reset)) emit windowEmuReset(); if (Input::HotkeyPressed(HK_Reset)) emit windowEmuReset();
if (Input::HotkeyPressed(HK_FullscreenToggle)) emit windowFullscreenToggle();
if (GBACart::CartInserted && GBACart::HasSolarSensor) if (GBACart::CartInserted && GBACart::HasSolarSensor)
{ {
@ -400,20 +409,27 @@ void EmuThread::run()
if (hasOGL != mainWindow->hasOGL) if (hasOGL != mainWindow->hasOGL)
{ {
hasOGL = mainWindow->hasOGL; hasOGL = mainWindow->hasOGL;
#ifdef OGLRENDERER_ENABLED
if (hasOGL) if (hasOGL)
{ {
oglContext->makeCurrent(oglSurface); oglContext->makeCurrent(oglSurface);
videoRenderer = OpenGL::Init() ? Config::_3DRenderer : 0; videoRenderer = OpenGL::Init() ? Config::_3DRenderer : 0;
} }
else else
#endif
{
videoRenderer = 0; videoRenderer = 0;
}
} }
else else
videoRenderer = hasOGL ? Config::_3DRenderer : 0; videoRenderer = hasOGL ? Config::_3DRenderer : 0;
videoSettingsDirty = false; videoSettingsDirty = false;
videoSettings.Soft_Threaded = Config::Threaded3D != 0; videoSettings.Soft_Threaded = Config::Threaded3D != 0;
videoSettings.GL_ScaleFactor = Config::GL_ScaleFactor; videoSettings.GL_ScaleFactor = Config::GL_ScaleFactor;
videoSettings.GL_BetterPolygons = Config::GL_BetterPolygons;
GPU::SetRenderSettings(videoRenderer, videoSettings); GPU::SetRenderSettings(videoRenderer, videoSettings);
} }
@ -924,12 +940,14 @@ void ScreenPanelGL::paintGL()
int frontbuf = GPU::FrontBuffer; int frontbuf = GPU::FrontBuffer;
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
#ifdef OGLRENDERER_ENABLED
if (GPU::Renderer != 0) if (GPU::Renderer != 0)
{ {
// hardware-accelerated render // hardware-accelerated render
GPU::GLCompositor::BindOutputTexture(); GPU::GLCompositor::BindOutputTexture();
} }
else else
#endif
{ {
// regular render // regular render
glBindTexture(GL_TEXTURE_2D, screenTexture); glBindTexture(GL_TEXTURE_2D, screenTexture);
@ -1053,6 +1071,9 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
actUndoStateLoad->setShortcut(QKeySequence(Qt::Key_F12)); actUndoStateLoad->setShortcut(QKeySequence(Qt::Key_F12));
connect(actUndoStateLoad, &QAction::triggered, this, &MainWindow::onUndoStateLoad); connect(actUndoStateLoad, &QAction::triggered, this, &MainWindow::onUndoStateLoad);
actImportSavefile = menu->addAction("Import savefile");
connect(actImportSavefile, &QAction::triggered, this, &MainWindow::onImportSavefile);
menu->addSeparator(); menu->addSeparator();
actQuit = menu->addAction("Quit"); actQuit = menu->addAction("Quit");
@ -1070,6 +1091,15 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
actStop = menu->addAction("Stop"); actStop = menu->addAction("Stop");
connect(actStop, &QAction::triggered, this, &MainWindow::onStop); connect(actStop, &QAction::triggered, this, &MainWindow::onStop);
menu->addSeparator();
actEnableCheats = menu->addAction("Enable cheats");
actEnableCheats->setCheckable(true);
connect(actEnableCheats, &QAction::triggered, this, &MainWindow::onEnableCheats);
actSetupCheats = menu->addAction("Setup cheat codes");
connect(actSetupCheats, &QAction::triggered, this, &MainWindow::onSetupCheats);
} }
{ {
QMenu* menu = menubar->addMenu("Config"); QMenu* menu = menubar->addMenu("Config");
@ -1212,11 +1242,16 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
actLoadState[i]->setEnabled(false); actLoadState[i]->setEnabled(false);
} }
actUndoStateLoad->setEnabled(false); actUndoStateLoad->setEnabled(false);
actImportSavefile->setEnabled(false);
actPause->setEnabled(false); actPause->setEnabled(false);
actReset->setEnabled(false); actReset->setEnabled(false);
actStop->setEnabled(false); actStop->setEnabled(false);
actSetupCheats->setEnabled(false);
actEnableCheats->setChecked(Config::EnableCheats != 0);
actSavestateSRAMReloc->setChecked(Config::SavestateRelocSRAM != 0); actSavestateSRAMReloc->setChecked(Config::SavestateRelocSRAM != 0);
@ -1327,7 +1362,7 @@ void MainWindow::dragEnterEvent(QDragEnterEvent* event)
QString filename = urls.at(0).toLocalFile(); QString filename = urls.at(0).toLocalFile();
QString ext = filename.right(3); QString ext = filename.right(3);
if (ext == "nds" || ext == "srl" || (ext == "gba" && RunningSomething)) if (ext == "nds" || ext == "srl" || ext == "dsi" || (ext == "gba" && RunningSomething))
event->acceptProposedAction(); event->acceptProposedAction();
} }
@ -1651,6 +1686,41 @@ void MainWindow::onUndoStateLoad()
OSD::AddMessage(0, "State load undone"); OSD::AddMessage(0, "State load undone");
} }
void MainWindow::onImportSavefile()
{
if (!RunningSomething) return;
emuThread->emuPause();
QString path = QFileDialog::getOpenFileName(this,
"Select savefile",
Config::LastROMFolder,
"Savefiles (*.sav *.bin *.dsv);;Any file (*.*)");
if (!path.isEmpty())
{
if (QMessageBox::warning(this,
"Emulation will be reset and data overwritten",
"The emulation will be reset and the current savefile overwritten.",
QMessageBox::Ok, QMessageBox::Cancel) == QMessageBox::Ok)
{
int res = Frontend::Reset();
if (res != Frontend::Load_OK)
{
QMessageBox::critical(this, "melonDS", "Reset failed\n" + loadErrorStr(res));
}
else
{
int diff = Frontend::ImportSRAM(path.toStdString().c_str());
if (diff > 0)
OSD::AddMessage(0, "Trimmed savefile");
else if (diff < 0)
OSD::AddMessage(0, "Savefile shorter than SRAM");
}
}
}
emuThread->emuUnpause();
}
void MainWindow::onQuit() void MainWindow::onQuit()
{ {
QApplication::quit(); QApplication::quit();
@ -1704,6 +1774,25 @@ void MainWindow::onStop()
NDS::Stop(); NDS::Stop();
} }
void MainWindow::onEnableCheats(bool checked)
{
Config::EnableCheats = checked?1:0;
Frontend::EnableCheats(Config::EnableCheats != 0);
}
void MainWindow::onSetupCheats()
{
emuThread->emuPause();
CheatsDialog* dlg = CheatsDialog::openDlg(this);
connect(dlg, &CheatsDialog::finished, this, &MainWindow::onCheatsDialogFinished);
}
void MainWindow::onCheatsDialogFinished(int res)
{
emuThread->emuUnpause();
}
void MainWindow::onOpenEmuSettings() void MainWindow::onOpenEmuSettings()
{ {
@ -1767,14 +1856,14 @@ void MainWindow::onAudioSettingsFinished(int res)
void MainWindow::onOpenWifiSettings() void MainWindow::onOpenWifiSettings()
{ {
emuThread->emuPause();
WifiSettingsDialog* dlg = WifiSettingsDialog::openDlg(this); WifiSettingsDialog* dlg = WifiSettingsDialog::openDlg(this);
connect(dlg, &WifiSettingsDialog::finished, this, &MainWindow::onWifiSettingsFinished); connect(dlg, &WifiSettingsDialog::finished, this, &MainWindow::onWifiSettingsFinished);
} }
void MainWindow::onWifiSettingsFinished(int res) void MainWindow::onWifiSettingsFinished(int res)
{ {
emuThread->emuPause();
if (Wifi::MPInited) if (Wifi::MPInited)
{ {
Platform::MP_DeInit(); Platform::MP_DeInit();
@ -1784,6 +1873,9 @@ void MainWindow::onWifiSettingsFinished(int res)
Platform::LAN_DeInit(); Platform::LAN_DeInit();
Platform::LAN_Init(); Platform::LAN_Init();
if (WifiSettingsDialog::needsReset)
onReset();
emuThread->emuUnpause(); emuThread->emuUnpause();
} }
@ -1892,21 +1984,51 @@ void MainWindow::onTitleUpdate(QString title)
setWindowTitle(title); setWindowTitle(title);
} }
void MainWindow::onFullscreenToggled()
{
if (!mainWindow->isFullScreen())
{
mainWindow->showFullScreen();
mainWindow->menuBar()->hide();
}
else
{
mainWindow->showNormal();
mainWindow->menuBar()->show();
}
}
void MainWindow::onEmuStart() void MainWindow::onEmuStart()
{ {
for (int i = 1; i < 9; i++) // TODO: make savestates work in DSi mode!!
if (Config::ConsoleType == 1)
{ {
actSaveState[i]->setEnabled(true); for (int i = 0; i < 9; i++)
actLoadState[i]->setEnabled(Frontend::SavestateExists(i)); {
actSaveState[i]->setEnabled(false);
actLoadState[i]->setEnabled(false);
}
actUndoStateLoad->setEnabled(false);
}
else
{
for (int i = 1; i < 9; i++)
{
actSaveState[i]->setEnabled(true);
actLoadState[i]->setEnabled(Frontend::SavestateExists(i));
}
actSaveState[0]->setEnabled(true);
actLoadState[0]->setEnabled(true);
actUndoStateLoad->setEnabled(false);
} }
actSaveState[0]->setEnabled(true);
actLoadState[0]->setEnabled(true);
actUndoStateLoad->setEnabled(false);
actPause->setEnabled(true); actPause->setEnabled(true);
actPause->setChecked(false); actPause->setChecked(false);
actReset->setEnabled(true); actReset->setEnabled(true);
actStop->setEnabled(true); actStop->setEnabled(true);
actImportSavefile->setEnabled(true);
actSetupCheats->setEnabled(true);
} }
void MainWindow::onEmuStop() void MainWindow::onEmuStop()
@ -1919,10 +2041,13 @@ void MainWindow::onEmuStop()
actLoadState[i]->setEnabled(false); actLoadState[i]->setEnabled(false);
} }
actUndoStateLoad->setEnabled(false); actUndoStateLoad->setEnabled(false);
actImportSavefile->setEnabled(false);
actPause->setEnabled(false); actPause->setEnabled(false);
actReset->setEnabled(false); actReset->setEnabled(false);
actStop->setEnabled(false); actStop->setEnabled(false);
actSetupCheats->setEnabled(false);
} }
void MainWindow::onUpdateVideoSettings(bool glchange) void MainWindow::onUpdateVideoSettings(bool glchange)
@ -2054,6 +2179,8 @@ int main(int argc, char** argv)
micWavBuffer = nullptr; micWavBuffer = nullptr;
Frontend::Init_ROM(); Frontend::Init_ROM();
Frontend::EnableCheats(Config::EnableCheats != 0);
Frontend::Init_Audio(audioFreq); Frontend::Init_Audio(audioFreq);
if (Config::MicInputType == 1) if (Config::MicInputType == 1)
@ -2080,7 +2207,7 @@ int main(int argc, char** argv)
char* file = argv[1]; char* file = argv[1];
char* ext = &file[strlen(file)-3]; char* ext = &file[strlen(file)-3];
if (!strcasecmp(ext, "nds") || !strcasecmp(ext, "srl")) if (!strcasecmp(ext, "nds") || !strcasecmp(ext, "srl") || !strcasecmp(ext, "dsi"))
{ {
int res = Frontend::LoadROM(file, Frontend::ROMSlot_NDS); int res = Frontend::LoadROM(file, Frontend::ROMSlot_NDS);
@ -2110,6 +2237,8 @@ int main(int argc, char** argv)
Input::CloseJoystick(); Input::CloseJoystick();
Frontend::DeInit_ROM();
if (audioDevice) SDL_CloseAudioDevice(audioDevice); if (audioDevice) SDL_CloseAudioDevice(audioDevice);
if (micDevice) SDL_CloseAudioDevice(micDevice); if (micDevice) SDL_CloseAudioDevice(micDevice);

View File

@ -69,6 +69,8 @@ signals:
void windowLimitFPSChange(); void windowLimitFPSChange();
void screenLayoutChange(); void screenLayoutChange();
void windowFullscreenToggle();
private: private:
volatile int EmuStatus; volatile int EmuStatus;
@ -193,11 +195,15 @@ private slots:
void onSaveState(); void onSaveState();
void onLoadState(); void onLoadState();
void onUndoStateLoad(); void onUndoStateLoad();
void onImportSavefile();
void onQuit(); void onQuit();
void onPause(bool checked); void onPause(bool checked);
void onReset(); void onReset();
void onStop(); void onStop();
void onEnableCheats(bool checked);
void onSetupCheats();
void onCheatsDialogFinished(int res);
void onOpenEmuSettings(); void onOpenEmuSettings();
void onEmuSettingsDialogFinished(int res); void onEmuSettingsDialogFinished(int res);
@ -226,6 +232,8 @@ private slots:
void onEmuStop(); void onEmuStop();
void onUpdateVideoSettings(bool glchange); void onUpdateVideoSettings(bool glchange);
void onFullscreenToggled();
private: private:
void createScreenPanel(); void createScreenPanel();
@ -240,11 +248,14 @@ public:
QAction* actSaveState[9]; QAction* actSaveState[9];
QAction* actLoadState[9]; QAction* actLoadState[9];
QAction* actUndoStateLoad; QAction* actUndoStateLoad;
QAction* actImportSavefile;
QAction* actQuit; QAction* actQuit;
QAction* actPause; QAction* actPause;
QAction* actReset; QAction* actReset;
QAction* actStop; QAction* actStop;
QAction* actEnableCheats;
QAction* actSetupCheats;
QAction* actEmuSettings; QAction* actEmuSettings;
QAction* actInputConfig; QAction* actInputConfig;

54
src/melonDLDI.h Normal file
View File

@ -0,0 +1,54 @@
/*
Copyright 2016-2020 Arisotura
This file is part of melonDS.
melonDS is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option)
any later version.
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with melonDS. If not, see http://www.gnu.org/licenses/.
*/
#ifndef MELONDLDI_H
#define MELONDLDI_H
const u8 melonDLDI[] =
{
0xED, 0xA5, 0x8D, 0xBF, 0x20, 0x43, 0x68, 0x69, 0x73, 0x68, 0x6D, 0x00, 0x01, 0x01, 0x00, 0x00,
0x6D, 0x65, 0x6C, 0x6F, 0x6E, 0x44, 0x53, 0x20, 0x44, 0x4C, 0x44, 0x49, 0x20, 0x64, 0x72, 0x69,
0x76, 0x65, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0xBF, 0xC0, 0x01, 0x80, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x4D, 0x45, 0x4C, 0x4E, 0x23, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0xBF, 0x88, 0x00, 0x80, 0xBF,
0x30, 0x01, 0x80, 0xBF, 0x70, 0x01, 0x80, 0xBF, 0xB0, 0x01, 0x80, 0xBF, 0xB8, 0x01, 0x80, 0xBF,
0x01, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1, 0x01, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1,
0x01, 0xC3, 0xA0, 0xE3, 0x1A, 0xCE, 0x8C, 0xE2, 0x02, 0x39, 0xA0, 0xE3, 0xB0, 0x30, 0xCC, 0xE1,
0x08, 0x00, 0xCC, 0xE5, 0x0C, 0x10, 0xCC, 0xE5, 0x21, 0x14, 0xA0, 0xE1, 0x0B, 0x10, 0xCC, 0xE5,
0x21, 0x14, 0xA0, 0xE1, 0x0A, 0x10, 0xCC, 0xE5, 0x21, 0x14, 0xA0, 0xE1, 0x09, 0x10, 0xCC, 0xE5,
0x21, 0x14, 0xA0, 0xE1, 0x0D, 0x10, 0xCC, 0xE5, 0xBE, 0x10, 0xCC, 0xE1, 0x03, 0x31, 0xA0, 0xE3,
0x00, 0x00, 0x52, 0xE3, 0x01, 0x34, 0x83, 0x13, 0x01, 0x35, 0x83, 0xE3, 0x04, 0x30, 0x8C, 0xE5,
0x41, 0x36, 0xA0, 0xE3, 0x01, 0x00, 0x10, 0xE3, 0x07, 0x00, 0x00, 0x1A, 0x04, 0x00, 0x9C, 0xE5,
0x02, 0x05, 0x10, 0xE3, 0x10, 0x10, 0x93, 0x15, 0x00, 0x00, 0x52, 0x13, 0x04, 0x10, 0x82, 0x14,
0x02, 0x01, 0x10, 0xE3, 0xF8, 0xFF, 0xFF, 0x1A, 0x1E, 0xFF, 0x2F, 0xE1, 0x00, 0x10, 0xA0, 0xE3,
0x04, 0x00, 0x9C, 0xE5, 0x02, 0x05, 0x10, 0xE3, 0x00, 0x00, 0x52, 0x13, 0x04, 0x10, 0x92, 0x14,
0x10, 0x10, 0x83, 0x15, 0x02, 0x01, 0x10, 0xE3, 0xF8, 0xFF, 0xFF, 0x1A, 0x1E, 0xFF, 0x2F, 0xE1,
0x03, 0x00, 0x12, 0xE3, 0x00, 0x00, 0xA0, 0x13, 0x1E, 0xFF, 0x2F, 0x11, 0x78, 0x40, 0x2D, 0xE9,
0x00, 0x40, 0xA0, 0xE1, 0x01, 0x50, 0xA0, 0xE1, 0x00, 0x60, 0xA0, 0xE3, 0xC0, 0x00, 0xA0, 0xE3,
0x06, 0x10, 0x84, 0xE0, 0xCD, 0xFF, 0xFF, 0xEB, 0x01, 0x60, 0x86, 0xE2, 0x05, 0x00, 0x56, 0xE1,
0xF9, 0xFF, 0xFF, 0x3A, 0x78, 0x40, 0xBD, 0xE8, 0x01, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1,
0x03, 0x00, 0x12, 0xE3, 0x00, 0x00, 0xA0, 0x13, 0x1E, 0xFF, 0x2F, 0x11, 0x78, 0x40, 0x2D, 0xE9,
0x00, 0x40, 0xA0, 0xE1, 0x01, 0x50, 0xA0, 0xE1, 0x00, 0x60, 0xA0, 0xE3, 0xC1, 0x00, 0xA0, 0xE3,
0x06, 0x10, 0x84, 0xE0, 0xBD, 0xFF, 0xFF, 0xEB, 0x01, 0x60, 0x86, 0xE2, 0x05, 0x00, 0x56, 0xE1,
0xF9, 0xFF, 0xFF, 0x3A, 0x78, 0x40, 0xBD, 0xE8, 0x01, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1,
0x01, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1, 0x01, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1,
};
#endif // MELONDLDI_H

View File

@ -19,13 +19,15 @@
#ifndef TYPES_H #ifndef TYPES_H
#define TYPES_H #define TYPES_H
typedef unsigned char u8; #include <stdint.h>
typedef unsigned short u16;
typedef unsigned int u32; typedef uint8_t u8;
typedef unsigned long long int u64; typedef uint16_t u16;
typedef signed char s8; typedef uint32_t u32;
typedef signed short s16; typedef uint64_t u64;
typedef signed int s32; typedef int8_t s8;
typedef signed long long int s64; typedef int16_t s16;
typedef int32_t s32;
typedef int64_t s64;
#endif // TYPES_H #endif // TYPES_H

View File

@ -19,7 +19,7 @@
#ifndef VERSION_H #ifndef VERSION_H
#define VERSION_H #define VERSION_H
#define MELONDS_VERSION "0.8.3-JIT" #define MELONDS_VERSION "0.9"
#define MELONDS_URL "http://melonds.kuribo64.net/" #define MELONDS_URL "http://melonds.kuribo64.net/"