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
shell: bash
working-directory: ${{runner.workspace}}
run: |
run: | #Fix grub installation error - https://github.com/actions/virtual-environments/issues/1605
sudo apt update
sudo apt-get install grub-efi
sudo update-grub
sudo apt full-upgrade
- name: Install dependencies
shell: bash
@ -32,7 +34,8 @@ jobs:
sudo rm /etc/apt/sources.list
sudo mv /etc/apt/sources.list{.new,}
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
run: mkdir ${{runner.workspace}}/build
- name: Configure

View File

@ -24,8 +24,8 @@ jobs:
working-directory: ${{runner.workspace}}
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 apt-get update \
&& sudo apt-get install cmake libcurl4-gnutls-dev libpcap0.8-dev libsdl2-dev qt5-default libslirp-dev libzip-dev
&& sudo apt update \
&& 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
run: mkdir ${{runner.workspace}}/build
- name: Configure

View File

@ -36,9 +36,8 @@ jobs:
- name: Make
run: |
C:\tools\msys64\usr\bin\bash.exe -lc "export PATH=`"/mingw64/bin:`$PATH`" \
&& cd melonDS/build && make -j$(nproc --all) \
&& ../msys-dist.sh"
&& cd melonDS/build && make -j$(nproc --all)"
- uses: actions/upload-artifact@v1
with:
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)
endif()
option(ENABLE_OGLRENDERER "Enable OpenGL renderer" ON)
if (ENABLE_OGLRENDERER)
add_definitions(-DOGLRENDERER_ENABLED)
endif()
if (CMAKE_BUILD_TYPE STREQUAL Debug)
add_compile_options(-Og)
endif()

View File

