Compare commits

...

17 commits

Author SHA1 Message Date
Admiral H. Curtiss 8641abcf86
Merge 4754596870 into 10798c3464 2024-05-07 11:27:52 -03:00
Nadia Holmquist Pedersen 10798c3464 fix README build badges finally 2024-05-05 08:40:37 +02:00
Nadia Holmquist Pedersen ee2c6cc7c2 actually add the cmake script too 2024-05-05 08:14:00 +02:00
Nadia Holmquist Pedersen 474bf6e784 Set default optimization flags less intrusively 2024-05-05 08:10:21 +02:00
Nadia Holmquist Pedersen 35cea5e1d7 Fix zstd ROM loading issues
* fix use-after-free of inContent
* don't try to free the DStream twice
2024-05-04 18:16:24 +02:00
Jakly 6112aa120a
Pu region sizing/bounds fix (#2024)
* fix the pu region's end point overflowing

According to gericom it cannot overflow at all

* set a minimum and a better maximum for the pu region size

* fix pu logging

* PU regions with a size of 31 always take up the entire address space

also tweak some logging a little more

* start is actually force aligned by size, oops

* small tweaks

* hopefully more clear code

* math is for nerds
2024-05-02 17:44:59 +02:00
Nadia Holmquist Pedersen ba8d547dfa Windows: Work around CMake not finding libarchive's include directory because MSYS2 CMake doesn't like UNIX paths. 2024-04-18 12:25:41 +02:00
RealAstolfo 84474105e2
ssize_t is not defined in stddef.h (#1999)
i had to add sys/types.h and patch my gentoo ebuilds for a successful compilation.
2024-04-18 13:40:38 +02:00
Rayyan Ansari 5a852cb00d
ROMManager: optimise ROMIcon function
Precompute all 16 5-bit RGB palette colours into 8-bit RGBA to avoid
repeated and superfluous calculation within the nested loop at the
point of index lookup.

A speedup was observed, from ~7ms, to a consistent 1ms
(i.e. now practically instantaneous) through timing with
std::chrono::high_resolution_clock.

Also improve comprehensibility, by using meaningful names, where
appropriate, for loop counter variables.
2024-04-16 23:39:22 +01:00
Arisotura 95adc87f6d wifi: try ignoring MP frames if not engaging in MP comm 2024-04-13 12:17:16 +02:00
Arisotura 8feeee6103 Input: only check joystick input if a joystick actually exists 2024-04-12 20:02:16 +02:00
Arisotura d99c571f94 FATStorage: make sure to always properly unmount the volume (fixes evil bug) 2024-04-12 19:43:02 +02:00
Arisotura 111dc7a563 wifi improvements:
* implement channels
* rework power-down support, fixing bugs
* fix bug when W_BeaconInterval is zero
* fix potential missing IRQs when writing to W_IE
2024-04-12 17:28:51 +02:00
Arisotura 0b87dd5fa6 fix touchscreen bug on Wayland 2024-04-09 12:54:31 +02:00
Arisotura 968bd26d85 fix generation of instance-unique MAC address when using an external firmware 2024-04-09 11:38:38 +02:00
Nadia Holmquist Pedersen 6e26559cd2
ci: fix macOS build
GitHub Actions' macOS runners have Python from homebrew installed and it's used by default instead of the Python that ships with macOS. Apparently Homebrew decided you shouldn't be able to install stuff with `pip3` anymore so our build broke since `setuptools` is no longer included by default and `glib` from vcpkg needs it to build.

Additionally,, the whole liblzma mess ended up breaking our builds too because libarchive (and its dependency libxml2) depends on it and the download is no longer available. The build option changes here should be reverted once this is sorted out because this is probably partially breaking archive support.

PS: Fuck you Jia Tan.
2024-04-03 14:49:27 +02:00
Admiral H. Curtiss 4754596870 ARMJit Compiler::Reset(): Cleaner way to fill memory with BRK. 2021-03-24 23:50:12 +01:00
20 changed files with 493 additions and 236 deletions

View file

@ -21,7 +21,7 @@ jobs:
uses: actions/checkout@v3
- name: Install dependencies for package building
run: |
brew install autoconf automake autoconf-archive libtool && pip3 install setuptools
brew install autoconf automake autoconf-archive libtool python-setuptools
- name: Set up CMake
uses: lukka/get-cmake@latest
- name: Set up vcpkg

View file

@ -8,6 +8,7 @@ endif()
set(CMAKE_POLICY_DEFAULT_CMP0069 NEW)
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
set(CMAKE_USER_MAKE_RULES_OVERRIDE "${CMAKE_SOURCE_DIR}/cmake/DefaultBuildFlags.cmake")
option(USE_VCPKG "Use vcpkg for dependency packages" OFF)
if (USE_VCPKG)
@ -78,14 +79,6 @@ if (ENABLE_LTO)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL GNU)
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Og")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Og")
endif()
string(REPLACE "-O2" "-O3" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
string(REPLACE "-O2" "-O3" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
if (NOT APPLE)
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} -s")
endif()

View file

@ -6,10 +6,9 @@
<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>
<br>
<a href="https://github.com/melonDS-emu/melonDS/actions?query=workflow%3A%22CMake+Build+%28Windows+x86-64%29%22+event%3Apush"><img src="https://img.shields.io/github/actions/workflow/status/melonDS-emu/melonDS/build-windows.yml?label=Windows%20x86-64&logo=GitHub&branch=master"></img></a>
<a href="https://github.com/melonDS-emu/melonDS/actions?query=workflow%3A%22CMake+Build+%28Ubuntu+x86-64%29%22+event%3Apush"><img src="https://img.shields.io/github/actions/workflow/status/melonDS-emu/melonDS/build-ubuntu.yml?label=Linux%20x86-64&logo=GitHub"></img></a>
<a href="https://github.com/melonDS-emu/melonDS/actions?query=workflow%3A%22CMake+Build+%28Ubuntu+aarch64%29%22+event%3Apush"><img src="https://img.shields.io/github/actions/workflow/status/melonDS-emu/melonDS/build-ubuntu-aarch64.yml?label=Linux%20ARM64&logo=GitHub"></img></a>
<a href="https://github.com/melonDS-emu/melonDS/actions/workflows/build-macos-universal.yml?query=event%3Apush"><img src="https://img.shields.io/github/actions/workflow/status/melonDS-emu/melonDS/build-macos.yml?label=macOS%20Universal&logo=GitHub"></img></a>
<a href="https://github.com/melonDS-emu/melonDS/actions/workflows/build-windows.yml?query=event%3Apush"><img src="https://github.com/melonDS-emu/melonDS/actions/workflows/build-windows.yml/badge.svg" /></a>
<a href="https://github.com/melonDS-emu/melonDS/actions/workflows/build-ubuntu.yml?query=event%3Apush"><img src="https://github.com/melonDS-emu/melonDS/actions/workflows/build-ubuntu.yml/badge.svg" /></a>
<a href="https://github.com/melonDS-emu/melonDS/actions/workflows/build-macos.yml?query=event%3Apush"><img src="https://github.com/melonDS-emu/melonDS/actions/workflows/build-macos.yml/badge.svg" /></a>
</p>
DS emulator, sorta

View file

@ -0,0 +1,9 @@
if (CMAKE_C_COMPILER_ID STREQUAL GNU)
set(CMAKE_C_FLAGS_DEBUG_INIT "-g -Og")
endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL GNU)
set(CMAKE_CXX_FLAGS_DEBUG_INIT "-g -Og")
endif()
string(REPLACE "-O2" "-O3" CMAKE_C_FLAGS_RELEASE_INIT "${CMAKE_C_FLAGS_RELEASE_INIT}")
string(REPLACE "-O2" "-O3" CMAKE_CXX_FLAGS_RELEASE_INIT "${CMAKE_CXX_FLAGS_RELEASE_INIT}")