@ -2,7 +2,7 @@
<h2 align="center"><b>melonDS</b></h2>
<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/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://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>
@ -38,7 +38,7 @@ As for the rest, the interface should be pretty straightforward. If you have a q
* Install dependencies:
```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:
@ -55,7 +55,23 @@ make -j$(nproc --all)
1. Install [MSYS2](https://www.msys2.org/)
2. Open the **MSYS2 MinGW 64-bit** terminal
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
```bash
git clone https://github.com/Arisotura/melonDS.git
@ -64,10 +80,9 @@ make -j$(nproc --all)
cd build
cmake .. -G 'MSYS Makefiles' -DBUILD_STATIC=ON -DQT5_STATIC_DIR=/mingw64/qt5-static
make -j$(nproc --all)
../msys-dist.sh
mkdir dist && cp melonDS.exe dist
```
If everything went well, melonDS and the libraries it needs should now be in the `dist` folder.
If everything went well, melonDS should now be in the `dist` folder.
## 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
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.
(at your option) any later version.

View File

@ -6,8 +6,8 @@
//include version information in .exe, modify these values to match your needs
1 VERSIONINFO
FILEVERSION 0,8,3,0
PRODUCTVERSION 0,8,3,0
FILEVERSION 0,9,0,0
PRODUCTVERSION 0,9,0,0
FILETYPE VFT_APP
{
BLOCK "StringFileInfo"
@ -15,14 +15,14 @@ FILETYPE VFT_APP
BLOCK "040904E4"
{
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 "InternalName", "SDnolem"
VALUE "LegalCopyright", "2016-2020 Arisotura & co."
VALUE "LegalTrademarks", ""
VALUE "OriginalFilename", "zafkflzdasd.exe"
VALUE "ProductName", "melonDS"
VALUE "ProductVersion", "0.8.3"
VALUE "ProductVersion", "0.9"
}
}
BLOCK "VarFileInfo"

View File

@ -11,4 +11,5 @@ for lib in $(ldd melonDS.exe | grep mingw | sed "s/.*=> //" | sed "s/(.*)//"); d
cp "${lib}" dist
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/.
*/
#ifndef ARCODELIST_H
#define ARCODELIST_H
#ifndef ARCODEFILE_H
#define ARCODEFILE_H
#include <list>
#include "types.h"
#define ARCL_MAJOR 1
#define ARCL_MINOR 1
typedef struct
{
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:
//
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 <string.h>
#include "NDS.h"
#include "DSi.h"
#include "AREngine.h"
namespace AREngine
{
typedef struct
{
u32 Code[2 * 64]; // TODO: more sensible size for this? allocate on demand?
bool Enabled;
// AR code file - frontend is responsible for managing this
ARCodeFile* CodeFile;
} CheatEntry;
// TODO: more sensible size for this? allocate on demand?
CheatEntry CheatCodes[64];
u32 NumCheatCodes;
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;
}
}
u8 (*BusRead8)(u32 addr);
u16 (*BusRead16)(u32 addr);
u32 (*BusRead32)(u32 addr);
void (*BusWrite8)(u32 addr, u8 val);
void (*BusWrite16)(u32 addr, u16 val);
void (*BusWrite32)(u32 addr, u32 val);
bool Init()
{
CodeFile = nullptr;
return true;
}
void DeInit()
{
//
}
void Reset()
{
memset(CheatCodes, 0, sizeof(CheatCodes));
NumCheatCodes = 0;
CodeFile = nullptr;
// TODO: acquire codes from a sensible source!
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)
if (NDS::ConsoleType == 1)
{
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;
NumCheatCodes++;*/
else
{
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)+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 datareg = 0;
@ -166,9 +104,11 @@ void RunCheat(CheatEntry* entry)
for (;;)
{
if (code >= &arcode.Code[arcode.CodeLen])
break;
u32 a = *code++;
u32 b = *code++;
if ((a|b) == 0) break;
u8 op = a >> 24;
@ -179,7 +119,7 @@ void RunCheat(CheatEntry* entry)
if ((op & 0xF0) == 0xE0)
{
for (u32 i = 0; i < b; i += 8)
*code += 2;
code += 2;
}
continue;
@ -189,15 +129,15 @@ void RunCheat(CheatEntry* entry)
switch (op)
{
case16(0x00): // 32-bit write
NDS::ARM7Write32((a & 0x0FFFFFFF) + offset, b);
BusWrite32((a & 0x0FFFFFFF) + offset, b);
break;
case16(0x10): // 16-bit write
NDS::ARM7Write16((a & 0x0FFFFFFF) + offset, b & 0xFFFF);
BusWrite16((a & 0x0FFFFFFF) + offset, b & 0xFFFF);
break;
case16(0x20): // 8-bit write
NDS::ARM7Write8((a & 0x0FFFFFFF) + offset, b & 0xFF);
BusWrite8((a & 0x0FFFFFFF) + offset, b & 0xFF);
break;
case16(0x30): // IF b > u32[a]
@ -205,7 +145,7 @@ void RunCheat(CheatEntry* entry)
condstack <<= 1;
condstack |= cond;
u32 chk = NDS::ARM7Read32(a & 0x0FFFFFFF);
u32 chk = BusRead32(a & 0x0FFFFFFF);
cond = (b > chk) ? 1:0;
}
@ -216,7 +156,7 @@ void RunCheat(CheatEntry* entry)
condstack <<= 1;
condstack |= cond;
u32 chk = NDS::ARM7Read32(a & 0x0FFFFFFF);
u32 chk = BusRead32(a & 0x0FFFFFFF);
cond = (b < chk) ? 1:0;
}
@ -227,7 +167,7 @@ void RunCheat(CheatEntry* entry)
condstack <<= 1;
condstack |= cond;
u32 chk = NDS::ARM7Read32(a & 0x0FFFFFFF);
u32 chk = BusRead32(a & 0x0FFFFFFF);
cond = (b == chk) ? 1:0;
}
@ -238,7 +178,7 @@ void RunCheat(CheatEntry* entry)
condstack <<= 1;
condstack |= cond;
u32 chk = NDS::ARM7Read32(a & 0x0FFFFFFF);
u32 chk = BusRead32(a & 0x0FFFFFFF);
cond = (b != chk) ? 1:0;
}
@ -249,7 +189,7 @@ void RunCheat(CheatEntry* entry)
condstack <<= 1;
condstack |= cond;
u16 val = NDS::ARM7Read16(a & 0x0FFFFFFF);
u16 val = BusRead16(a & 0x0FFFFFFF);
u16 chk = ~(b >> 16);
chk &= val;
@ -262,7 +202,7 @@ void RunCheat(CheatEntry* entry)
condstack <<= 1;
condstack |= cond;
u16 val = NDS::ARM7Read16(a & 0x0FFFFFFF);
u16 val = BusRead16(a & 0x0FFFFFFF);
u16 chk = ~(b >> 16);
chk &= val;
@ -275,7 +215,7 @@ void RunCheat(CheatEntry* entry)
condstack <<= 1;
condstack |= cond;
u16 val = NDS::ARM7Read16(a & 0x0FFFFFFF);
u16 val = BusRead16(a & 0x0FFFFFFF);
u16 chk = ~(b >> 16);
chk &= val;
@ -288,7 +228,7 @@ void RunCheat(CheatEntry* entry)
condstack <<= 1;
condstack |= cond;
u16 val = NDS::ARM7Read16(a & 0x0FFFFFFF);
u16 val = BusRead16(a & 0x0FFFFFFF);
u16 chk = ~(b >> 16);
chk &= val;
@ -297,7 +237,7 @@ void RunCheat(CheatEntry* entry)
break;
case16(0xB0): // offset = u32[a + offset]
offset = NDS::ARM7Read32((a & 0x0FFFFFFF) + offset);
offset = BusRead32((a & 0x0FFFFFFF) + offset);
break;
case 0xC0: // FOR 0..b
@ -334,7 +274,7 @@ void RunCheat(CheatEntry* entry)
break;
case 0xC6: // u32[b] = offset
NDS::ARM7Write32(b, offset);
BusWrite32(b, offset);
break;
case 0xD0: // ENDIF
@ -383,30 +323,30 @@ void RunCheat(CheatEntry* entry)
break;
case 0xD6: // u32[b+offset] = datareg / offset += 4
NDS::ARM7Write32(b + offset, datareg);
BusWrite32(b + offset, datareg);
offset += 4;
break;
case 0xD7: // u16[b+offset] = datareg / offset += 2
NDS::ARM7Write16(b + offset, datareg & 0xFFFF);
BusWrite16(b + offset, datareg & 0xFFFF);
offset += 2;
break;
case 0xD8: // u8[b+offset] = datareg / offset += 1
NDS::ARM7Write8(b + offset, datareg & 0xFF);
BusWrite8(b + offset, datareg & 0xFF);
offset += 1;
break;
case 0xD9: // datareg = u32[b+offset]
datareg = NDS::ARM7Read32(b + offset);
datareg = BusRead32(b + offset);
break;
case 0xDA: // datareg = u16[b+offset]
datareg = NDS::ARM7Read16(b + offset);
datareg = BusRead16(b + offset);
break;
case 0xDB: // datareg = u8[b+offset]
datareg = NDS::ARM7Read8(b + offset);
datareg = BusRead8(b + offset);
break;
case 0xDC: // offset += b
@ -421,23 +361,23 @@ void RunCheat(CheatEntry* entry)
u32 bytesleft = b;
while (bytesleft >= 8)
{
NDS::ARM7Write32(dstaddr, *code++); dstaddr += 4;
NDS::ARM7Write32(dstaddr, *code++); dstaddr += 4;
BusWrite32(dstaddr, *code++); dstaddr += 4;
BusWrite32(dstaddr, *code++); dstaddr += 4;
bytesleft -= 8;
}
if (bytesleft > 0)
{
u8* leftover = (u8*)code;
*code += 2;
code += 2;
if (bytesleft >= 4)
{
NDS::ARM7Write32(dstaddr, *(u32*)leftover); dstaddr += 4;
BusWrite32(dstaddr, *(u32*)leftover); dstaddr += 4;
leftover += 4;
bytesleft -= 4;
}
while (bytesleft > 0)
{
NDS::ARM7Write8(dstaddr, *leftover++); dstaddr++;
BusWrite8(dstaddr, *leftover++); dstaddr++;
bytesleft--;
}
}
@ -453,14 +393,14 @@ void RunCheat(CheatEntry* entry)
u32 bytesleft = b;
while (bytesleft >= 4)
{
NDS::ARM7Write32(dstaddr, NDS::ARM7Read32(srcaddr));
BusWrite32(dstaddr, BusRead32(srcaddr));
srcaddr += 4;
dstaddr += 4;
bytesleft -= 4;
}
while (bytesleft > 0)
{
NDS::ARM7Write8(dstaddr, NDS::ARM7Read8(srcaddr));
BusWrite8(dstaddr, BusRead8(srcaddr));
srcaddr++;
dstaddr++;
bytesleft--;
@ -477,13 +417,19 @@ void RunCheat(CheatEntry* entry)
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];
if (entry->Enabled)
RunCheat(entry);
ARCodeCat& cat = *i;
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
#define ARENGINE_H
#include "ARCodeFile.h"
namespace AREngine
{
@ -26,6 +28,8 @@ bool Init();
void DeInit();
void Reset();
void SetCodeFile(ARCodeFile* file);
void RunCheats();
}

View File

@ -24,7 +24,10 @@
#include "types.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
{

View File

@ -38,6 +38,14 @@ namespace ARMJIT
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 CodeIndexMainRAM[NDS::MainRAMMaxSize / 512];
AddressRange CodeIndexSWRAM[NDS::SharedWRAMSize / 512];
@ -52,9 +60,6 @@ AddressRange CodeIndexNWRAM_A[DSi::NWRAMSize / 512];
AddressRange CodeIndexNWRAM_B[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 FastBlockLookupMainRAM[NDS::MainRAMMaxSize / 2];
u64 FastBlockLookupSWRAM[NDS::SharedWRAMSize / 2];
@ -146,8 +151,6 @@ u32 LocaliseCodeAddress(u32 num, u32 addr)
return 0;
}
TinyVector<u32> InvalidLiterals;
template <typename T, int ConsoleType>
T SlowRead9(u32 addr, ARMv5* cpu)
{
@ -286,97 +289,6 @@ void SlowBlockTransfer7(u32 addr, u64* data, u32 num)
INSTANTIATE_SLOWMEM(0)
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()
{
JITCompiler = new Compiler();
@ -568,7 +480,7 @@ InterpreterFunc InterpretARM[ARMInstrInfo::ak_Count] =
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(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(STRB),
@ -622,6 +534,20 @@ InterpreterFunc InterpretTHUMB[ARMInstrInfo::tk_Count] =
};
#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)
{
bool thumb = cpu->CPSR & 0x20;
@ -659,10 +585,7 @@ void CompileBlock(ARM* cpu)
}
// some memory has been remapped
JitBlock* prevBlock = RestoreCandidates.Insert(existingBlockIt->second->InstrHash, existingBlockIt->second);
if (prevBlock)
delete prevBlock;
RetireJitBlock(existingBlockIt->second);
map.erase(existingBlockIt);
}
@ -906,11 +829,13 @@ void CompileBlock(ARM* cpu)
u32 literalHash = (u32)XXH3_64bits(literalValues, numLiterals * 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;
if (prevBlock)
if (prevBlockIt != RestoreCandidates.end())
{
RestoreCandidates.Remove(instrHash);
prevBlock = prevBlockIt->second;
RestoreCandidates.erase(prevBlockIt);
mayRestore = prevBlock->StartAddr == blockAddr && prevBlock->LiteralHash == literalHash;
@ -932,7 +857,6 @@ void CompileBlock(ARM* cpu)
else
{
mayRestore = false;
prevBlock = NULL;
}
JitBlock* block;
@ -1078,9 +1002,7 @@ void InvalidateByAddr(u32 localAddr)
if (!literalInvalidation)
{
JitBlock* prevBlock = RestoreCandidates.Insert(block->InstrHash, block);
if (prevBlock)
delete prevBlock;
RetireJitBlock(block);
}
else
{
@ -1165,21 +1087,13 @@ void ResetBlockCache()
InvalidLiterals.Clear();
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)
{
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;
}
if (FastBlockLookupRegions[i])
memset(FastBlockLookupRegions[i], 0xFF, CodeRegionSizes[i] * sizeof(u64) / 2);
}
for (auto it = RestoreCandidates.begin(); it != RestoreCandidates.end(); it++)
delete it->second;
RestoreCandidates.clear();
for (auto it : JitBlocks9)
{
JitBlock* block = it.second;

View File

@ -436,7 +436,7 @@ void Compiler::A_Comp_GetOp2(bool S, Op2& op2)
Comp_AddCycles_C();
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))
{
@ -447,7 +447,7 @@ void Compiler::A_Comp_GetOp2(bool S, Op2& op2)
ANDI2R(RCPSR, RCPSR, ~(1 << 29));
}
op2 = Op2(ROR(CurInstr.Instr & 0xFF, (CurInstr.Instr >> 7) & 0x1E));
op2 = Op2(imm);
}
else
{
@ -523,7 +523,7 @@ void Compiler::A_Comp_ALUMovOp()
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_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

View File

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

View File

@ -1,5 +1,5 @@
#ifndef ARMJIT_COMPILER_H
#define ARMJIT_COMPILER_H
#ifndef ARMJIT_A64_COMPILER_H
#define ARMJIT_A64_COMPILER_H
#include "../ARM.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;
}
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)
@ -65,7 +65,7 @@ bool Compiler::Comp_MemLoadLiteral(int size, bool signExtend, int rd, u32 addr)
if (size == 32)
{
CurCPU->DataRead32(addr & ~0x3, &val);
val = ROR(val, (addr & 0x3) << 3);
val = ::ROR(val, (addr & 0x3) << 3);
}
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)
{
ROR_(W0, offset.Reg.Rm, offset.Reg.ShiftAmount);
ROR(W0, offset.Reg.Rm, offset.Reg.ShiftAmount);
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 (staticAddress & 0x3)
ROR_(rdMapped, W0, (staticAddress & 0x3) << 3);
ROR(rdMapped, W0, (staticAddress & 0x3) << 3);
else
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__)
#include "ARMJIT_x64/ARMJIT_Compiler.h"
#elif defined(__aarch64__)
@ -9,4 +12,6 @@
namespace ARMJIT
{
extern Compiler* JITCompiler;
}
}
#endif

View File

@ -279,6 +279,7 @@ bool UnmapFromRange(u32 addr, u32 num, u32 offset, u32 size)
#endif
}
#ifndef __SWITCH__
void SetCodeProtectionRange(u32 addr, u32 size, u32 num, int protection)
{
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);
#endif
}
#endif
struct Mapping
{
@ -524,8 +526,8 @@ bool MapAtAddress(u32 addr)
{
u32 sectionOffset = offset;
bool hasCode = isExecutable && ARMJIT::PageContainsCode(&range[offset / 512]);
while ((!isExecutable || ARMJIT::PageContainsCode(&range[offset / 512]) == hasCode)
&& offset < mirrorSize
while (offset < mirrorSize
&& (!isExecutable || ARMJIT::PageContainsCode(&range[offset / 512]) == hasCode)
&& (!skipDTCM || mirrorStart + offset != NDS::ARM9->DTCMBase))
{
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;
mirrorSize = 0x100000;
return true;
}
return false;
case memregion_VWRAM:
@ -1007,7 +1010,7 @@ void WifiWrite32(u32 addr, u32 val)
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>

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)

View File

@ -110,7 +110,7 @@ OpArg Compiler::A_Comp_GetALUOp2(bool S, bool& carryUsed)
Comp_AddCycles_C();
u32 shift = (CurInstr.Instr >> 7) & 0x1E;
u32 imm = ROR(CurInstr.Instr & 0xFF, shift);
u32 imm = ::ROR(CurInstr.Instr & 0xFF, shift);
carryUsed = false;
if (S && shift)
@ -209,7 +209,8 @@ void Compiler::A_Comp_Arith()
Comp_ArithTriOp(&Compiler::AND, rd, rn, op2, carryUsed, sFlag|opSymmetric|opInvertOp2);
break;
default:
assert("unimplemented");
printf("this is a JIT bug! %04x\n", op);
abort();
}
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)
BT(32, R(RSCRATCH), Imm8(31));
ROR_(32, R(RSCRATCH), R(ECX));
ROR(32, R(RSCRATCH), R(ECX));
if (S)
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
MOV(32, R(RSCRATCH), rm);
if (amount > 0)
ROR_(32, R(RSCRATCH), Imm8(amount));
ROR(32, R(RSCRATCH), Imm8(amount));
else
{
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);
}
assert(false);
abort();
}
void Compiler::T_Comp_ShiftImm()
@ -779,4 +780,4 @@ void Compiler::T_Comp_RelAddr()
MOV(32, rd, Imm32((R15 & ~2) + offset));
}
}
}

View File

@ -106,7 +106,7 @@ void Compiler::A_Comp_MSR()
Comp_AddCycles_C();
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));
u32 mask = 0;

View File

@ -1,5 +1,5 @@
#ifndef ARMJIT_COMPILER_H
#define ARMJIT_COMPILER_H
#ifndef ARMJIT_X64_COMPILER_H
#define ARMJIT_X64_COMPILER_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;
}
printf("this is a JIT bug %x\n", pc);
printf("this is a JIT bug %llx\n", pc);
abort();
}
@ -73,7 +73,7 @@ bool Compiler::Comp_MemLoadLiteral(int size, bool signExtend, int rd, u32 addr)
if (size == 32)
{
CurCPU->DataRead32(addr & ~0x3, &val);
val = ROR(val, (addr & 0x3) << 3);
val = ::ROR(val, (addr & 0x3) << 3);
}
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 (staticAddress & 0x3)
ROR_(32, rdMapped, Imm8((staticAddress & 0x3) * 8));
ROR(32, rdMapped, Imm8((staticAddress & 0x3) * 8));
}
else
{
AND(32, R(RSCRATCH3), Imm8(0x3));
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));
if (staticAddress & 0x3)
ROR_(32, rdMapped, Imm8((staticAddress & 0x3) * 8));
ROR(32, rdMapped, Imm8((staticAddress & 0x3) * 8));
}
else
{
@ -819,4 +819,4 @@ void Compiler::T_Comp_LDMIA_STMIA()
ADD(32, rb, Imm8(offset));
}
}
}

View File

@ -3,7 +3,7 @@ project(core)
set (CMAKE_CXX_STANDARD 14)
add_library(core STATIC
ARCodeList.cpp
ARCodeFile.cpp
AREngine.cpp
ARM.cpp
ARM_InstrTable.h
@ -26,16 +26,12 @@ add_library(core STATIC
FIFO.h
GBACart.cpp
GPU.cpp
GPU_OpenGL.cpp
GPU_OpenGL_shaders.h
GPU2D.cpp
GPU3D.cpp
GPU3D_OpenGL.cpp
GPU3D_OpenGL_shaders.h
GPU3D_Soft.cpp
melonDLDI.h
NDS.cpp
NDSCart.cpp
OpenGLSupport.cpp
Platform.h
ROMList.h
RTC.cpp
@ -51,6 +47,16 @@ add_library(core STATIC
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)
enable_language(ASM)
@ -94,9 +100,16 @@ if (ENABLE_JIT)
endif()
endif()
if (WIN32)
target_link_libraries(core ole32 comctl32 ws2_32 opengl32)
if (ENABLE_OGLRENDERER)
if (WIN32)
target_link_libraries(core ole32 comctl32 ws2_32 opengl32)
else()
target_link_libraries(core GL EGL)
endif()
else()
target_link_libraries(core GL EGL)
endif()
if (WIN32)
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:
//printf("cache debug index register %08X\n", val);
return;
case 0xF10:
//printf("cache debug instruction tag %08X\n", val);
return;
case 0xF20:
//printf("cache debug data tag %08X\n", val);
return;
@ -632,7 +632,7 @@ void ARMv5::CP15Write(u32 id, u32 val)
case 0xF40:
//printf("cache debug data cache %08X\n", val);
return;
}
if ((id & 0xF00) == 0xF00) // test/debug shit?

View File

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

View File

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

View File

@ -73,6 +73,8 @@ void DMA::Reset()
SrcAddrInc = 0;
DstAddrInc = 0;
Stall = false;
Running = false;
InProgress = false;
@ -111,8 +113,8 @@ void DMA::DoSavestate(Savestate* file)
file->Var32(&DstAddrInc);
file->Var32(&Running);
file->Var32((u32*)&InProgress);
file->Var32((u32*)&IsGXFIFODMA);
file->Bool32(&InProgress);
file->Bool32(&IsGXFIFODMA);
}
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)
{
SCFG_Clock9 = val & 0x0187;
return;
NDS::ARM9Timestamp >>= NDS::ARM9ClockShift;
NDS::ARM9Target >>= NDS::ARM9ClockShift;
printf("CLOCK9=%04X\n", val);
SCFG_Clock9 = val & 0x0187;
if (SCFG_Clock9 & (1<<0)) NDS::ARM9ClockShift = 2;
else NDS::ARM9ClockShift = 1;
NDS::ARM9Timestamp <<= NDS::ARM9ClockShift;
NDS::ARM9Target <<= NDS::ARM9ClockShift;
NDS::ARM9->UpdateRegionTimings(0x00000000, 0xFFFFFFFF);
}
@ -895,6 +912,20 @@ void ARM9Write8(u32 addr, u8 val)
case 0x04000000:
ARM9IOWrite8(addr, val);
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);
@ -1549,25 +1580,37 @@ void ARM9IOWrite32(u32 addr, u32 val)
switch (addr)
{
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:
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;
}*/
printf("from %08X, ARM7 %08X, %08X\n", NDS::GetPC(0), NDS::GetPC(1), NDS::ARM7->R[1]);
u32 oldram = (SCFG_EXT[0] >> 14) & 0x3;
u32 newram = (val >> 14) & 0x3;
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:
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;
case 0x04004040:
@ -1660,7 +1703,7 @@ u8 ARM7IORead8(u32 addr)
case 0x04004501: return DSi_I2C::Cnt;
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 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;

View File

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

View File

@ -140,7 +140,7 @@ u16 DSi_Camera::ReadReg(u16 addr)
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;
}
@ -162,5 +162,5 @@ void DSi_Camera::WriteReg(u16 addr, u16 val)
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",
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);
*(u32*)&EEPROM[0x000] = 0x300;
@ -755,8 +785,7 @@ void DSi_NWifi::BMI_Command()
case 0x08: // BMI_GET_TARGET_ID
MB_Write32(4, 0xFFFFFFFF);
MB_Write32(4, 0x0000000C);
//MB_Write32(4, 0x20000118);
MB_Write32(4, 0x23000024); // ROM version (TODO: how to determine correct one?)
MB_Write32(4, ROMID);
MB_Write32(4, 0x00000002);
return;
@ -1436,7 +1465,7 @@ u32 DSi_NWifi::WindowRead(u32 addr)
{
printf("NWifi: window read %08X\n", addr);
if ((addr & 0xFFFF00) == 0x520000)
if ((addr & 0xFFFF00) == HostIntAddr)
{
// RAM host interest area
// TODO: different base based on hardware version
@ -1462,9 +1491,7 @@ u32 DSi_NWifi::WindowRead(u32 addr)
switch (addr)
{
case 0x40EC: // chip ID
// 0D000000 / 0D000001 == AR6013
// TODO: check firmware.bin to determine the correct value
return 0x0D000001;
return ChipID;
// SOC_RESET_CAUSE
case 0x40C0: return 2;

View File

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

View File

@ -117,13 +117,19 @@ void DSi_SDHost::Reset()
if (Num == 0)
{
// TODO: eventually pull from host filesystem
/*DSi_MMCStorage* sd = new DSi_MMCStorage(this, false, "sd.bin");
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* sd;
DSi_MMCStorage* mmc;
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);
Ports[0] = sd;
@ -429,14 +435,14 @@ u16 DSi_SDHost::Read(u32 addr)
if (!Num)
{
if (Ports[0]) // basic check of whether the SD card is inserted
ret |= 0x0030;
ret |= 0x00B0;
else
ret |= 0x0008;
}
else
{
// SDIO wifi is always inserted, I guess
ret |= 0x0030;
ret |= 0x00B0;
}
return ret;
}

View File

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

View File

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

View File

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

View File

@ -35,9 +35,6 @@
// * [Gericom] bit15 is used as bottom green bit for palettes. TODO: check where this applies.
// 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
//
// FIFO display mode:
@ -78,7 +75,10 @@
// * for rotscaled sprites: coordinates that are inside the sprite are clamped to the sprite region
// 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)
@ -102,6 +102,7 @@ GPU2D::~GPU2D()
void GPU2D::Reset()
{
Enabled = false;
DispCnt = 0;
memset(BGCnt, 0, 4*2);
memset(BGXPos, 0, 4*2);
@ -309,8 +310,6 @@ u32 GPU2D::Read32(u32 addr)
void GPU2D::Write8(u32 addr, u8 val)
{
if (!Enabled) return;
switch (addr & 0x00000FFF)
{
case 0x000:
@ -329,7 +328,12 @@ void GPU2D::Write8(u32 addr, u8 val)
DispCnt = (DispCnt & 0x00FFFFFF) | (val << 24);
if (Num) DispCnt &= 0xC0B1FFF7;
return;
}
if (!Enabled) return;
switch (addr & 0x00000FFF)
{
case 0x008: BGCnt[0] = (BGCnt[0] & 0xFF00) | val; return;
case 0x009: BGCnt[0] = (BGCnt[0] & 0x00FF) | (val << 8); 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)
{
if (!Enabled) return;
switch (addr & 0x00000FFF)
{
case 0x000:
@ -418,6 +420,22 @@ void GPU2D::Write16(u32 addr, u16 val)
if (Num) DispCnt &= 0xC0B1FFF7;
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 0x00A: BGCnt[1] = val; return;
case 0x00C: BGCnt[2] = val; return;
@ -526,17 +544,6 @@ void GPU2D::Write16(u32 addr, u16 val)
EVY = val & 0x1F;
if (EVY > 16) EVY = 16;
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);
@ -544,8 +551,6 @@ void GPU2D::Write16(u32 addr, u16 val)
void GPU2D::Write32(u32 addr, u32 val)
{
if (!Enabled) return;
switch (addr & 0x00000FFF)
{
case 0x000:
@ -553,6 +558,24 @@ void GPU2D::Write32(u32 addr, u32 val)
if (Num) DispCnt &= 0xC0B1FFF7;
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:
if (val & 0x08000000) val |= 0xF0000000;
BGXRef[0] = val;
@ -574,19 +597,6 @@ void GPU2D::Write32(u32 addr, u32 val)
BGYRef[1] = val;
if (GPU::VCount < 192) BGYRefInternal[1] = BGYRef[1];
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);
@ -805,7 +815,6 @@ void GPU2D::DrawScanline(u32 line)
int i = 0;
for (; i < (stride & ~1); i+=2)
*(u64*)&dst[i] = *(u64*)&BGOBJLine[i];
if (stride & 1) dst[i] = BGOBJLine[i];
}
break;
@ -940,6 +949,7 @@ void GPU2D::VBlankEnd()
//OBJMosaicY = 0;
//OBJMosaicYCount = 0;
#ifdef OGLRENDERER_ENABLED
if (Accelerated)
{
if ((Num == 0) && (CaptureCnt & (1<<31)) && (((CaptureCnt >> 29) & 0x3) != 1))
@ -947,6 +957,7 @@ void GPU2D::VBlankEnd()
GPU3D::GLRenderer::PrepareCaptureFrame();
}
}
#endif
}

View File

@ -401,8 +401,33 @@ void DoSavestate(Savestate* file)
file->Var32(&NumTestCommands);
file->Var32(&DispCnt);
file->Var8(&AlphaRefVal);
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(&GXStat);
@ -445,7 +470,7 @@ void DoSavestate(Savestate* file)
file->VarArray(vtx->Color, sizeof(s32)*3);
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->FinalColor, sizeof(s32)*3);
@ -471,9 +496,6 @@ void DoSavestate(Savestate* file)
file->Var32(&NumPolygons);
file->Var32(&NumOpaquePolygons);
file->Var32(&ClearAttr1);
file->Var32(&ClearAttr2);
file->Var32(&FlushRequest);
file->Var32(&FlushAttributes);
@ -485,7 +507,7 @@ void DoSavestate(Savestate* file)
file->VarArray(vtx->Color, sizeof(s32)*3);
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->FinalColor, sizeof(s32)*3);
@ -523,17 +545,17 @@ void DoSavestate(Savestate* file)
file->VarArray(poly->FinalZ, 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->TexParam);
file->Var32(&poly->TexPalette);
file->Var32((u32*)&poly->FacingView);
file->Var32((u32*)&poly->Translucent);
file->Bool32(&poly->FacingView);
file->Bool32(&poly->Translucent);
file->Var32((u32*)&poly->IsShadowMask);
file->Var32((u32*)&poly->IsShadow);
file->Bool32(&poly->IsShadowMask);
file->Bool32(&poly->IsShadow);
if (file->IsAtleastVersion(4, 1))
file->Var32((u32*)&poly->Type);
@ -2506,13 +2528,19 @@ void VBlank()
void VCount215()
{
if (GPU::Renderer == 0) SoftRenderer::RenderFrame();
#ifdef OGLRENDERER_ENABLED
else GLRenderer::RenderFrame();
#endif
}
u32* GetLine(int line)
{
if (GPU::Renderer == 0) return SoftRenderer::GetLine(line);
#ifdef OGLRENDERER_ENABLED
else return GLRenderer::GetLine(line);
#else
return NULL;
#endif
}

View File

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

View File

@ -113,7 +113,7 @@ GLuint TexMemID;
GLuint TexPalMemID;
int ScaleFactor;
bool Antialias;
bool BetterPolygons;
int ScreenW, ScreenH;
GLuint FramebufferTex[8];
@ -342,9 +342,6 @@ bool Init()
SetupDefaultTexParams(FramebufferTex[5]);
SetupDefaultTexParams(FramebufferTex[7]);
// downscale framebuffer for antialiased mode
SetupDefaultTexParams(FramebufferTex[2]);
// downscale framebuffer for display capture (always 256x192)
SetupDefaultTexParams(FramebufferTex[3]);
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);
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;
}
@ -404,52 +403,27 @@ void Reset()
void SetRenderSettings(GPU::RenderSettings& settings)
{
int scale = settings.GL_ScaleFactor;
bool antialias = false; // REMOVE ME!
if (antialias) scale *= 2;
ScaleFactor = scale;
Antialias = antialias;
BetterPolygons = settings.GL_BetterPolygons;
ScreenW = 256 * 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[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ScreenW, ScreenH, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, FramebufferTex[2]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, FramebufferTex[4]);
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[5]);
//glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8UI, ScreenW, ScreenH, 0, GL_RGB_INTEGER, 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);
}
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[1]);
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, ScreenH, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
glBindTexture(GL_TEXTURE_2D, FramebufferTex[5]);
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, ScreenW, ScreenH, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
glBindTexture(GL_TEXTURE_2D, FramebufferTex[7]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, ScreenW, ScreenH, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferID[3]);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, FramebufferTex[3], 0);
@ -464,12 +438,6 @@ void SetRenderSettings(GPU::RenderSettings& settings)
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferID[1]);
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_COLOR_ATTACHMENT1, FramebufferTex[7], 0);
glDrawBuffers(2, fbassign);
@ -479,6 +447,8 @@ void SetRenderSettings(GPU::RenderSettings& settings)
glBindBuffer(GL_PIXEL_PACK_BUFFER, PixelbufferID);
glBufferData(GL_PIXEL_PACK_BUFFER, 256*192*4, NULL, GL_DYNAMIC_READ);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
//glLineWidth(scale);
//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)
{
u32* vptr = &VertexBuffer[0];
@ -564,43 +595,16 @@ void BuildPolygons(RendererPolygon* polygons, int npolys)
{
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 (lastx == x && lasty == y) continue;
if (lastx == vtx->FinalPosition[0] &&
lasty == vtx->FinalPosition[1]) continue;
}
*vptr++ = x | (y << 16);
*vptr++ = z | (w << 16);
lastx = vtx->FinalPosition[0];
lasty = vtx->FinalPosition[1];
*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;
vptr = SetupVertex(poly, j, vtx, vtxattr, vptr);
*iptr++ = vidx;
rp->NumIndices++;
@ -610,57 +614,148 @@ void BuildPolygons(RendererPolygon* polygons, int npolys)
if (nout >= 2) break;
}
}
else
else if (poly->NumVertices == 3) // regular triangle
{
rp->PrimType = GL_TRIANGLES;
for (int j = 0; j < poly->NumVertices; j++)
for (int j = 0; j < 3; j++)
{
Vertex* vtx = poly->Vertices[j];
u32 z = poly->FinalZ[j];
u32 w = poly->FinalW[j];
vptr = SetupVertex(poly, j, vtx, vtxattr, vptr);
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;
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];
}
*vptr++ = x | (y << 16);
// build center vertex
*vptr++ = cX | (cY << 16);
*vptr++ = z | (w << 16);
*vptr++ = (vtx->FinalColor[0] >> 1) |
((vtx->FinalColor[1] >> 1) << 8) |
((vtx->FinalColor[2] >> 1) << 16) |
*vptr++ = (u32)cR |
((u32)cG << 8) |
((u32)cB << 16) |
(alpha << 24);
*vptr++ = (u16)vtx->TexCoords[0] | ((u16)vtx->TexCoords[1] << 16);
*vptr++ = (u16)cS | ((u16)cT << 16);
*vptr++ = vtxattr | (zshift << 16);
*vptr++ = poly->TexParam;
*vptr++ = poly->TexPalette;
if (j >= 2)
vidx++;
// build the final polygon
for (int j = 0; j < poly->NumVertices; j++)
{
// build a triangle
*iptr++ = vidx_first;
*iptr++ = vidx - 1;
*iptr++ = vidx;
rp->NumIndices += 3;
Vertex* vtx = poly->Vertices[j];
vptr = SetupVertex(poly, j, vtx, vtxattr, vptr);
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;
// 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
UseRenderShader(flags);
@ -759,8 +858,10 @@ void RenderSceneChunk(int y, int h)
if (rp->PolyData->IsShadowMask) { i++; continue; }
// zorp
glDepthFunc(GL_LESS);
if (rp->PolyData->Attr & (1<<14))
glDepthFunc(GL_LEQUAL);
else
glDepthFunc(GL_LESS);
u32 polyattr = rp->PolyData->Attr;
u32 polyid = (polyattr >> 24) & 0x3F;
@ -845,8 +946,10 @@ void RenderSceneChunk(int y, int h)
{
UseRenderShader(flags | RenderFlag_Trans);
// zorp
glDepthFunc(GL_LESS);
if (rp->PolyData->Attr & (1<<14))
glDepthFunc(GL_LEQUAL);
else
glDepthFunc(GL_LESS);
u32 polyattr = rp->PolyData->Attr;
u32 polyid = (polyattr >> 24) & 0x3F;
@ -936,8 +1039,10 @@ void RenderSceneChunk(int y, int h)
if (!(polyattr & (1<<15))) transfog = fogenable;
else transfog = GL_FALSE;
// zorp
glDepthFunc(GL_LESS);
if (rp->PolyData->Attr & (1<<14))
glDepthFunc(GL_LEQUAL);
else
glDepthFunc(GL_LESS);
if (rp->PolyData->IsShadow)
{
@ -1003,9 +1108,9 @@ void RenderSceneChunk(int y, int h)
glStencilMask(0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, FramebufferTex[4]);
glBindTexture(GL_TEXTURE_2D, FramebufferTex[FrontBuffer ? 6 : 4]);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, FramebufferTex[5]);
glBindTexture(GL_TEXTURE_2D, FramebufferTex[FrontBuffer ? 7 : 5]);
glBindBuffer(GL_ARRAY_BUFFER, ClearVertexBufferID);
glBindVertexArray(ClearVertexArrayID);
@ -1055,8 +1160,8 @@ void RenderFrame()
{
CurShaderID = -1;
if (Antialias) glBindFramebuffer(GL_FRAMEBUFFER, FramebufferID[2]);
else glBindFramebuffer(GL_FRAMEBUFFER, FramebufferID[FrontBuffer]);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, FramebufferID[FrontBuffer]);
ShaderConfig.uScreenSize[0] = ScreenW;
ShaderConfig.uScreenSize[1] = ScreenH;
@ -1218,14 +1323,6 @@ void RenderFrame()
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;
}

View File

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

View File

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

View File

@ -47,6 +47,8 @@ enum
Event_DSi_SDIOTransfer,
Event_DSi_NWifi,
Event_DSi_RAMSizeChange,
Event_MAX
};
@ -209,6 +211,8 @@ void SetLidClosed(bool closed);
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 CancelEvent(u32 id);

View File

@ -25,7 +25,9 @@
#include "CRC32.h"
#include "DSi_AES.h"
#include "Platform.h"
#include "Config.h"
#include "ROMList.h"
#include "melonDLDI.h"
namespace NDSCart_SRAM
@ -464,11 +466,13 @@ u16 SPICnt;
u32 ROMCnt;
u8 ROMCommand[8];
u32 ROMDataOut;
u32 ROMData;
u8 DataOut[0x4000];
u32 DataOutPos;
u32 DataOutLen;
u8 TransferData[0x4000];
u32 TransferPos;
u32 TransferLen;
u32 TransferDir;
u8 TransferCmd[8];
bool CartInserted;
u8* CartROM;
@ -478,6 +482,8 @@ u32 CartID;
bool CartIsHomebrew;
bool CartIsDSi;
FILE* CartSD;
u32 CmdEncMode;
u32 DataEncMode;
@ -489,6 +495,7 @@ u64 Key2_Y;
void ROMCommand_Retail(u8* cmd);
void ROMCommand_RetailNAND(u8* cmd);
void ROMCommand_Homebrew(u8* cmd);
void (*ROMCommandHandler)(u8* cmd);
@ -615,6 +622,8 @@ bool Init()
CartROM = NULL;
CartSD = NULL;
return true;
}
@ -622,6 +631,8 @@ void DeInit()
{
if (CartROM) delete[] CartROM;
if (CartSD) fclose(CartSD);
NDSCart_SRAM::DeInit();
}
@ -635,6 +646,9 @@ void Reset()
CartIsHomebrew = false;
CartIsDSi = false;
if (CartSD) fclose(CartSD);
CartSD = NULL;
ROMCommandHandler = NULL;
NDSCart_SRAM::Reset();
@ -650,11 +664,13 @@ void DoSavestate(Savestate* file)
file->Var32(&ROMCnt);
file->VarArray(ROMCommand, 8);
file->Var32(&ROMDataOut);
file->Var32(&ROMData);
file->VarArray(DataOut, 0x4000);
file->Var32(&DataOutPos);
file->Var32(&DataOutLen);
file->VarArray(TransferData, 0x4000);
file->Var32(&TransferPos);
file->Var32(&TransferLen);
file->Var32(&TransferDir);
file->VarArray(TransferCmd, 8);
// cart inserted/len/ROM/etc should be already populated
// 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 size = *(u32*)&CartROM[0x2C];
@ -696,23 +710,7 @@ void ApplyDLDIPatch()
return;
}
printf("DLDI shit 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);
printf("DLDI structure found at %08X (%08X)\n", dldioffset, offset+dldioffset);
if (*(u32*)&patch[0] != 0xBF8DA5ED ||
*(u32*)&patch[4] != 0x69684320 ||
@ -743,7 +741,7 @@ void ApplyDLDIPatch()
u32 patchsize = 1 << patch[0x0D];
u32 patchend = patchbase + patchsize;
memcpy(&binary[dldioffset], patch, dldisize);
memcpy(&binary[dldioffset], patch, len);
*(u32*)&binary[dldioffset+0x40] += delta;
*(u32*)&binary[dldioffset+0x44] += delta;
@ -807,7 +805,6 @@ void ApplyDLDIPatch()
memset(&binary[dldioffset+fixstart], 0, fixend-fixstart);
}
delete[] patch;
printf("applied DLDI patch\n");
}
@ -987,11 +984,13 @@ bool LoadROM(const char* path, const char* sram, bool direct)
Key1_Encrypt((u32*)&CartROM[arm9base]);
}
}
else
{
CartIsHomebrew = true;
//ApplyDLDIPatch();
}
}
if ((arm9base < 0x4000) || (gamecode == 0x23232323))
{
CartIsHomebrew = true;
if (Config::DLDIEnable)
ApplyDLDIPatch(melonDLDI, sizeof(melonDLDI));
}
if (direct)
@ -1005,7 +1004,9 @@ bool LoadROM(const char* path, const char* sram, bool direct)
CartInserted = true;
// TODO: support more fancy cart types (homebrew?, flashcarts, etc)
if (CartID & 0x08000000)
if (CartIsHomebrew)
ROMCommandHandler = ROMCommand_Homebrew;
else if (CartID & 0x08000000)
ROMCommandHandler = ROMCommand_RetailNAND;
else
ROMCommandHandler = ROMCommand_Retail;
@ -1017,6 +1018,13 @@ bool LoadROM(const char* path, const char* sram, bool direct)
printf("Save file: %s\n", sram);
NDSCart_SRAM::LoadSave(sram, romparams.SaveMemType);
if (CartIsHomebrew && Config::DLDIEnable)
{
CartSD = Platform::OpenLocalFile(Config::DLDISDPath, "r+b");
}
else
CartSD = NULL;
return true;
}
@ -1026,6 +1034,19 @@ void RelocateSave(const char* path, bool 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()
{
// CHECKME: what if there is a transfer in progress?
@ -1034,14 +1055,17 @@ void ResetCart()
ROMCnt = 0;
memset(ROMCommand, 0, 8);
ROMDataOut = 0;
ROMData = 0;
Key2_X = 0;
Key2_Y = 0;
memset(DataOut, 0, 0x4000);
DataOutPos = 0;
DataOutLen = 0;
memset(TransferData, 0, 0x4000);
TransferPos = 0;
TransferLen = 0;
TransferDir = 0;
memset(TransferCmd, 0, 8);
TransferCmd[0] = 0xFF;
CmdEncMode = 0;
DataEncMode = 0;
@ -1055,7 +1079,7 @@ void ReadROM(u32 addr, u32 len, u32 offset)
if ((addr+len) > CartROMSize)
len = CartROMSize - addr;
memcpy(DataOut+offset, CartROM+addr, len);
memcpy(TransferData+offset, CartROM+addr, len);
}
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);
}
memcpy(DataOut+offset, CartROM+addr, len);
memcpy(TransferData+offset, CartROM+addr, len);
}
@ -1079,16 +1103,41 @@ void ROMEndTransfer(u32 param)
if (SPICnt & (1<<14))
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)
{
if (DataOutPos >= DataOutLen)
ROMDataOut = 0;
else
ROMDataOut = *(u32*)&DataOut[DataOutPos];
if (TransferDir == 0)
{
if (TransferPos >= TransferLen)
ROMData = 0;
else
ROMData = *(u32*)&TransferData[TransferPos];
DataOutPos += 4;
TransferPos += 4;
}
ROMCnt |= (1<<23);
@ -1106,16 +1155,16 @@ void ROMCommand_Retail(u8* cmd)
case 0xB7:
{
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);
ReadROM_B7(addr, len1, 0);
ReadROM_B7(addr+len1, DataOutLen-len1, len1);
ReadROM_B7(addr+len1, TransferLen-len1, len1);
}
else
ReadROM_B7(addr, DataOutLen, 0);
ReadROM_B7(addr, TransferLen, 0);
}
break;
@ -1136,8 +1185,8 @@ void ROMCommand_RetailNAND(u8* cmd)
// Jam with the Band stores words 6-9 of this at 0x02131BB0
// it doesn't seem to use those anywhere later
for (u32 pos = 0; pos < DataOutLen; pos += 4)
*(u32*)&DataOut[pos] = 0;
for (u32 pos = 0; pos < TransferLen; pos += 4)
*(u32*)&TransferData[pos] = 0;
}
break;
@ -1150,16 +1199,16 @@ void ROMCommand_RetailNAND(u8* cmd)
case 0xB7:
{
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);
ReadROM_B7(addr, len1, 0);
ReadROM_B7(addr+len1, DataOutLen-len1, len1);
ReadROM_B7(addr+len1, TransferLen-len1, len1);
}
else
ReadROM_B7(addr, DataOutLen, 0);
ReadROM_B7(addr, TransferLen, 0);
}
break;
@ -1169,13 +1218,59 @@ void ROMCommand_RetailNAND(u8* cmd)
// * bit7: busy? error?
// * bit5: accessing savemem
for (u32 pos = 0; pos < DataOutLen; pos += 4)
*(u32*)&DataOut[pos] = NDSCart_SRAM::StatusReg * 0x01010101;
for (u32 pos = 0; pos < TransferLen; pos += 4)
*(u32*)&TransferData[pos] = NDSCart_SRAM::StatusReg * 0x01010101;
}
break;
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;
}
}
@ -1215,8 +1310,8 @@ void WriteROMCnt(u32 val)
else if (datasize > 0)
datasize = 0x100 << datasize;
DataOutPos = 0;
DataOutLen = datasize;
TransferPos = 0;
TransferLen = datasize;
// handle KEY1 encryption as needed.
// 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],
datasize);*/
// default is read
// commands that do writes will change this
TransferDir = 0;
switch (cmd[0])
{
case 0x9F:
memset(DataOut, 0xFF, DataOutLen);
memset(TransferData, 0xFF, TransferLen);
break;
case 0x00:
memset(DataOut, 0, DataOutLen);
if (DataOutLen > 0x1000)
memset(TransferData, 0, TransferLen);
if (TransferLen > 0x1000)
{
ReadROM(0, 0x1000, 0);
for (u32 pos = 0x1000; pos < DataOutLen; pos += 0x1000)
memcpy(DataOut+pos, DataOut, 0x1000);
for (u32 pos = 0x1000; pos < TransferLen; pos += 0x1000)
memcpy(TransferData+pos, TransferData, 0x1000);
}
else
ReadROM(0, DataOutLen, 0);
ReadROM(0, TransferLen, 0);
break;
case 0x90:
case 0xB8:
for (u32 pos = 0; pos < DataOutLen; pos += 4)
*(u32*)&DataOut[pos] = CartID;
for (u32 pos = 0; pos < TransferLen; pos += 4)
*(u32*)&TransferData[pos] = CartID;
break;
case 0x3C:
@ -1292,8 +1391,8 @@ void WriteROMCnt(u32 val)
break;
case 0x10:
for (u32 pos = 0; pos < DataOutLen; pos += 4)
*(u32*)&DataOut[pos] = CartID;
for (u32 pos = 0; pos < TransferLen; pos += 4)
*(u32*)&TransferData[pos] = CartID;
break;
case 0x20:
@ -1343,29 +1442,52 @@ void WriteROMCnt(u32 val)
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()
{
if (ROMCnt & (1<<23))
{
ROMCnt &= ~(1<<23);
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);
AdvanceROMTransfer();
}
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);
void RelocateSave(const char* path, bool write);
int ImportSRAM(const u8* data, u32 length);
void ResetCart();
void WriteROMCnt(u32 val);
u32 ReadROMData();
void WriteROMData(u32 val);
void WriteSPICnt(u16 val);
u8 ReadSPIData();

View File

@ -16,6 +16,9 @@
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 <string.h>
#include <time.h>
@ -125,31 +128,29 @@ void ByteIn(u8 val)
case 0x20:
{
time_t timestamp;
struct tm* timedata;
time(&timestamp);
timedata = localtime(&timestamp);
time_t timestamp = time(NULL);
struct tm timedata;
localtime_r(&timestamp, &timedata);
Output[0] = BCD(timedata->tm_year - 100);
Output[1] = BCD(timedata->tm_mon + 1);
Output[2] = BCD(timedata->tm_mday);
Output[3] = BCD(timedata->tm_wday);
Output[4] = BCD(timedata->tm_hour);
Output[5] = BCD(timedata->tm_min);
Output[6] = BCD(timedata->tm_sec);
Output[0] = BCD(timedata.tm_year - 100);
Output[1] = BCD(timedata.tm_mon + 1);
Output[2] = BCD(timedata.tm_mday);
Output[3] = BCD(timedata.tm_wday);
Output[4] = BCD(timedata.tm_hour);
Output[5] = BCD(timedata.tm_min);
Output[6] = BCD(timedata.tm_sec);
}
break;
case 0x60:
{
time_t timestamp;
struct tm* timedata;
time(&timestamp);
timedata = localtime(&timestamp);
time_t timestamp = time(NULL);
struct tm timedata;
localtime_r(&timestamp, &timedata);
Output[0] = BCD(timedata->tm_hour);
Output[1] = BCD(timedata->tm_min);
Output[2] = BCD(timedata->tm_sec);
Output[0] = BCD(timedata.tm_hour);
Output[1] = BCD(timedata.tm_min);
Output[2] = BCD(timedata.tm_sec);
}
break;

View File

@ -179,24 +179,25 @@ void Reset()
//Firmware[userdata+0x64] &= 0xBF;
*(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",
Firmware[0x36], Firmware[0x37], Firmware[0x38],
Firmware[0x39], Firmware[0x3A], Firmware[0x3B]);
//*(u16*)&Firmware[0x2A] = CRC16(&Firmware[0x2C], *(u16*)&Firmware[0x2C], 0x0000);
// verify shit
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");
@ -241,6 +242,7 @@ void SetupDirectBoot()
u8 GetConsoleType() { return Firmware[0x1D]; }
u8 GetWifiVersion() { return Firmware[0x2F]; }
u8 GetNWifiVersion() { return Firmware[0x1FD]; } // for DSi; will return 0xFF on a DS
u8 GetRFVersion() { return Firmware[0x40]; }
u8* GetWifiMAC() { return &Firmware[0x36]; }

View File

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

View File

@ -420,6 +420,8 @@ void Channel::Run(s32* buf, u32 samples)
{
if (!(Cnt & (1<<31))) return;
if ((type < 3) && ((Length+LoopPos) < 16)) return;
if (KeyOn)
{
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)
{
if (Error) return;
@ -273,4 +289,4 @@ void Savestate::VarArray(void* data, u32 len)
{
fread(data, len, 1, file);
}
}
}

View File

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

View File

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

View File

@ -1631,7 +1631,7 @@ void ARM64XEmitter::ASR(ARM64Reg Rd, ARM64Reg Rm, int shift)
int bits = Is64Bit(Rd) ? 64 : 32;
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);
}

View File

@ -727,7 +727,7 @@ public:
void LSR(ARM64Reg Rd, ARM64Reg Rm, int shift);
void LSL(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)
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);
}
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);
}

View File

@ -489,7 +489,7 @@ public:
// 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 RCR(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
void Init_ROM();
// deinitialize the ROM handling utility
void DeInit_ROM();
// load the BIOS/firmware and boot from it
int LoadBIOS();
@ -97,6 +100,12 @@ bool SaveState(const char* filename);
// undo the latest savestate load
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
// * screenWidth/screenHeight: size of the host display

View File

@ -27,6 +27,8 @@
#include "NDS.h"
#include "GBACart.h"
#include "AREngine.h"
namespace Frontend
{
@ -37,6 +39,9 @@ char PrevSRAMPath[ROMSlot_MAX][1024]; // for savestate 'undo load'
bool SavestateLoaded;
ARCodeFile* CheatFile;
bool CheatsOn;
void Init_ROM()
{
@ -48,6 +53,18 @@ void Init_ROM()
memset(SRAMPath[ROMSlot_GBA], 0, 1024);
memset(PrevSRAMPath[ROMSlot_NDS], 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
@ -198,6 +215,32 @@ int VerifyDSiNAND()
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 res;
@ -235,6 +278,8 @@ int LoadBIOS()
SavestateLoaded = false;
LoadCheats();
return Load_OK;
}
@ -295,6 +340,8 @@ int LoadROM(const char* file, int slot)
{
SavestateLoaded = false;
LoadCheats();
// Reload the inserted GBA cartridge (if any)
// TODO: report failure there??
if (ROMPath[ROMSlot_GBA][0] != '\0') NDS::LoadGBAROM(ROMPath[ROMSlot_GBA], SRAMPath[ROMSlot_GBA]);
@ -387,6 +434,8 @@ int Reset()
return Load_ROMLoadError;
}
LoadCheats();
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
main.cpp
main_shaders.h
CheatsDialog.cpp
EmuSettingsDialog.cpp
InputConfigDialog.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->txtBIOS7Path->setText(Config::BIOS7Path);
ui->txtFirmwarePath->setText(Config::FirmwarePath);
ui->cbDLDIEnable->setChecked(Config::DLDIEnable != 0);
ui->txtDLDISDPath->setText(Config::DLDISDPath);
ui->txtDSiBIOS9Path->setText(Config::DSiBIOS9Path);
ui->txtDSiBIOS7Path->setText(Config::DSiBIOS7Path);
ui->txtDSiFirmwarePath->setText(Config::DSiFirmwarePath);
ui->txtDSiNANDPath->setText(Config::DSiNANDPath);
ui->cbDSiSDEnable->setChecked(Config::DSiSDEnable != 0);
ui->txtDSiSDPath->setText(Config::DSiSDPath);
ui->cbxConsoleType->addItem("DS");
ui->cbxConsoleType->addItem("DSi (experimental)");
@ -141,10 +145,14 @@ void EmuSettingsDialog::done(int r)
std::string bios9Path = ui->txtBIOS9Path->text().toStdString();
std::string bios7Path = ui->txtBIOS7Path->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 dsiBios7Path = ui->txtDSiBIOS7Path->text().toStdString();
std::string dsiFirmwarePath = ui->txtDSiFirmwarePath->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
|| directBoot != Config::DirectBoot
@ -158,10 +166,14 @@ void EmuSettingsDialog::done(int r)
|| strcmp(Config::BIOS9Path, bios9Path.c_str()) != 0
|| strcmp(Config::BIOS7Path, bios7Path.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::DSiBIOS7Path, dsiBios7Path.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
&& 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::BIOS7Path, bios7Path.c_str(), 1023); Config::BIOS7Path[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::DSiBIOS7Path, dsiBios7Path.c_str(), 1023); Config::DSiBIOS7Path[1023] = '\0';
strncpy(Config::DSiFirmwarePath, dsiFirmwarePath.c_str(), 1023); Config::DSiFirmwarePath[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
Config::JIT_Enable = jitEnable;
@ -260,6 +276,18 @@ void EmuSettingsDialog::on_btnDSiBIOS7Browse_clicked()
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()
{
QString file = QFileDialog::getOpenFileName(this,
@ -284,6 +312,18 @@ void EmuSettingsDialog::on_btnDSiNANDBrowse_clicked()
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()
{
bool disabled = !ui->chkEnableJIT->isChecked();

View File

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

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>514</width>
<height>359</height>
<width>575</width>
<height>254</height>
</rect>
</property>
<property name="sizePolicy">
@ -86,209 +86,242 @@
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>BIOS Files</string>
<string>DS-mode</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>DS mode</string>
<layout class="QGridLayout" name="gridLayout">
<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>
<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>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>DSi mode</string>
<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="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>
<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>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_3">
<attribute name="title">
<string>CPU Emulation</string>
<string>CPU emulation</string>
</attribute>
<layout class="QFormLayout" name="formLayout_5">
<item row="0" column="0">
@ -354,6 +387,53 @@
</item>
</layout>
</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>
</item>
<item>
@ -369,23 +449,8 @@
</layout>
</widget>
<tabstops>
<tabstop>tabWidget</tabstop>
<tabstop>cbxConsoleType</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>spnJITMaximumBlockSize</tabstop>
</tabstops>

View File

@ -98,7 +98,9 @@ int GetEventKeyVal(QKeyEvent* event)
void KeyPress(QKeyEvent* 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++)
if (keyKP == Config::KeyMapping[i])
@ -112,7 +114,9 @@ void KeyPress(QKeyEvent* event)
void KeyRelease(QKeyEvent* 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++)
if (keyKP == Config::KeyMapping[i])

View File

@ -54,6 +54,7 @@ const int hk_general[] =
HK_Reset,
HK_FastForward,
HK_FastForwardToggle,
HK_FullscreenToggle,
HK_Lid,
HK_Mic,
};
@ -64,6 +65,7 @@ const char* hk_general_labels[] =
"Reset",
"Fast forward",
"Toggle FPS limit",
"Toggle Fullscreen",
"Close/open lid",
"Microphone",
};
@ -86,7 +88,7 @@ InputConfigDialog::InputConfigDialog(QWidget* parent) : QDialog(parent), ui(new
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]];
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->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();
if (njoy > 0)
@ -177,7 +179,7 @@ void InputConfigDialog::on_InputConfigDialog_accepted()
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::HKJoyMapping[hk_general[i]] = hkGeneralJoyMap[i];
@ -226,7 +228,7 @@ void KeyMapButton::keyPressEvent(QKeyEvent* 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 mod = event->modifiers();

View File

@ -64,7 +64,7 @@ private:
int keypadKeyMap[12], keypadJoyMap[12];
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)
{
#if defined(__WIN32__) || defined(UNIX_PORTABLE)
#if defined(__WIN32__) || defined(PORTABLE)
if (argc > 0 && strlen(argv[0]) > 0)
{
int len = strlen(argv[0]);
@ -137,13 +137,20 @@ FILE* OpenFile(const char* path, const char* mode, bool mustexist)
}
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;
} 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;
} else if (mode[0] == 'w') {
}
else if (mode[0] == 'w')
{
qmode = QIODevice::OpenModeFlag::Truncate | QIODevice::OpenModeFlag::WriteOnly;
} else {
}
else
{
qmode = QIODevice::OpenModeFlag::ReadOnly;
}
@ -167,7 +174,7 @@ FILE* OpenLocalFile(const char* path, const char* mode)
else
{
#ifdef PORTABLE
fullpath = path;
fullpath = QString(EmuDirectory) + QDir::separator() + path;
#else
// Check user configuration directory
QDir config(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation));

View File

@ -51,7 +51,7 @@ int _3DRenderer;
int Threaded3D;
int GL_ScaleFactor;
int GL_Antialias;
int GL_BetterPolygons;
int LimitFPS;
int AudioSync;
@ -72,6 +72,8 @@ char MicWavPath[1024];
char LastROMFolder[1024];
int EnableCheats;
bool EnableJIT;
ConfigEntry PlatformConfigFile[] =
@ -108,6 +110,7 @@ ConfigEntry PlatformConfigFile[] =
{"HKKey_Reset", 0, &HKKeyMapping[HK_Reset], -1, NULL, 0},
{"HKKey_FastForward", 0, &HKKeyMapping[HK_FastForward], -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_SolarSensorIncrease", 0, &HKKeyMapping[HK_SolarSensorIncrease], -1, NULL, 0},
@ -117,6 +120,7 @@ ConfigEntry PlatformConfigFile[] =
{"HKJoy_Reset", 0, &HKJoyMapping[HK_Reset], -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_FullscreenToggle], -1, NULL, 0},
{"HKJoy_SolarSensorDecrease", 0, &HKJoyMapping[HK_SolarSensorDecrease], -1, NULL, 0},
{"HKJoy_SolarSensorIncrease", 0, &HKJoyMapping[HK_SolarSensorIncrease], -1, NULL, 0},
@ -133,15 +137,15 @@ ConfigEntry PlatformConfigFile[] =
{"IntegerScaling", 0, &IntegerScaling, 0, 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},
{"ScreenVSyncInterval", 0, &ScreenVSyncInterval, 1, NULL, 0},
{"3DRenderer", 0, &_3DRenderer, 1, NULL, 0},
{"3DRenderer", 0, &_3DRenderer, 0, NULL, 0},
{"Threaded3D", 0, &Threaded3D, 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},
{"AudioSync", 0, &AudioSync, 1, NULL, 0},
@ -162,6 +166,8 @@ ConfigEntry PlatformConfigFile[] =
{"LastROMFolder", 1, LastROMFolder, 0, "", 1023},
{"EnableCheats", 0, &EnableCheats, 0, NULL, 0},
{"", -1, NULL, 0, NULL, 0}
};

View File

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

View File

@ -42,6 +42,7 @@ VideoSettingsDialog::VideoSettingsDialog(QWidget* parent) : QDialog(parent), ui(
oldVSyncInterval = Config::ScreenVSyncInterval;
oldSoftThreaded = Config::Threaded3D;
oldGLScale = Config::GL_ScaleFactor;
oldGLBetterPolygons = Config::GL_BetterPolygons;
grp3DRenderer = new QButtonGroup(this);
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)));
grp3DRenderer->button(Config::_3DRenderer)->setChecked(true);
#ifndef OGLRENDERER_ENABLED
ui->rb3DOpenGL->setEnabled(false);
#endif
ui->cbGLDisplay->setChecked(Config::ScreenUseGL != 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->setCurrentIndex(Config::GL_ScaleFactor-1);
ui->cbBetterPolygons->setChecked(Config::GL_BetterPolygons != 0);
if (!Config::ScreenVSync)
ui->sbVSyncInterval->setEnabled(false);
@ -68,12 +75,14 @@ VideoSettingsDialog::VideoSettingsDialog(QWidget* parent) : QDialog(parent), ui(
ui->cbGLDisplay->setEnabled(true);
ui->cbSoftwareThreaded->setEnabled(true);
ui->cbxGLResolution->setEnabled(false);
ui->cbBetterPolygons->setEnabled(false);
}
else
{
ui->cbGLDisplay->setEnabled(false);
ui->cbSoftwareThreaded->setEnabled(false);
ui->cbxGLResolution->setEnabled(true);
ui->cbBetterPolygons->setEnabled(true);
}
}
@ -99,6 +108,7 @@ void VideoSettingsDialog::on_VideoSettingsDialog_rejected()
Config::ScreenVSyncInterval = oldVSyncInterval;
Config::Threaded3D = oldSoftThreaded;
Config::GL_ScaleFactor = oldGLScale;
Config::GL_BetterPolygons = oldGLBetterPolygons;
bool new_gl = (Config::ScreenUseGL != 0) || (Config::_3DRenderer != 0);
emit updateVideoSettings(old_gl != new_gl);
@ -117,12 +127,14 @@ void VideoSettingsDialog::onChange3DRenderer(int renderer)
ui->cbGLDisplay->setEnabled(true);
ui->cbSoftwareThreaded->setEnabled(true);
ui->cbxGLResolution->setEnabled(false);
ui->cbBetterPolygons->setEnabled(false);
}
else
{
ui->cbGLDisplay->setEnabled(false);
ui->cbSoftwareThreaded->setEnabled(false);
ui->cbxGLResolution->setEnabled(true);
ui->cbBetterPolygons->setEnabled(true);
}
bool new_gl = (Config::ScreenUseGL != 0) || (Config::_3DRenderer != 0);
@ -167,3 +179,10 @@ void VideoSettingsDialog::on_cbxGLResolution_currentIndexChanged(int idx)
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_cbxGLResolution_currentIndexChanged(int idx);
void on_cbBetterPolygons_stateChanged(int state);
void on_cbSoftwareThreaded_stateChanged(int state);
@ -78,6 +79,7 @@ private:
int oldVSyncInterval;
int oldSoftThreaded;
int oldGLScale;
int oldGLBetterPolygons;
};
#endif // VIDEOSETTINGSDIALOG_H

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>482</width>
<height>237</height>
<height>244</height>
</rect>
</property>
<property name="sizePolicy">
@ -43,6 +43,16 @@
</property>
</widget>
</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>
</widget>
</item>

View File

@ -17,7 +17,7 @@
*/
#include <stdio.h>
#include <QFileDialog>
#include <QMessageBox>
#include "types.h"
#include "Platform.h"
@ -41,6 +41,10 @@
WifiSettingsDialog* WifiSettingsDialog::currentDlg = nullptr;
bool WifiSettingsDialog::needsReset = false;
extern bool RunningSomething;
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->cbBindAnyAddr->setChecked(Config::SocketBindAnyAddr != 0);
ui->cbRandomizeMAC->setChecked(Config::RandomizeMAC != 0);
int sel = 0;
for (int i = 0; i < LAN_PCap::NumAdapters; i++)
@ -77,33 +82,49 @@ WifiSettingsDialog::~WifiSettingsDialog()
delete ui;
}
void WifiSettingsDialog::on_WifiSettingsDialog_accepted()
void WifiSettingsDialog::done(int r)
{
Config::SocketBindAnyAddr = ui->cbBindAnyAddr->isChecked() ? 1:0;
Config::DirectLAN = ui->cbDirectMode->isChecked() ? 1:0;
needsReset = false;
int sel = ui->cbxDirectAdapter->currentIndex();
if (sel < 0 || sel >= LAN_PCap::NumAdapters) sel = 0;
if (LAN_PCap::NumAdapters < 1)
if (r == QDialog::Accepted)
{
Config::LANDevice[0] = '\0';
}
else
{
strncpy(Config::LANDevice, LAN_PCap::Adapters[sel].DeviceName, 127);
Config::LANDevice[127] = '\0';
int randommac = ui->cbRandomizeMAC->isChecked() ? 1:0;
if (randommac != Config::RandomizeMAC)
{
if (RunningSomething
&& 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();
}
void WifiSettingsDialog::on_WifiSettingsDialog_rejected()
{
closeDlg();
}
void WifiSettingsDialog::on_cbDirectMode_stateChanged(int state)
{
updateAdapterControls();

View File

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

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>479</width>
<height>217</height>
<height>240</height>
</rect>
</property>
<property name="sizePolicy">
@ -39,6 +39,16 @@
</property>
</widget>
</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>
</widget>
</item>

View File

@ -41,6 +41,7 @@
#include "main.h"
#include "Input.h"
#include "CheatsDialog.h"
#include "EmuSettingsDialog.h"
#include "InputConfigDialog.h"
#include "VideoSettingsDialog.h"
@ -55,7 +56,9 @@
#include "NDS.h"
#include "GBACart.h"
#ifdef OGLRENDERER_ENABLED
#include "OpenGLSupport.h"
#endif
#include "GPU.h"
#include "SPU.h"
#include "Wifi.h"
@ -120,7 +123,6 @@ void audioCallback(void* data, Uint8* stream, int len)
if (num_in < len_in-margin)
{
int last = num_in-1;
if (last < 0) last = 0;
for (int i = num_in; i < len_in-margin; i++)
((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(windowEmuReset()), mainWindow->actReset, SLOT(trigger()));
connect(this, SIGNAL(screenLayoutChange()), mainWindow->panel, SLOT(onScreenLayoutChanged()));
connect(this, SIGNAL(windowFullscreenToggle()), mainWindow, SLOT(onFullscreenToggled()));
if (mainWindow->hasOGL) initOpenGL();
}
@ -342,13 +345,17 @@ void EmuThread::run()
videoSettings.Soft_Threaded = Config::Threaded3D != 0;
videoSettings.GL_ScaleFactor = Config::GL_ScaleFactor;
#ifdef OGLRENDERER_ENABLED
if (hasOGL)
{
oglContext->makeCurrent(oglSurface);
videoRenderer = OpenGL::Init() ? Config::_3DRenderer : 0;
}
else
#endif
{
videoRenderer = 0;
}
GPU::InitRenderer(videoRenderer);
GPU::SetRenderSettings(videoRenderer, videoSettings);
@ -371,6 +378,8 @@ void EmuThread::run()
if (Input::HotkeyPressed(HK_Pause)) emit windowEmuPause();
if (Input::HotkeyPressed(HK_Reset)) emit windowEmuReset();
if (Input::HotkeyPressed(HK_FullscreenToggle)) emit windowFullscreenToggle();
if (GBACart::CartInserted && GBACart::HasSolarSensor)
{
@ -400,20 +409,27 @@ void EmuThread::run()
if (hasOGL != mainWindow->hasOGL)
{
hasOGL = mainWindow->hasOGL;
#ifdef OGLRENDERER_ENABLED
if (hasOGL)
{
oglContext->makeCurrent(oglSurface);
videoRenderer = OpenGL::Init() ? Config::_3DRenderer : 0;
}
else
#endif
{
videoRenderer = 0;
}
}
else
videoRenderer = hasOGL ? Config::_3DRenderer : 0;
videoSettingsDirty = false;
videoSettings.Soft_Threaded = Config::Threaded3D != 0;
videoSettings.GL_ScaleFactor = Config::GL_ScaleFactor;
videoSettings.GL_BetterPolygons = Config::GL_BetterPolygons;
GPU::SetRenderSettings(videoRenderer, videoSettings);
}
@ -924,12 +940,14 @@ void ScreenPanelGL::paintGL()
int frontbuf = GPU::FrontBuffer;
glActiveTexture(GL_TEXTURE0);
#ifdef OGLRENDERER_ENABLED
if (GPU::Renderer != 0)
{
// hardware-accelerated render
GPU::GLCompositor::BindOutputTexture();
}
else
#endif
{
// regular render
glBindTexture(GL_TEXTURE_2D, screenTexture);
@ -1053,6 +1071,9 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
actUndoStateLoad->setShortcut(QKeySequence(Qt::Key_F12));
connect(actUndoStateLoad, &QAction::triggered, this, &MainWindow::onUndoStateLoad);
actImportSavefile = menu->addAction("Import savefile");
connect(actImportSavefile, &QAction::triggered, this, &MainWindow::onImportSavefile);
menu->addSeparator();
actQuit = menu->addAction("Quit");
@ -1070,6 +1091,15 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
actStop = menu->addAction("Stop");
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");
@ -1212,11 +1242,16 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
actLoadState[i]->setEnabled(false);
}
actUndoStateLoad->setEnabled(false);
actImportSavefile->setEnabled(false);
actPause->setEnabled(false);
actReset->setEnabled(false);
actStop->setEnabled(false);
actSetupCheats->setEnabled(false);
actEnableCheats->setChecked(Config::EnableCheats != 0);
actSavestateSRAMReloc->setChecked(Config::SavestateRelocSRAM != 0);
@ -1327,7 +1362,7 @@ void MainWindow::dragEnterEvent(QDragEnterEvent* event)
QString filename = urls.at(0).toLocalFile();
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();
}
@ -1651,6 +1686,41 @@ void MainWindow::onUndoStateLoad()
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()
{
QApplication::quit();
@ -1704,6 +1774,25 @@ void MainWindow::onStop()
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()
{
@ -1767,14 +1856,14 @@ void MainWindow::onAudioSettingsFinished(int res)
void MainWindow::onOpenWifiSettings()
{
emuThread->emuPause();
WifiSettingsDialog* dlg = WifiSettingsDialog::openDlg(this);
connect(dlg, &WifiSettingsDialog::finished, this, &MainWindow::onWifiSettingsFinished);
}
void MainWindow::onWifiSettingsFinished(int res)
{
emuThread->emuPause();
if (Wifi::MPInited)
{
Platform::MP_DeInit();
@ -1784,6 +1873,9 @@ void MainWindow::onWifiSettingsFinished(int res)
Platform::LAN_DeInit();
Platform::LAN_Init();
if (WifiSettingsDialog::needsReset)
onReset();
emuThread->emuUnpause();
}
@ -1892,21 +1984,51 @@ void MainWindow::onTitleUpdate(QString title)
setWindowTitle(title);
}
void MainWindow::onFullscreenToggled()
{
if (!mainWindow->isFullScreen())
{
mainWindow->showFullScreen();
mainWindow->menuBar()->hide();
}
else
{
mainWindow->showNormal();
mainWindow->menuBar()->show();
}
}
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);
actLoadState[i]->setEnabled(Frontend::SavestateExists(i));
for (int i = 0; i < 9; 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->setChecked(false);
actReset->setEnabled(true);
actStop->setEnabled(true);
actImportSavefile->setEnabled(true);
actSetupCheats->setEnabled(true);
}
void MainWindow::onEmuStop()
@ -1919,10 +2041,13 @@ void MainWindow::onEmuStop()
actLoadState[i]->setEnabled(false);
}
actUndoStateLoad->setEnabled(false);
actImportSavefile->setEnabled(false);
actPause->setEnabled(false);
actReset->setEnabled(false);
actStop->setEnabled(false);
actSetupCheats->setEnabled(false);
}
void MainWindow::onUpdateVideoSettings(bool glchange)
@ -2054,6 +2179,8 @@ int main(int argc, char** argv)
micWavBuffer = nullptr;
Frontend::Init_ROM();
Frontend::EnableCheats(Config::EnableCheats != 0);
Frontend::Init_Audio(audioFreq);
if (Config::MicInputType == 1)
@ -2080,7 +2207,7 @@ int main(int argc, char** argv)
char* file = argv[1];
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);
@ -2110,6 +2237,8 @@ int main(int argc, char** argv)
Input::CloseJoystick();
Frontend::DeInit_ROM();
if (audioDevice) SDL_CloseAudioDevice(audioDevice);
if (micDevice) SDL_CloseAudioDevice(micDevice);

View File

@ -69,6 +69,8 @@ signals:
void windowLimitFPSChange();
void screenLayoutChange();
void windowFullscreenToggle();
private:
volatile int EmuStatus;
@ -193,11 +195,15 @@ private slots:
void onSaveState();
void onLoadState();
void onUndoStateLoad();
void onImportSavefile();
void onQuit();
void onPause(bool checked);
void onReset();
void onStop();
void onEnableCheats(bool checked);
void onSetupCheats();
void onCheatsDialogFinished(int res);
void onOpenEmuSettings();
void onEmuSettingsDialogFinished(int res);
@ -226,6 +232,8 @@ private slots:
void onEmuStop();
void onUpdateVideoSettings(bool glchange);
void onFullscreenToggled();
private:
void createScreenPanel();
@ -240,11 +248,14 @@ public:
QAction* actSaveState[9];
QAction* actLoadState[9];
QAction* actUndoStateLoad;
QAction* actImportSavefile;
QAction* actQuit;
QAction* actPause;
QAction* actReset;
QAction* actStop;
QAction* actEnableCheats;
QAction* actSetupCheats;
QAction* actEmuSettings;
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
#define TYPES_H
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long int u64;
typedef signed char s8;
typedef signed short s16;
typedef signed int s32;
typedef signed long long int s64;
#include <stdint.h>
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef int8_t s8;
typedef int16_t s16;
typedef int32_t s32;
typedef int64_t s64;
#endif // TYPES_H

View File

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