View file

@ -19,6 +19,13 @@ function(fix_interface_includes)
if (PARENT_DIR MATCHES "include$")
list(APPEND NEW_DIRS "${PARENT_DIR}")
endif()
# HACK
# The libarchive pkg-config file in MSYS2 seems to include a UNIX-style path for its
# include directory and CMake doesn't like that.
if (WIN32 AND MINGW AND target STREQUAL PkgConfig::LibArchive)
list(FILTER DIRS EXCLUDE REGEX "^/[^.]+64/.*")
endif()
endforeach()
list(APPEND DIRS ${NEW_DIRS})

View file

@ -865,8 +865,9 @@ void Compiler::Reset()
const u32 brk_0 = 0xD4200000;
for (int i = 0; i < (JitMemMainSize + JitMemSecondarySize) / 4; i++)
*(((u32*)GetRWPtr()) + i) = brk_0;
u8* const rw_ptr = GetWriteableRWPtr();
for (u32 i = 0; i < (JitMemMainSize + JitMemSecondarySize); i += sizeof(u32))
std::memcpy(rw_ptr + i, &brk_0, sizeof(u32));
}
void Compiler::Comp_AddCycles_C(bool forceNonConstant)

View file

@ -186,10 +186,14 @@ void ARMv5::UpdatePURegion(u32 n)
return;
}
u32 start = rgn >> 12;
u32 sz = 2 << ((rgn >> 1) & 0x1F);
u32 end = start + (sz >> 12);
// TODO: check alignment of start
// notes:
// * min size of a pu region is 4KiB (12 bits)
// * size is calculated as size + 1, but the 12 lsb of address space are ignored, therefore we need it as size + 1 - 12, or size - 11
// * pu regions are aligned based on their size
u32 size = std::max((int)((rgn>>1) & 0x1F) - 11, 0); // obtain the size, subtract 11 and clamp to a min of 0.
u32 start = ((rgn >> 12) >> size) << size; // determine the start offset, and use shifts to force alignment with a multiple of the size.
u32 end = start + (1<<size); // add 1 left shifted by size to start to determine end point
// dont need to bounds check the end point because the force alignment inherently prevents it from breaking
u8 usermask = 0;
u8 privmask = 0;
@ -239,7 +243,7 @@ void ARMv5::UpdatePURegion(u32 n)
"PU region %d: %08X-%08X, user=%02X priv=%02X, %08X/%08X\n",
n,
start << 12,
end << 12,
(end << 12) - 1,
usermask,
privmask,
PU_DataRW,
@ -579,12 +583,12 @@ void ARMv5::CP15Write(u32 id, u32 val)
std::snprintf(log_output,
sizeof(log_output),
"PU: region %d = %08X : %s, %08X-%08X\n",
"PU: region %d = %08X : %s, start: %08X size: %02X\n",
(id >> 4) & 0xF,
val,
val & 1 ? "enabled" : "disabled",
val & 0xFFFFF000,
(val & 0xFFFFF000) + (2 << ((val & 0x3E) >> 1))
(val & 0x3E) >> 1
);
Log(LogLevel::Debug, "%s", log_output);
// Some implementations of Log imply a newline, so we build up the line before printing it

View file

@ -110,6 +110,7 @@ bool FATStorage::InjectFile(const std::string& path, u8* data, u32 len)
res = f_mount(&fs, "0:", 1);
if (res != FR_OK)
{
f_unmount("0:");
ff_disk_close();
return false;
}
@ -146,6 +147,7 @@ u32 FATStorage::ReadFile(const std::string& path, u32 start, u32 len, u8* data)
res = f_mount(&fs, "0:", 1);
if (res != FR_OK)
{
f_unmount("0:");
ff_disk_close();
return false;
}
@ -1144,6 +1146,7 @@ bool FATStorage::Save()
res = f_mount(&fs, "0:", 1);
if (res != FR_OK)
{
f_unmount("0:");
ff_disk_close();
return false;
}

View file

@ -1845,7 +1845,7 @@ void NDS::debug(u32 param)
//for (int i = 0; i < 9; i++)
// printf("VRAM %c: %02X\n", 'A'+i, GPU->VRAMCNT[i]);
Platform::FileHandle* shit = Platform::OpenFile("debug/DSfirmware.bin", FileMode::Write);
Platform::FileHandle* shit = Platform::OpenFile("debug/pokeplat.bin", FileMode::Write);
Platform::FileWrite(ARM9.ITCM, 0x8000, 1, shit);
for (u32 i = 0x02000000; i < 0x02400000; i+=4)
{

View file

@ -159,11 +159,45 @@ void Wifi::Reset()
#undef BBREG_FIXED
const Firmware& fw = NDS.SPI.GetFirmware();
const auto& fwheader = fw.GetHeader();
RFVersion = fw.GetHeader().RFChipType;
RFVersion = fwheader.RFChipType;
memset(RFRegs, 0, 4*0x40);
Firmware::FirmwareConsoleType console = fw.GetHeader().ConsoleType;
// load channel index/data from the firmware
// the current channel will be determined by RF settings
// so we compare the two 'most important' RF registers to these values to figure out which channel is selected
if (RFVersion == 3)
{
RFChannelIndex[0] = fwheader.Type3Config.RFIndex1;
RFChannelIndex[1] = fwheader.Type3Config.RFIndex2;
for (int i = 0; i < 14; i++)
{
RFChannelData[i][0] = fwheader.Type3Config.RFData1[i];
RFChannelData[i][1] = fwheader.Type3Config.RFData2[i];
}
}
else
{
RFChannelIndex[0] = fwheader.Type2Config.InitialRF56Values[2] >> 2;
RFChannelIndex[1] = fwheader.Type2Config.InitialRF56Values[5] >> 2;
for (int i = 0; i < 14; i++)
{
RFChannelData[i][0] = fwheader.Type2Config.InitialRF56Values[i*6 + 0] |
(fwheader.Type2Config.InitialRF56Values[i*6 + 1] << 8) |
((fwheader.Type2Config.InitialRF56Values[i*6 + 2] & 0x03) << 16);
RFChannelData[i][1] = fwheader.Type2Config.InitialRF56Values[i*6 + 3] |
(fwheader.Type2Config.InitialRF56Values[i*6 + 4] << 8) |
((fwheader.Type2Config.InitialRF56Values[i*6 + 5] & 0x03) << 16);
}
}
CurChannel = 0;
Firmware::FirmwareConsoleType console = fwheader.ConsoleType;
if (console == Firmware::FirmwareConsoleType::DS)
IOPORT(0x000) = 0x1440;
else if (console == Firmware::FirmwareConsoleType::DSLite)
@ -182,6 +216,8 @@ void Wifi::Reset()
// TODO: find out what the initial values are
IOPORT(W_PowerUS) = 0x0001;
//IOPORT(W_BeaconInterval) = 100;
USTimestamp = 0;
USCounter = 0;
@ -209,7 +245,6 @@ void Wifi::Reset()
CmdCounter = 0;
USUntilPowerOn = 0;
ForcePowerOn = false;
IsMP = false;
IsMPClient = false;
@ -244,6 +279,8 @@ void Wifi::DoSavestate(Savestate* file)
file->Var8(&RFVersion);
file->VarArray(RFRegs, 4*0x40);
file->Var32((u32*)&CurChannel);
file->Var64(&USCounter);
file->Var64(&USCompare);
file->Bool32(&BlockBeaconIRQ14);
@ -285,7 +322,6 @@ void Wifi::DoSavestate(Savestate* file)
file->Var16(&MPLastSeqno);
file->Var32((u32*)&USUntilPowerOn);
file->Bool32(&ForcePowerOn);
file->Bool32(&IsMP);
file->Bool32(&IsMPClient);
@ -351,33 +387,38 @@ void Wifi::SetPowerCnt(u32 val)
}
void Wifi::SetIRQ(u32 irq)
void Wifi::CheckIRQ(u16 oldflags)
{
u32 oldflags = IOPORT(W_IF) & IOPORT(W_IE);
IOPORT(W_IF) |= (1<<irq);
u32 newflags = IOPORT(W_IF) & IOPORT(W_IE);
u16 newflags = IOPORT(W_IF) & IOPORT(W_IE);
if ((oldflags == 0) && (newflags != 0))
NDS.SetIRQ(1, IRQ_Wifi);
}
void Wifi::SetIRQ(u32 irq)
{
u16 oldflags = IOPORT(W_IF) & IOPORT(W_IE);
IOPORT(W_IF) |= (1<<irq);
CheckIRQ(oldflags);
}
void Wifi::SetIRQ13()
{
SetIRQ(13);
if (!(IOPORT(W_PowerTX) & 0x0002))
if ((IOPORT(W_ModeWEP) & 0x7) != 3)
{
IOPORT(0x034) = 0x0002;
//PowerDown();
// FIXME!!
IOPORT(W_RFPins) = 0x0046;
IOPORT(W_RFStatus) = 9;
if (!(IOPORT(W_PowerTX) & (1<<1)))
{
UpdatePowerStatus(-1);
}
}
}
void Wifi::SetIRQ14(int source) // 0=USCOMPARE 1=BEACONCOUNT 2=forced
{
// CHECKME: is this also done for USCOMPARE IRQ?
if (source != 2)
IOPORT(W_BeaconCount1) = IOPORT(W_BeaconInterval);
@ -409,10 +450,10 @@ void Wifi::SetIRQ15()
{
SetIRQ(15);
if (IOPORT(W_PowerTX) & 0x0001)
// unlike auto sleep, auto wakeup works under all power management modes
if (IOPORT(W_PowerTX) & (1<<0))
{
IOPORT(W_RFPins) |= 0x0080;
IOPORT(W_RFStatus) = 1;
UpdatePowerStatus(1);
}
}
@ -426,16 +467,110 @@ void Wifi::SetStatus(u32 status)
}
void Wifi::PowerDown()
void Wifi::UpdatePowerStatus(int power) // 1=on 0=no change -1=off
{
IOPORT(W_TXReqRead) &= ~0x000F;
IOPORT(W_PowerState) |= 0x0200;
// TRANSCEIVER POWER MANAGEMENT
//
// * W_PowerForce overrides all else
// * W_ModeReset bit0 forcibly turns off the transceiver when cleared
// * power is normally turned on or off either by IRQ15/IRQ13 or by W_PowerState
// depending on the power management mode selected in W_ModeWEP
// * W_PowerDownCtrl controls how deep a regular power-down is
// if the RF hardware is powered down while still sending or receiving,
// the current frame is completed before going idle
if (!ComStatus)
int curflags = 0;
if (IOPORT(W_TRXPower) == 1) curflags |= 1;
if (!(IOPORT(W_PowerState) & (1<<9))) curflags |= 2;
int reqflags = curflags;
if (IOPORT(W_PowerForce) & (1<<15))
{
SetStatus(9);
reqflags = (IOPORT(W_PowerForce) & (1<<0)) ? 0 : 3;
}
else if (!(IOPORT(W_ModeReset) & (1<<0)))
{
reqflags = 0;
}
else
{
if (power == 0)
{
if ((IOPORT(W_PowerState) & 0x0202) == 0x0202)
power = 1;
else if ((IOPORT(W_PowerState) & 0x0201) == 0x0001)
power = -1;
}
// W_PowerDownCtrl:
// * bit 0 inhibits a regular power-down
// * bit 1 forces a wakeup, atleast partial
if ((power == -1) && (IOPORT(W_PowerDownCtrl) & (1<<0)))
power = 0;
/*if (power == 1)
reqflags = 3;
else if (power == -1)
reqflags = IOPORT(W_PowerDownCtrl);
else if (IOPORT(W_PowerDownCtrl) & (1<<1))
reqflags = (curflags == 3) ? 3 : IOPORT(W_PowerDownCtrl);*/
// TODO: support partial power statuses (W_PowerDownCtrl=1 or 2)
if (power == 1)
reqflags = 3;
else if (power == -1)
reqflags = IOPORT(W_PowerDownCtrl) ? 3 : 0;
else if (IOPORT(W_PowerDownCtrl) & (1<<1))
reqflags = 3;
}
if (reqflags == curflags)
return;
if (reqflags & 1)
{
if (!(curflags & 1))
{
IOPORT(W_TRXPower) = 1;
SetStatus(1);
}
}
else
{
// signal the transceiver is going to turn off (checkme)
IOPORT(W_TRXPower) = 2;
if (!ComStatus)
{
IOPORT(W_TRXPower) = 0;
SetStatus(9);
}
}
if (reqflags & 2)
{
// power on
IOPORT(W_PowerState) |= (1<<8);
if ((!(curflags & 2)) && (USUntilPowerOn == 0))
{
Log(LogLevel::Debug, "wifi: TRX power ON\n");
USUntilPowerOn = -2048;
SetIRQ(11);
}
}
else
{
// power off
if (curflags & 2)
Log(LogLevel::Debug, "wifi: TRX power OFF\n");
IOPORT(W_PowerState) &= ~(1<<0);
IOPORT(W_PowerState) &= ~(1<<8);
IOPORT(W_PowerState) |= (1<<9);
USUntilPowerOn = 0;
}
}
@ -521,6 +656,9 @@ void Wifi::TXSendFrame(const TXSlot* slot, int num)
if (noseqno == 2)
*(u16*)&TXBuffer[0xC] |= (1<<11);
if (CurChannel == 0) return;
TXBuffer[9] = CurChannel;
switch (num)
{
case 0:
@ -600,6 +738,9 @@ void Wifi::StartTX_Cmd()
slot->CurPhase = 13;
slot->CurPhaseTime = CmdCounter - 100;
}
// starting a CMD transfer wakes up the transceiver automatically
UpdatePowerStatus(1);
}
void Wifi::StartTX_Beacon()
@ -678,6 +819,9 @@ void Wifi::SendMPDefaultReply()
// TODO
reply[0x8] = 0x14;
if (CurChannel == 0) return;
reply[0x9] = CurChannel;
*(u16*)&reply[0xC + 0x00] = 0x0158;
*(u16*)&reply[0xC + 0x02] = 0x00F0;//0; // TODO??
*(u16*)&reply[0xC + 0x04] = IOPORT(W_BSSID0);
@ -767,6 +911,9 @@ void Wifi::SendMPAck(u16 cmdcount, u16 clientfail)
if (TXSlots[1].Rate == 2) ack[0x8] = 0x14;
else ack[0x8] = 0xA;
if (CurChannel == 0) return;
ack[0x9] = CurChannel;
*(u16*)&ack[0xC + 0x00] = 0x0218;
*(u16*)&ack[0xC + 0x02] = 0;
*(u16*)&ack[0xC + 0x04] = 0x0903;
@ -1110,8 +1257,11 @@ void Wifi::FinishRX()
if (!ComStatus)
{
if (IOPORT(W_PowerState) & 0x0300)
if (IOPORT(W_PowerState) & (1<<9))
{
IOPORT(W_TRXPower) = 0;
SetStatus(9);
}
else
SetStatus(1);
}
@ -1380,7 +1530,7 @@ void Wifi::FinishRX()
void Wifi::MPClientReplyRX(int client)
{
if (IOPORT(W_PowerState) & 0x0300)
if (IOPORT(W_PowerState) & (1<<9))
return;
if (!(IOPORT(W_RXCnt) & 0x8000))
@ -1421,7 +1571,7 @@ void Wifi::MPClientReplyRX(int client)
bool Wifi::CheckRX(int type) // 0=regular 1=MP replies 2=MP host frames
{
if (IOPORT(W_PowerState) & 0x0300)
if (IOPORT(W_PowerState) & (1<<9))
return false;
if (!(IOPORT(W_RXCnt) & 0x8000))
@ -1433,7 +1583,7 @@ bool Wifi::CheckRX(int type) // 0=regular 1=MP replies 2=MP host frames
int rxlen;
int framelen;
u16 framectl;
u8 txrate;
u8 txrate, chan;
u64 timestamp;
for (;;)
@ -1468,6 +1618,24 @@ bool Wifi::CheckRX(int type) // 0=regular 1=MP replies 2=MP host frames
continue;
}
chan = RXBuffer[9];
if (chan != CurChannel || CurChannel == 0)
{
Log(LogLevel::Debug, "received frame but bad channel %d (expected %d)\n", chan, CurChannel);
continue;
}
// hack: ignore MP frames if not engaged in a MP comm
if (type == 0 && (!IsMP))
{
if (MACEqual(&RXBuffer[12 + 16], MPReplyMAC) ||
MACEqual(&RXBuffer[12 + 4], MPCmdMAC) ||
MACEqual(&RXBuffer[12 + 4], MPReplyMAC))
{
continue;
}
}
framectl = *(u16*)&RXBuffer[12+0];
txrate = RXBuffer[8];
@ -1528,7 +1696,6 @@ bool Wifi::CheckRX(int type) // 0=regular 1=MP replies 2=MP host frames
// we also need to determine how far we can run after having received this frame
RXTimestamp = timestamp;
//if (RXTimestamp < USTimestamp) printf("CRAP!! %04X %016llX %016llX\n", framectl, RXTimestamp, USTimestamp);
if (RXTimestamp < USTimestamp) RXTimestamp = USTimestamp;
NextSync = RXTimestamp + (framelen * (txrate==0x14 ? 4:8));
@ -1570,11 +1737,13 @@ void Wifi::MSTimer()
}
}
IOPORT(W_BeaconCount1)--;
if (IOPORT(W_BeaconCount1) == 0)
if (IOPORT(W_BeaconCount1) != 0)
{
SetIRQ14(1);
IOPORT(W_BeaconCount1)--;
if (IOPORT(W_BeaconCount1) == 0) SetIRQ14(1);
}
if (IOPORT(W_BeaconCount1) == 0)
IOPORT(W_BeaconCount1) = IOPORT(W_BeaconInterval);
if (IOPORT(W_BeaconCount2) != 0)
{
@ -1605,19 +1774,19 @@ void Wifi::USTimer(u32 param)
if (!(USTimestamp & 0x3FF & kTimeCheckMask))
WifiAP->MSTimer();
bool switchOffPowerSaving = false;
if (USUntilPowerOn < 0)
{
USUntilPowerOn += kTimerInterval;
switchOffPowerSaving = (USUntilPowerOn >= 0) && (IOPORT(W_PowerUnk) & 0x0001 || ForcePowerOn);
}
if ((USUntilPowerOn >= 0) && (IOPORT(W_PowerState) & 0x0002 || switchOffPowerSaving))
{
IOPORT(W_PowerState) = 0;
IOPORT(W_RFPins) = 1;
IOPORT(W_RFPins) = 0x0084;
SetIRQ(11);
if (USUntilPowerOn >= 0)
{
USUntilPowerOn = 0;
IOPORT(W_PowerState) = 0;
SetStatus(1);
UpdatePowerStatus(0);
}
}
if (IOPORT(W_USCountCnt))
@ -1660,7 +1829,7 @@ void Wifi::USTimer(u32 param)
u16 txbusy = IOPORT(W_TXBusy);
if (txbusy)
{
if (IOPORT(W_PowerState) & 0x0300)
if (IOPORT(W_PowerState) & (1<<9))
{
ComStatus = 0;
TXCurSlot = -1;
@ -1695,9 +1864,10 @@ void Wifi::USTimer(u32 param)
bool finished = ProcessTX(&TXSlots[TXCurSlot], TXCurSlot);
if (finished)
{
if (IOPORT(W_PowerState) & 0x0300)
if (IOPORT(W_PowerState) & (1<<9))
{
IOPORT(W_TXBusy) = 0;
IOPORT(W_TRXPower) = 0;
SetStatus(9);
}
@ -1754,8 +1924,9 @@ void Wifi::USTimer(u32 param)
RXCounter = 0;
}
// TODO: proper error management
if ((!ComStatus) && (IOPORT(W_PowerState) & 0x0300))
if ((!ComStatus) && (IOPORT(W_PowerState) & (1<<9)))
{
IOPORT(W_TRXPower) = 0;
SetStatus(9);
}
}
@ -1766,6 +1937,28 @@ void Wifi::USTimer(u32 param)
}
void Wifi::ChangeChannel()
{
u32 val1 = RFRegs[RFChannelIndex[0]];
u32 val2 = RFRegs[RFChannelIndex[1]];
CurChannel = 0;
for (int i = 0; i < 14; i++)
{
if (val1 == RFChannelData[i][0] && val2 == RFChannelData[i][1])
{
CurChannel = i+1;
break;
}
}
if (CurChannel > 0)
Log(LogLevel::Debug, "wifi: switching to channel %d\n", CurChannel);
else
Log(LogLevel::Debug, "wifi: invalid channel values %05X:%05X\n", val1, val2);
}
void Wifi::RFTransfer_Type2()
{
u32 id = (IOPORT(W_RFData2) >> 2) & 0x1F;
@ -1780,6 +1973,9 @@ void Wifi::RFTransfer_Type2()
{
u32 data = IOPORT(W_RFData1) | ((IOPORT(W_RFData2) & 0x0003) << 16);
RFRegs[id] = data;
if (id == RFChannelIndex[0] || id == RFChannelIndex[1])
ChangeChannel();
}
}
@ -1796,6 +1992,9 @@ void Wifi::RFTransfer_Type3()
{
u32 data = IOPORT(W_RFData1) & 0xFF;
RFRegs[id] = data;
if (id == RFChannelIndex[0] || id == RFChannelIndex[1])
ChangeChannel();
}
}
@ -1819,6 +2018,7 @@ u16 Wifi::Read(u32 addr)
switch (addr)
{
case W_Random: // random generator. not accurate
// TODO: rotate the sequence based on the ARM7 cycle counter (if this is important)
Random = (Random & 0x1) ^ (((Random & 0x3FF) << 1) | (Random >> 10));
return Random;
@ -1899,7 +2099,6 @@ u16 Wifi::Read(u32 addr)
}
}
//printf("WIFI: read %08X\n", addr);
return IOPORT(addr&0xFFF);
}
@ -1923,28 +2122,20 @@ void Wifi::Write(u32 addr, u16 val)
case W_ModeReset:
{
u16 oldval = IOPORT(W_ModeReset);
IOPORT(W_ModeReset) = val & 0x0001;
if (!(oldval & 0x0001) && (val & 0x0001))
{
if (!(USUntilPowerOn < 0 && ForcePowerOn))
{
//printf("mode reset power on %08x\n", NDS::ARM7->R[15]);
IOPORT(0x034) = 0x0002;
IOPORT(0x27C) = 0x0005;
// TODO: 02A2??
IOPORT(0x27C) = 0x0005;
// TODO: 02A2??
if (IOPORT(W_PowerUnk) & 0x0002)
{
USUntilPowerOn = -2048;
IOPORT(W_PowerState) |= 0x100;
}
}
UpdatePowerStatus(0);
}
else if ((oldval & 0x0001) && !(val & 0x0001))
{
//printf("mode reset shutdown %08x\n", NDS::ARM7->R[15]);
IOPORT(0x27C) = 0x000A;
PowerDown();
UpdatePowerStatus(0);
}
if (val & 0x2000)
@ -1986,23 +2177,43 @@ void Wifi::Write(u32 addr, u16 val)
IOPORT(0x230) = 0x0047;
}
}
break;
return;
case W_ModeWEP:
val &= 0x007F;
//printf("writing mode web %x\n", val);
if ((val & 0x7) == 1)
IOPORT(W_PowerUnk) |= 0x0002;
if ((val & 0x7) == 2)
IOPORT(W_PowerUnk) = 0x0003;
break;
IOPORT(W_ModeWEP) = val;
if (IOPORT(W_PowerTX) & (1<<1))
{
if ((val & 0x7) == 1)
IOPORT(W_PowerDownCtrl) |= (1<<1);
else if ((val & 0x7) == 2)
IOPORT(W_PowerDownCtrl) = 3;
if ((val & 0x7) != 3)
IOPORT(W_PowerState) &= 0x0300;
UpdatePowerStatus(0);
}
return;
case W_IE:
{
u16 oldflags = IOPORT(W_IF) & IOPORT(W_IE);
IOPORT(W_IE) = val;
CheckIRQ(oldflags);
}
return;
case W_IF:
IOPORT(W_IF) &= ~val;
return;
case W_IFSet:
IOPORT(W_IF) |= (val & 0xFBFF);
Log(LogLevel::Debug, "wifi: force-setting IF %04X\n", val);
{
u16 oldflags = IOPORT(W_IF) & IOPORT(W_IE);
IOPORT(W_IF) |= (val & 0xFBFF);
CheckIRQ(oldflags);
Log(LogLevel::Debug, "wifi: force-setting IF %04X\n", val);
}
return;
case W_AIDLow:
@ -2012,67 +2223,63 @@ void Wifi::Write(u32 addr, u16 val)
IOPORT(W_AIDFull) = val & 0x07FF;
return;
case W_PowerState:
//printf("writing power state %x %08x\n", val, NDS::ARM7->R[15]);
IOPORT(W_PowerState) |= val & 0x0002;
if (IOPORT(W_ModeReset) & 0x0001 && IOPORT(W_PowerState) & 0x0002)
{
/*if (IOPORT(W_PowerState) & 0x100)
{
AlwaysPowerOn = true;
USUntilPowerOn = -1;
}
else */
if (IOPORT(W_PowerForce) == 1)
{
//printf("power on\n");
IOPORT(W_PowerState) |= 0x100;
USUntilPowerOn = -2048;
ForcePowerOn = false;
}
}
return;
case W_PowerForce:
//if ((val&0x8001)==0x8000) printf("WIFI: forcing power %04X\n", val);
val &= 0x8001;
//printf("writing power force %x %08x\n", val, NDS::ARM7->R[15]);
if (val == 0x8001)
{
//printf("force power off\n");
IOPORT(0x034) = 0x0002;
IOPORT(W_PowerState) = 0x0200;
IOPORT(W_TXReqRead) = 0;
PowerDown();
}
if (val == 1 && IOPORT(W_PowerState) & 0x0002)
{
//printf("power on\n");
IOPORT(W_PowerState) |= 0x100;
USUntilPowerOn = -2048;
ForcePowerOn = false;
}
if (val == 0x8000)
{
//printf("force power on\n");
IOPORT(W_PowerState) |= 0x100;
USUntilPowerOn = -2048;
ForcePowerOn = true;
}
break;
case W_PowerUS:
IOPORT(W_PowerUS) = val & 0x0003;
UpdatePowerOn();
return;
case W_PowerUnk:
val &= 0x0003;
//printf("writing power unk %x\n", val);
if ((IOPORT(W_ModeWEP) & 0x7) == 1)
val |= 2;
else if ((IOPORT(W_ModeWEP) & 0x7) == 2)
val = 3;
break;
case W_PowerTX:
IOPORT(W_PowerTX) = val & 0x0003;
if (val & (1<<1))
{
if ((IOPORT(W_ModeWEP) & 0x7) == 1)
IOPORT(W_PowerDownCtrl) |= (1<<1);
else if ((IOPORT(W_ModeWEP) & 0x7) == 2)
IOPORT(W_PowerDownCtrl) = 3;
UpdatePowerStatus(0);
}
return;
case W_PowerState:
if ((IOPORT(W_ModeWEP) & 0x7) != 3)
return;
val = (IOPORT(W_PowerState) & 0x0300) | (val & 0x0003);
if ((val & 0x0300) == 0x0200)
val &= ~(1<<0);
else
val &= ~(1<<1);
if (!(val & (1<<9)))
val &= ~(1<<8);
IOPORT(W_PowerState) = val;
UpdatePowerStatus(0);
return;
case W_PowerForce:
val &= 0x8001;
IOPORT(W_PowerForce) = val;
UpdatePowerStatus(0);
return;
case W_PowerDownCtrl:
IOPORT(W_PowerDownCtrl) = val & 0x0003;
if (IOPORT(W_PowerTX) & (1<<1))
{
if ((IOPORT(W_ModeWEP) & 0x7) == 1)
IOPORT(W_PowerDownCtrl) |= (1<<1);
else if ((IOPORT(W_ModeWEP) & 0x7) == 2)
IOPORT(W_PowerDownCtrl) = 3;
}
if (val != 0 && val != 3)
Log(LogLevel::Warn, "wifi: unusual W_PowerDownCtrl value %04X\n", val);
UpdatePowerStatus(0);
return;
case W_USCountCnt: val &= 0x0001; break;
case W_USCompareCnt:
@ -2231,6 +2438,7 @@ void Wifi::Write(u32 addr, u16 val)
// read-only ports
case 0x000:
case 0x034:
case 0x044:
case 0x054:
case 0x098:

View file

@ -52,11 +52,12 @@ public:
W_RXCnt = 0x030,
W_WEPCnt = 0x032,
W_TRXPower = 0x034,
W_PowerUS = 0x036,
W_PowerTX = 0x038,
W_PowerState = 0x03C,
W_PowerForce = 0x040,
W_PowerUnk = 0x48,
W_PowerDownCtrl = 0x48,
W_Random = 0x044,
@ -206,6 +207,10 @@ private:
u8 RFVersion;
u32 RFRegs[0x40];
u32 RFChannelIndex[2];
u32 RFChannelData[14][2];
int CurChannel;
struct TXSlot
{
bool Valid;
@ -240,7 +245,6 @@ private:
bool LANInited;
int USUntilPowerOn;
bool ForcePowerOn;
// MULTIPLAYER SYNC APPARATUS
bool IsMP;
@ -253,13 +257,15 @@ private:
void ScheduleTimer(bool first);
void UpdatePowerOn();
void CheckIRQ(u16 oldflags);
void SetIRQ(u32 irq);
void SetIRQ13();
void SetIRQ14(int source);
void SetIRQ15();
void SetStatus(u32 status);
void PowerDown();
void UpdatePowerStatus(int power);
int PreambleLen(int rate) const;
u32 NumClients(u16 bitmask) const;
@ -284,6 +290,8 @@ private:
void MSTimer();
void ChangeChannel();
void RFTransfer_Type2();
void RFTransfer_Type3();
};

View file

@ -35,6 +35,7 @@ using Platform::LogLevel;
const char* WifiAP::APName = "melonAP";
const u8 WifiAP::APMac[6] = {0x00, 0xF0, 0x77, 0x77, 0x77, 0x77};
const u8 WifiAP::APChannel = 6;
#define PWRITE_8(p, v) *p++ = v;
#define PWRITE_16(p, v) *(u16*)p = v; p += 2;
@ -55,7 +56,7 @@ const u8 WifiAP::APMac[6] = {0x00, 0xF0, 0x77, 0x77, 0x77, 0x77};
PWRITE_16(p, 0); \
PWRITE_16(p, 0); \
PWRITE_8(p, rate); \
PWRITE_8(p, 0); \
PWRITE_8(p, APChannel); \
PWRITE_16(p, len);
//#define PALIGN_4(p, base) p += ((4 - ((ptrdiff_t)(p-base) & 0x3)) & 0x3);
@ -174,7 +175,7 @@ int WifiAP::HandleManagementFrame(const u8* data, int len)
PWRITE_16(p, 128); // beacon interval
PWRITE_16(p, 0x0021); // capability
PWRITE_8(p, 0x01); PWRITE_8(p, 0x02); PWRITE_8(p, 0x82); PWRITE_8(p, 0x84); // rates
PWRITE_8(p, 0x03); PWRITE_8(p, 0x01); PWRITE_8(p, 0x06); // current channel
PWRITE_8(p, 0x03); PWRITE_8(p, 0x01); PWRITE_8(p, APChannel); // current channel
PWRITE_8(p, 0x00); PWRITE_8(p, strlen(APName));
memcpy(p, APName, strlen(APName)); p += strlen(APName);
@ -260,6 +261,9 @@ int WifiAP::HandleManagementFrame(const u8* data, int len)
int WifiAP::SendPacket(const u8* data, int len)
{
if (data[9] != APChannel)
return 0;
data += 12;
u16 framectl = *(u16*)&data[0];
@ -327,7 +331,7 @@ int WifiAP::RecvPacket(u8* data)
PWRITE_16(p, 128); // beacon interval
PWRITE_16(p, 0x0021); // capability
PWRITE_8(p, 0x01); PWRITE_8(p, 0x02); PWRITE_8(p, 0x82); PWRITE_8(p, 0x84); // rates
PWRITE_8(p, 0x03); PWRITE_8(p, 0x01); PWRITE_8(p, 0x06); // current channel
PWRITE_8(p, 0x03); PWRITE_8(p, 0x01); PWRITE_8(p, APChannel); // current channel
PWRITE_8(p, 0x05); PWRITE_8(p, 0x04); PWRITE_8(p, 0); PWRITE_8(p, 0); PWRITE_8(p, 0); PWRITE_8(p, 0); // TIM
PWRITE_8(p, 0x00); PWRITE_8(p, strlen(APName));
memcpy(p, APName, strlen(APName)); p += strlen(APName);

View file

@ -34,6 +34,7 @@ public:
static const char* APName;
static const u8 APMac[6];
static const u8 APChannel;
void MSTimer();

View file

@ -3,6 +3,7 @@
#define GDBSTUB_H_
#include <stddef.h>
#include <sys/types.h>
#include <map>
#include <vector>

View file

@ -209,16 +209,22 @@ void Process()
}
JoyInputMask = 0xFFF;
for (int i = 0; i < 12; i++)
if (JoystickButtonDown(Config::JoyMapping[i]))
JoyInputMask &= ~(1<<i);
if (Joystick)
{
for (int i = 0; i < 12; i++)
if (JoystickButtonDown(Config::JoyMapping[i]))
JoyInputMask &= ~(1 << i);
}
InputMask = KeyInputMask & JoyInputMask;
JoyHotkeyMask = 0;
for (int i = 0; i < HK_MAX; i++)
if (JoystickButtonDown(Config::HKJoyMapping[i]))
JoyHotkeyMask |= (1<<i);
if (Joystick)
{
for (int i = 0; i < HK_MAX; i++)
if (JoystickButtonDown(Config::HKJoyMapping[i]))
JoyHotkeyMask |= (1 << i);
}
HotkeyMask = KeyHotkeyMask | JoyHotkeyMask;
HotkeyPress = HotkeyMask & ~LastHotkeyMask;

View file

@ -642,7 +642,7 @@ Firmware GenerateFirmware(int type) noexcept
}
}
CustomizeFirmware(firmware);
CustomizeFirmware(firmware, true);
// If we don't have Wi-fi settings to load,
// then the defaults will have already been populated by the constructor.
@ -681,10 +681,7 @@ std::optional<Firmware> LoadFirmware(int type) noexcept
return std::nullopt;
}
if (Config::FirmwareOverrideSettings)
{
CustomizeFirmware(firmware);
}
CustomizeFirmware(firmware, Config::FirmwareOverrideSettings);
return firmware;
}
@ -951,8 +948,8 @@ u32 DecompressROM(const u8* inContent, const u32 inSize, unique_ptr<u8[]>& outCo
if (realSize != ZSTD_CONTENTSIZE_UNKNOWN)
{
outContent = make_unique<u8[]>(realSize);
u64 decompressed = ZSTD_decompress(outContent.get(), realSize, inContent, inSize);
auto newOutContent = make_unique<u8[]>(realSize);
u64 decompressed = ZSTD_decompress(newOutContent.get(), realSize, inContent, inSize);
if (ZSTD_isError(decompressed))
{
@ -960,6 +957,7 @@ u32 DecompressROM(const u8* inContent, const u32 inSize, unique_ptr<u8[]>& outCo
return 0;
}
outContent = std::move(newOutContent);
return realSize;
}
else
@ -1014,7 +1012,6 @@ u32 DecompressROM(const u8* inContent, const u32 inSize, unique_ptr<u8[]>& outCo
}
} while (inBuf.pos < inBuf.size);
ZSTD_freeDStream(dStream);
outContent = make_unique<u8[]>(outBuf.pos);
memcpy(outContent.get(), outBuf.dst, outBuf.pos);
@ -1120,54 +1117,59 @@ bool ParseMacAddress(void* data)
return false;
}
void CustomizeFirmware(Firmware& firmware) noexcept
void CustomizeFirmware(Firmware& firmware, bool overridesettings) noexcept
{
auto& currentData = firmware.GetEffectiveUserData();
// setting up username
std::string orig_username = Config::FirmwareUsername;
if (!orig_username.empty())
{ // If the frontend defines a username, take it. If not, leave the existing one.
std::u16string username = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(orig_username);
size_t usernameLength = std::min(username.length(), (size_t) 10);
currentData.NameLength = usernameLength;
memcpy(currentData.Nickname, username.data(), usernameLength * sizeof(char16_t));
}
auto language = static_cast<Firmware::Language>(Config::FirmwareLanguage);
if (language != Firmware::Language::Reserved)
{ // If the frontend specifies a language (rather than using the existing value)...
currentData.Settings &= ~Firmware::Language::Reserved; // ..clear the existing language...
currentData.Settings |= language; // ...and set the new one.
}
// setting up color
u8 favoritecolor = Config::FirmwareFavouriteColour;
if (favoritecolor != 0xFF)
if (overridesettings)
{
currentData.FavoriteColor = favoritecolor;
}
auto &currentData = firmware.GetEffectiveUserData();
u8 birthmonth = Config::FirmwareBirthdayMonth;
if (birthmonth != 0)
{ // If the frontend specifies a birth month (rather than using the existing value)...
currentData.BirthdayMonth = birthmonth;
}
// setting up username
std::string orig_username = Config::FirmwareUsername;
if (!orig_username.empty())
{ // If the frontend defines a username, take it. If not, leave the existing one.
std::u16string username = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(
orig_username);
size_t usernameLength = std::min(username.length(), (size_t) 10);
currentData.NameLength = usernameLength;
memcpy(currentData.Nickname, username.data(), usernameLength * sizeof(char16_t));
}
u8 birthday = Config::FirmwareBirthdayDay;
if (birthday != 0)
{ // If the frontend specifies a birthday (rather than using the existing value)...
currentData.BirthdayDay = birthday;
}
auto language = static_cast<Firmware::Language>(Config::FirmwareLanguage);
if (language != Firmware::Language::Reserved)
{ // If the frontend specifies a language (rather than using the existing value)...
currentData.Settings &= ~Firmware::Language::Reserved; // ..clear the existing language...
currentData.Settings |= language; // ...and set the new one.
}
// setup message
std::string orig_message = Config::FirmwareMessage;
if (!orig_message.empty())
{
std::u16string message = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(orig_message);
size_t messageLength = std::min(message.length(), (size_t) 26);
currentData.MessageLength = messageLength;
memcpy(currentData.Message, message.data(), messageLength * sizeof(char16_t));
// setting up color
u8 favoritecolor = Config::FirmwareFavouriteColour;
if (favoritecolor != 0xFF)
{
currentData.FavoriteColor = favoritecolor;
}
u8 birthmonth = Config::FirmwareBirthdayMonth;
if (birthmonth != 0)
{ // If the frontend specifies a birth month (rather than using the existing value)...
currentData.BirthdayMonth = birthmonth;
}
u8 birthday = Config::FirmwareBirthdayDay;
if (birthday != 0)
{ // If the frontend specifies a birthday (rather than using the existing value)...
currentData.BirthdayDay = birthday;
}
// setup message
std::string orig_message = Config::FirmwareMessage;
if (!orig_message.empty())
{
std::u16string message = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(
orig_message);
size_t messageLength = std::min(message.length(), (size_t) 26);
currentData.MessageLength = messageLength;
memcpy(currentData.Message, message.data(), messageLength * sizeof(char16_t));
}
}
MacAddress mac;
@ -1176,14 +1178,16 @@ void CustomizeFirmware(Firmware& firmware) noexcept
memcpy(&mac, header.MacAddr.data(), sizeof(MacAddress));
MacAddress configuredMac;
rep = ParseMacAddress(&configuredMac);
rep &= (configuredMac != MacAddress());
if (rep)
if (overridesettings)
{
mac = configuredMac;
MacAddress configuredMac;
rep = ParseMacAddress(&configuredMac);
rep &= (configuredMac != MacAddress());
if (rep)
{
mac = configuredMac;
}
}
int inst = Platform::InstanceID();
@ -1568,23 +1572,28 @@ QString GBACartLabel()
void ROMIcon(const u8 (&data)[512], const u16 (&palette)[16], u32 (&iconRef)[32*32])
{
int index = 0;
for (int i = 0; i < 4; i++)
u32 paletteRGBA[16];
for (int i = 0; i < 16; i++)
{
for (int j = 0; j < 4; j++)
u8 r = ((palette[i] >> 0) & 0x1F) * 255 / 31;
u8 g = ((palette[i] >> 5) & 0x1F) * 255 / 31;
u8 b = ((palette[i] >> 10) & 0x1F) * 255 / 31;
u8 a = i ? 255 : 0;
paletteRGBA[i] = r | (g << 8) | (b << 16) | (a << 24);
}
int count = 0;
for (int ytile = 0; ytile < 4; ytile++)
{
for (int xtile = 0; xtile < 4; xtile++)
{
for (int k = 0; k < 8; k++)
for (int ypixel = 0; ypixel < 8; ypixel++)
{
for (int l = 0; l < 8; l++)
for (int xpixel = 0; xpixel < 8; xpixel++)
{
u8 pal_index = index % 2 ? data[index/2] >> 4 : data[index/2] & 0x0F;
u8 r = ((palette[pal_index] >> 0) & 0x1F) * 255 / 31;
u8 g = ((palette[pal_index] >> 5) & 0x1F) * 255 / 31;
u8 b = ((palette[pal_index] >> 10) & 0x1F) * 255 / 31;
u8 a = pal_index ? 255: 0;
u32* row = &iconRef[256 * i + 32 * k + 8 * j];
row[l] = r | (g << 8) | (b << 16) | (a << 24);
index++;
u8 pal_index = count % 2 ? data[count/2] >> 4 : data[count/2] & 0x0F;
iconRef[ytile*256 + ypixel*32 + xtile*8 + xpixel] = paletteRGBA[pal_index];
count++;
}
}
}

View file

@ -67,7 +67,7 @@ std::optional<FATStorageArgs> GetDSiSDCardArgs() noexcept;
std::optional<FATStorage> LoadDSiSDCard() noexcept;
std::optional<FATStorageArgs> GetDLDISDCardArgs() noexcept;
std::optional<FATStorage> LoadDLDISDCard() noexcept;
void CustomizeFirmware(Firmware& firmware) noexcept;
void CustomizeFirmware(Firmware& firmware, bool overridesettings) noexcept;
Firmware GenerateFirmware(int type) noexcept;
/// Loads and customizes a firmware image based on the values in Config
std::optional<Firmware> LoadFirmware(int type) noexcept;

View file

@ -214,7 +214,7 @@ void ScreenPanel::mouseMoveEvent(QMouseEvent* event)
showCursor();
if (!(event->buttons() & Qt::LeftButton)) return;
//if (!(event->buttons() & Qt::LeftButton)) return;
if (!touching) return;
int x = event->pos().x();

View file

@ -805,7 +805,7 @@ void MainWindow::keyPressEvent(QKeyEvent* event)
if (event->isAutoRepeat()) return;
// TODO!! REMOVE ME IN RELEASE BUILDS!!
//if (event->key() == Qt::Key_F11) NDS::debug(0);
//if (event->key() == Qt::Key_F11) emuThread->NDS->debug(0);
Input::KeyPress(event);
}

View file

@ -1,7 +1,11 @@
{
"dependencies": [
"sdl2",
"libarchive",
{
"name": "libarchive",
"default-features": false,
"features": ["bzip2", "crypto", "lz4", "zstd"]
},
"libslirp",
"zstd",
{