| ... | ... |
@@ -38,18 +38,13 @@ GameInfo gameInfo; |
| 38 | 38 |
NDSSystem nds; |
| 39 | 39 |
static std::unique_ptr<CFIRMWARE> firmware; |
| 40 | 40 |
|
| 41 |
-namespace DLDI |
|
| 42 |
-{
|
|
| 43 |
- bool tryPatch(void *data, size_t size); |
|
| 44 |
-} |
|
| 45 |
- |
|
| 46 | 41 |
int NDS_Init() |
| 47 | 42 |
{
|
| 48 | 43 |
MMU_Init(); |
| 49 | 44 |
nds.VCount = 0; |
| 50 | 45 |
|
| 51 | 46 |
// got to print this somewhere.. |
| 52 |
- printf("%s\n", EMU_DESMUME_NAME_AND_VERSION());
|
|
| 47 |
+ fprintf(stderr, "%s\n", EMU_DESMUME_NAME_AND_VERSION()); |
|
| 53 | 48 |
|
| 54 | 49 |
armcpu_new(&NDS_ARM7, 1); |
| 55 | 50 |
armcpu_new(&NDS_ARM9, 0); |
| ... | ... |
@@ -230,7 +225,7 @@ template<int procnum, int num> struct TSequenceItem_Timer : public TSequenceItem |
| 230 | 225 |
} |
| 231 | 226 |
#ifndef NDEBUG |
| 232 | 227 |
if (ctr > 1) |
| 233 |
- printf("yikes!!!!! please report!\n");
|
|
| 228 |
+ fprintf(stderr, "yikes!!!!! please report!\n"); |
|
| 234 | 229 |
#endif |
| 235 | 230 |
} |
| 236 | 231 |
|
| ... | ... |
@@ -267,7 +262,7 @@ template<int procnum, int chan> struct TSequenceItem_DMA : public TSequenceItem |
| 267 | 262 |
|
| 268 | 263 |
void exec() |
| 269 | 264 |
{
|
| 270 |
- //printf("exec from TSequenceItem_DMA: %d %d\n",procnum,chan);
|
|
| 265 |
+ //fprintf(stderr, "exec from TSequenceItem_DMA: %d %d\n",procnum,chan); |
|
| 271 | 266 |
this->controller->exec(); |
| 272 | 267 |
} |
| 273 | 268 |
}; |
| ... | ... |
@@ -453,7 +448,7 @@ static void execHardware_hstart_vblankEnd() |
| 453 | 448 |
|
| 454 | 449 |
static void execHardware_hstart_vblankStart() |
| 455 | 450 |
{
|
| 456 |
- //printf("--------VBLANK!!!--------\n");
|
|
| 451 |
+ //fprintf(stderr, "--------VBLANK!!!--------\n"); |
|
| 457 | 452 |
|
| 458 | 453 |
// fire vblank interrupts if necessary |
| 459 | 454 |
for (int i = 0; i < 2; ++i) |
| ... | ... |
@@ -794,7 +789,7 @@ template<bool FORCE> void NDS_exec(int32_t) |
| 794 | 789 |
uint64_t next = sequencer.findNext(); |
| 795 | 790 |
next = std::min(next, nds_timer + kMaxWork); // lets set an upper limit for now |
| 796 | 791 |
|
| 797 |
- //printf("%d\n", next - nds_timer);
|
|
| 792 |
+ //fprintf(stderr, "%d\n", next - nds_timer); |
|
| 798 | 793 |
|
| 799 | 794 |
sequencer.reschedule = false; |
| 800 | 795 |
|
| ... | ... |
@@ -838,7 +833,7 @@ template<int PROCNUM> static void execHardware_interrupts_core() |
| 838 | 833 |
|
| 839 | 834 |
if (masked && MMU.reg_IME[PROCNUM] && !ARMPROC.CPSR.bits.I) |
| 840 | 835 |
{
|
| 841 |
- //printf("Executing IRQ on procnum %d with IF = %08X and IE = %08X\n",PROCNUM,IF,IE);
|
|
| 836 |
+ //fprintf(stderr, "Executing IRQ on procnum %d with IF = %08X and IE = %08X\n",PROCNUM,IF,IE); |
|
| 842 | 837 |
armcpu_irqException(&ARMPROC); |
| 843 | 838 |
} |
| 844 | 839 |
} |
* Removed a couple files that were not being used.
* Cleanups found with clang's -Weverything (and shutting it up about a
lot of things that were ridiculous, as well as ignoring some of the
warnings still coming up).
| ... | ... |
@@ -36,9 +36,7 @@ TCommonSettings CommonSettings; |
| 36 | 36 |
|
| 37 | 37 |
GameInfo gameInfo; |
| 38 | 38 |
NDSSystem nds; |
| 39 |
-std::unique_ptr<CFIRMWARE> firmware; |
|
| 40 |
- |
|
| 41 |
-bool singleStep; |
|
| 39 |
+static std::unique_ptr<CFIRMWARE> firmware; |
|
| 42 | 40 |
|
| 43 | 41 |
namespace DLDI |
| 44 | 42 |
{
|
| ... | ... |
@@ -162,7 +160,7 @@ enum ESI_DISPCNT |
| 162 | 160 |
}; |
| 163 | 161 |
|
| 164 | 162 |
uint64_t nds_timer; |
| 165 |
-uint64_t nds_arm9_timer, nds_arm7_timer; |
|
| 163 |
+static uint64_t nds_arm9_timer, nds_arm7_timer; |
|
| 166 | 164 |
|
| 167 | 165 |
struct TSequenceItem |
| 168 | 166 |
{
|
| ... | ... |
@@ -170,6 +168,8 @@ struct TSequenceItem |
| 170 | 168 |
uint32_t param; |
| 171 | 169 |
bool enabled; |
| 172 | 170 |
|
| 171 |
+ virtual ~TSequenceItem() { }
|
|
| 172 |
+ |
|
| 173 | 173 |
virtual bool isTriggered() const |
| 174 | 174 |
{
|
| 175 | 175 |
return this->enabled && nds_timer >= this->timestamp; |
| ... | ... |
@@ -330,7 +330,7 @@ struct TSequenceItem_sqrtunit : public TSequenceItem |
| 330 | 330 |
} |
| 331 | 331 |
}; |
| 332 | 332 |
|
| 333 |
-struct Sequencer |
|
| 333 |
+static struct Sequencer |
|
| 334 | 334 |
{
|
| 335 | 335 |
bool nds_vblankEnded; |
| 336 | 336 |
bool reschedule; |
| ... | ... |
@@ -1010,7 +1010,6 @@ static void PrepareBiosARM9() |
| 1010 | 1010 |
|
| 1011 | 1011 |
void NDS_Reset() |
| 1012 | 1012 |
{
|
| 1013 |
- singleStep = false; |
|
| 1014 | 1013 |
bool fw_success = false; |
| 1015 | 1014 |
auto header = NDS_getROMHeader(); |
| 1016 | 1015 |
|
* [2SF] Used more up-to-date asmjit, despite the ugly looking code.
| ... | ... |
@@ -164,8 +164,6 @@ enum ESI_DISPCNT |
| 164 | 164 |
uint64_t nds_timer; |
| 165 | 165 |
uint64_t nds_arm9_timer, nds_arm7_timer; |
| 166 | 166 |
|
| 167 |
-static const uint64_t kNever = 0xFFFFFFFFFFFFFFFFULL; |
|
| 168 |
- |
|
| 169 | 167 |
struct TSequenceItem |
| 170 | 168 |
{
|
| 171 | 169 |
uint64_t timestamp; |
| ... | ... |
@@ -910,7 +908,7 @@ static void PrepareBiosARM9() |
| 910 | 908 |
{
|
| 911 | 909 |
// read arm9 bios from inputfile and flag it if it succeeds |
| 912 | 910 |
FILE *arm9inf = fopen(CommonSettings.ARM9BIOS, "rb"); |
| 913 |
- if (fread(MMU.ARM9_BIOS, 1, 4096, arm9inf) == 4096) |
|
| 911 |
+ if (fread(MMU.ARM9_BIOS, 1, 4096, arm9inf) == 4096) |
|
| 914 | 912 |
NDS_ARM9.BIOS_loaded = true; |
| 915 | 913 |
fclose(arm9inf); |
| 916 | 914 |
} |
| ... | ... |
@@ -919,7 +917,7 @@ static void PrepareBiosARM9() |
| 919 | 917 |
if (CommonSettings.SWIFromBIOS && NDS_ARM9.BIOS_loaded) |
| 920 | 918 |
{
|
| 921 | 919 |
NDS_ARM9.swi_tab = 0; |
| 922 |
- |
|
| 920 |
+ |
|
| 923 | 921 |
// if we used routines from bios, apply patches |
| 924 | 922 |
if (CommonSettings.PatchSWI3) |
| 925 | 923 |
_MMU_write16<ARMCPU_ARM9>(0xFFFF07CC, 0x4770); |
| ... | ... |
@@ -927,7 +925,7 @@ static void PrepareBiosARM9() |
| 927 | 925 |
else |
| 928 | 926 |
NDS_ARM9.swi_tab = ARM_swi_tab[ARMCPU_ARM9]; |
| 929 | 927 |
|
| 930 |
- if (!NDS_ARM9.BIOS_loaded) |
|
| 928 |
+ if (!NDS_ARM9.BIOS_loaded) |
|
| 931 | 929 |
{
|
| 932 | 930 |
// fake bios content, critical to normal operations, since we dont have a real bios. |
| 933 | 931 |
// it'd be cool if we could write this in some kind of assembly language, inline or otherwise, without some bulky dependencies |
| ... | ... |
@@ -1038,7 +1036,7 @@ void NDS_Reset() |
| 1038 | 1036 |
PrepareBiosARM7(); |
| 1039 | 1037 |
PrepareBiosARM9(); |
| 1040 | 1038 |
|
| 1041 |
- // according to smea, this is initialized to 3 by the time we get into a user game program. who does this? |
|
| 1039 |
+ // according to smea, this is initialized to 3 by the time we get into a user game program. who does this? |
|
| 1042 | 1040 |
// well, the firmware load process is about to write a boot program into SIWRAM for the arm7. so we need it setup by now. |
| 1043 | 1041 |
// but, this is a bit weird.. I would be expecting the bioses to do that. maybe we have some more detail to emulate. |
| 1044 | 1042 |
// * is this setting the default, or does the bios do it before loading the firmware programs? |
| ... | ... |
@@ -127,7 +127,7 @@ std::unique_ptr<NDS_header> NDS_getROMHeader() |
| 127 | 127 |
memcpy(header->logo, MMU.CART_ROM + 192, 156); |
| 128 | 128 |
header->logoCRC16 = T1ReadWord(MMU.CART_ROM, 348); |
| 129 | 129 |
header->headerCRC16 = T1ReadWord(MMU.CART_ROM, 350); |
| 130 |
- memcpy(header->reserved, MMU.CART_ROM + 352, std::min(160, static_cast<int>(gameInfo.romsize) - 352)); |
|
| 130 |
+ memcpy(header->reserved, MMU.CART_ROM + 352, std::min<size_t>(160, gameInfo.romsize - 352)); |
|
| 131 | 131 |
|
| 132 | 132 |
return header; |
| 133 | 133 |
} |
| ... | ... |
@@ -298,10 +298,10 @@ struct TSequenceItem_divider : public TSequenceItem |
| 298 | 298 |
T1WriteQuad(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A0, MMU.divResult); |
| 299 | 299 |
T1WriteQuad(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A8, MMU.divMod); |
| 300 | 300 |
#else |
| 301 |
- T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A0, static_cast<uint32_t>(MMU.divResult)); |
|
| 302 |
- T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A4, static_cast<uint32_t>(MMU.divResult >> 32)); |
|
| 303 |
- T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A8, static_cast<uint32_t>(MMU.divMod)); |
|
| 304 |
- T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2AC, static_cast<uint32_t>(MMU.divMod >> 32)); |
|
| 301 |
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A0, MMU.divResult & 0xFFFFFFFF); |
|
| 302 |
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A4, (MMU.divResult >> 32) & 0xFFFFFFFF); |
|
| 303 |
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A8, MMU.divMod & 0xFFFFFFFF); |
|
| 304 |
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2AC, (MMU.divMod >> 32) & 0xFFFFFFFF); |
|
| 305 | 305 |
#endif |
| 306 | 306 |
MMU.divRunning = false; |
| 307 | 307 |
} |
| ... | ... |
@@ -556,10 +556,10 @@ static void execHardware_hstart() |
| 556 | 556 |
} |
| 557 | 557 |
|
| 558 | 558 |
// write the new vcount |
| 559 |
- T1WriteWord(MMU.ARM9_REG, 6, static_cast<uint16_t>(nds.VCount)); |
|
| 560 |
- T1WriteWord(MMU.ARM9_REG, 0x1006, static_cast<uint16_t>(nds.VCount)); |
|
| 561 |
- T1WriteWord(MMU.ARM7_REG, 6, static_cast<uint16_t>(nds.VCount)); |
|
| 562 |
- T1WriteWord(MMU.ARM7_REG, 0x1006, static_cast<uint16_t>(nds.VCount)); |
|
| 559 |
+ T1WriteWord(MMU.ARM9_REG, 6, nds.VCount & 0xFFFF); |
|
| 560 |
+ T1WriteWord(MMU.ARM9_REG, 0x1006, nds.VCount & 0xFFFF); |
|
| 561 |
+ T1WriteWord(MMU.ARM7_REG, 6, nds.VCount & 0xFFFF); |
|
| 562 |
+ T1WriteWord(MMU.ARM7_REG, 0x1006, nds.VCount & 0xFFFF); |
|
| 563 | 563 |
|
| 564 | 564 |
// turn off hblank status bit |
| 565 | 565 |
T1WriteWord(MMU.ARM9_REG, 4, T1ReadWord(MMU.ARM9_REG, 4) & 0xFFFD); |
| ... | ... |
@@ -802,9 +802,9 @@ template<bool FORCE> void NDS_exec(int32_t) |
| 802 | 802 |
|
| 803 | 803 |
// cast these down to 32bits so that things run faster on 32bit procs |
| 804 | 804 |
uint64_t nds_timer_base = nds_timer; |
| 805 |
- int32_t arm9 = static_cast<int32_t>(nds_arm9_timer - nds_timer); |
|
| 806 |
- int32_t arm7 = static_cast<int32_t>(nds_arm7_timer - nds_timer); |
|
| 807 |
- int32_t s32next = static_cast<int32_t>(next - nds_timer); |
|
| 805 |
+ int32_t arm9 = (nds_arm9_timer - nds_timer) & 0xFFFFFFFF; |
|
| 806 |
+ int32_t arm7 = (nds_arm7_timer - nds_timer) & 0xFFFFFFFF; |
|
| 807 |
+ int32_t s32next = (next - nds_timer) & 0xFFFFFFFF; |
|
| 808 | 808 |
|
| 809 | 809 |
#ifdef HAVE_JIT |
| 810 | 810 |
auto arm9arm7 = CommonSettings.use_jit ? armInnerLoop<true, true, true>(nds_timer_base, s32next, arm9, arm7) : armInnerLoop<true, true, false>(nds_timer_base, s32next, arm9, arm7); |
| ... | ... |
@@ -1,6 +1,6 @@ |
| 1 | 1 |
/* |
| 2 | 2 |
Copyright (C) 2006 yopyop |
| 3 |
- Copyright (C) 2008-2012 DeSmuME team |
|
| 3 |
+ Copyright (C) 2008-2013 DeSmuME team |
|
| 4 | 4 |
|
| 5 | 5 |
This file is free software: you can redistribute it and/or modify |
| 6 | 6 |
it under the terms of the GNU General Public License as published by |
| ... | ... |
@@ -21,176 +21,72 @@ |
| 21 | 21 |
#include <cstdlib> |
| 22 | 22 |
#include <cmath> |
| 23 | 23 |
#include <zlib.h> |
| 24 |
- |
|
| 25 |
-#include "common.h" |
|
| 26 | 24 |
#include "NDSSystem.h" |
| 27 |
-//#include "render3D.h" |
|
| 28 | 25 |
#include "MMU.h" |
| 29 |
-//#include "ROMReader.h" |
|
| 30 |
-//#include "gfx3d.h" |
|
| 31 |
-//#include "utils/decrypt/decrypt.h" |
|
| 32 |
-//#include "utils/decrypt/crc.h" |
|
| 26 |
+#include "cp15.h" |
|
| 33 | 27 |
#include "bios.h" |
| 34 |
-//#include "debug.h" |
|
| 35 |
-//#include "cheatSystem.h" |
|
| 36 |
-//#include "movie.h" |
|
| 37 |
-//#include "Disassembler.h" |
|
| 38 | 28 |
#include "readwrite.h" |
| 39 |
-//#include "debug.h" |
|
| 40 | 29 |
#include "firmware.h" |
| 41 | 30 |
#include "version.h" |
| 42 | 31 |
#include "slot1.h" |
| 43 | 32 |
|
| 44 |
-#include "path.h" |
|
| 45 |
- |
|
| 46 |
-//#define LOG_ARM9 |
|
| 47 |
-//#define LOG_ARM7 |
|
| 48 |
-//bool dolog = false; |
|
| 49 |
-//#define LOG_TO_FILE |
|
| 50 |
-//#define LOG_TO_FILE_REGS |
|
| 51 |
- |
|
| 52 |
-//=============================================================== |
|
| 53 |
-//FILE *fp_dis7 = NULL; |
|
| 54 |
-//FILE *fp_dis9 = NULL; |
|
| 55 |
- |
|
| 56 |
-PathInfo path; |
|
| 33 |
+// =============================================================== |
|
| 57 | 34 |
|
| 58 | 35 |
TCommonSettings CommonSettings; |
| 59 |
-//static BaseDriver _stub_driver; |
|
| 60 |
-//BaseDriver* driver = &_stub_driver; |
|
| 61 |
-//std::string InputDisplayString; |
|
| 62 |
- |
|
| 63 |
-//static bool LidClosed = false; |
|
| 64 |
-//static uint8_t countLid = 0; |
|
| 65 | 36 |
|
| 66 | 37 |
GameInfo gameInfo; |
| 67 | 38 |
NDSSystem nds; |
| 68 |
-CFIRMWARE *firmware = NULL; |
|
| 69 |
-//ADVANsCEne advsc; |
|
| 39 |
+std::unique_ptr<CFIRMWARE> firmware; |
|
| 70 | 40 |
|
| 71 | 41 |
bool singleStep; |
| 72 |
-//bool nds_debug_continuing[2]; |
|
| 73 |
-//int lagframecounter; |
|
| 74 |
-//int LagFrameFlag; |
|
| 75 |
-//int lastLag; |
|
| 76 |
-//int TotalLagFrames; |
|
| 77 |
- |
|
| 78 |
-//TSCalInfo TSCal; |
|
| 79 | 42 |
|
| 80 | 43 |
namespace DLDI |
| 81 | 44 |
{
|
| 82 |
- bool tryPatch(void* data, size_t size); |
|
| 45 |
+ bool tryPatch(void *data, size_t size); |
|
| 83 | 46 |
} |
| 84 | 47 |
|
| 85 |
-/*void Desmume_InitOnce() |
|
| 48 |
+int NDS_Init() |
|
| 86 | 49 |
{
|
| 87 |
- static bool initOnce = false; |
|
| 88 |
- if(initOnce) return; |
|
| 89 |
- initOnce = true;*/ |
|
| 90 |
- |
|
| 91 |
-/*#ifdef HAVE_LIBAGG |
|
| 92 |
- extern void Agg_init(); //no need to include just for this |
|
| 93 |
- Agg_init(); |
|
| 94 |
-#endif*/ |
|
| 95 |
-//} |
|
| 96 |
- |
|
| 97 |
-#ifdef GDB_STUB |
|
| 98 |
-int NDS_Init( struct armcpu_memory_iface *arm9_mem_if, |
|
| 99 |
-struct armcpu_ctrl_iface **arm9_ctrl_iface, |
|
| 100 |
-struct armcpu_memory_iface *arm7_mem_if, |
|
| 101 |
-struct armcpu_ctrl_iface **arm7_ctrl_iface) {
|
|
| 102 |
-#else |
|
| 103 |
-int NDS_Init() {
|
|
| 104 |
-#endif |
|
| 105 |
- //nds.idleFrameCounter = 0; |
|
| 106 |
- //memset(nds.runCycleCollector,0,sizeof(nds.runCycleCollector)); |
|
| 107 | 50 |
MMU_Init(); |
| 108 | 51 |
nds.VCount = 0; |
| 109 | 52 |
|
| 110 |
- //got to print this somewhere.. |
|
| 53 |
+ // got to print this somewhere.. |
|
| 111 | 54 |
printf("%s\n", EMU_DESMUME_NAME_AND_VERSION());
|
| 112 | 55 |
|
| 113 |
- /*if (Screen_Init(GFXCORE_DUMMY) != 0) |
|
| 114 |
- return -1;*/ |
|
| 56 |
+ armcpu_new(&NDS_ARM7, 1); |
|
| 57 |
+ armcpu_new(&NDS_ARM9, 0); |
|
| 115 | 58 |
|
| 116 |
- //gfx3d_init(); |
|
| 117 |
- |
|
| 118 |
-#ifdef GDB_STUB |
|
| 119 |
- armcpu_new(&NDS_ARM7,1, arm7_mem_if, arm7_ctrl_iface); |
|
| 120 |
- armcpu_new(&NDS_ARM9,0, arm9_mem_if, arm9_ctrl_iface); |
|
| 121 |
-#else |
|
| 122 |
- armcpu_new(&NDS_ARM7,1); |
|
| 123 |
- armcpu_new(&NDS_ARM9,0); |
|
| 124 |
-#endif |
|
| 125 |
- |
|
| 126 |
- if (SPU_Init(SNDCORE_DUMMY, 740) != 0) |
|
| 59 |
+ if (SPU_Init(SNDCORE_DUMMY, 740)) |
|
| 127 | 60 |
return -1; |
| 128 | 61 |
|
| 129 |
- //WIFI_Init() ; |
|
| 130 |
- |
|
| 131 |
- // Init calibration info |
|
| 132 |
- //TSCal.adc.x1 = 0x0200; |
|
| 133 |
- //TSCal.adc.y1 = 0x0200; |
|
| 134 |
- //TSCal.scr.x1 = 0x20 + 1; // calibration screen coords are 1-based, |
|
| 135 |
- //TSCal.scr.y1 = 0x20 + 1; // either that or NDS_getADCTouchPosX/Y are wrong. |
|
| 136 |
- //TSCal.adc.x2 = 0x0E00; |
|
| 137 |
- //TSCal.adc.y2 = 0x0800; |
|
| 138 |
- //TSCal.scr.x2 = 0xE0 + 1; |
|
| 139 |
- //TSCal.scr.y2 = 0x80 + 1; |
|
| 140 |
- //TSCal.adc.width = (TSCal.adc.x2 - TSCal.adc.x1); |
|
| 141 |
- //TSCal.adc.height = (TSCal.adc.y2 - TSCal.adc.y1); |
|
| 142 |
- //TSCal.scr.width = (TSCal.scr.x2 - TSCal.scr.x1); |
|
| 143 |
- //TSCal.scr.height = (TSCal.scr.y2 - TSCal.scr.y1); |
|
| 144 |
- |
|
| 145 |
- //cheats = new CHEATS(); |
|
| 146 |
- //cheatSearch = new CHEATSEARCH(); |
|
| 147 |
- |
|
| 148 | 62 |
return 0; |
| 149 | 63 |
} |
| 150 | 64 |
|
| 151 |
-void NDS_DeInit() {
|
|
| 152 |
- if(MMU.CART_ROM != MMU.UNUSED_RAM) |
|
| 65 |
+void NDS_DeInit() |
|
| 66 |
+{
|
|
| 67 |
+ if (MMU.CART_ROM != MMU.UNUSED_RAM) |
|
| 153 | 68 |
NDS_FreeROM(); |
| 154 | 69 |
|
| 155 | 70 |
SPU_DeInit(); |
| 156 |
- //Screen_DeInit(); |
|
| 157 | 71 |
MMU_DeInit(); |
| 158 |
- //gpu3D->NDS_3D_Close(); |
|
| 159 |
- |
|
| 160 |
- //WIFI_DeInit(); |
|
| 161 |
- /*if (cheats) |
|
| 162 |
- delete cheats;*/ |
|
| 163 |
- /*if (cheatSearch) |
|
| 164 |
- delete cheatSearch;*/ |
|
| 165 | 72 |
|
| 166 |
-#ifdef LOG_ARM7 |
|
| 167 |
- if (fp_dis7 != NULL) |
|
| 168 |
- {
|
|
| 169 |
- fclose(fp_dis7); |
|
| 170 |
- fp_dis7 = NULL; |
|
| 171 |
- } |
|
| 172 |
-#endif |
|
| 173 |
- |
|
| 174 |
-#ifdef LOG_ARM9 |
|
| 175 |
- if (fp_dis9 != NULL) |
|
| 176 |
- {
|
|
| 177 |
- fclose(fp_dis9); |
|
| 178 |
- fp_dis9 = NULL; |
|
| 179 |
- } |
|
| 73 |
+#ifdef HAVE_JIT |
|
| 74 |
+ arm_jit_close(); |
|
| 180 | 75 |
#endif |
| 181 | 76 |
} |
| 182 | 77 |
|
| 183 |
-bool NDS_SetROM(uint8_t * rom, uint32_t mask) |
|
| 78 |
+bool NDS_SetROM(uint8_t *rom, uint32_t mask) |
|
| 184 | 79 |
{
|
| 185 | 80 |
MMU_setRom(rom, mask); |
| 186 | 81 |
|
| 187 | 82 |
return true; |
| 188 | 83 |
} |
| 189 | 84 |
|
| 190 |
-NDS_header * NDS_getROMHeader() |
|
| 85 |
+std::unique_ptr<NDS_header> NDS_getROMHeader() |
|
| 191 | 86 |
{
|
| 192 |
- if(MMU.CART_ROM == MMU.UNUSED_RAM) return NULL; |
|
| 193 |
- NDS_header * header = new NDS_header; |
|
| 87 |
+ if (MMU.CART_ROM == MMU.UNUSED_RAM) |
|
| 88 |
+ return std::unique_ptr<NDS_header>(); |
|
| 89 |
+ auto header = std::unique_ptr<NDS_header>(new NDS_header); |
|
| 194 | 90 |
|
| 195 | 91 |
memcpy(header->gameTile, MMU.CART_ROM, 12); |
| 196 | 92 |
memcpy(header->gameCode, MMU.CART_ROM + 12, 4); |
| ... | ... |
@@ -231,800 +127,34 @@ NDS_header * NDS_getROMHeader() |
| 231 | 127 |
memcpy(header->logo, MMU.CART_ROM + 192, 156); |
| 232 | 128 |
header->logoCRC16 = T1ReadWord(MMU.CART_ROM, 348); |
| 233 | 129 |
header->headerCRC16 = T1ReadWord(MMU.CART_ROM, 350); |
| 234 |
- memcpy(header->reserved, MMU.CART_ROM + 352, std::min(160, (int)gameInfo.romsize - 352)); |
|
| 130 |
+ memcpy(header->reserved, MMU.CART_ROM + 352, std::min(160, static_cast<int>(gameInfo.romsize) - 352)); |
|
| 235 | 131 |
|
| 236 | 132 |
return header; |
| 237 | 133 |
} |
| 238 | 134 |
|
| 239 |
- |
|
| 240 |
- |
|
| 241 |
- |
|
| 242 |
-/*void debug() |
|
| 243 |
-{
|
|
| 244 |
- //if(NDS_ARM9.R[15]==0x020520DC) emu_halt(); |
|
| 245 |
- //DSLinux |
|
| 246 |
- //if(NDS_ARM9.CPSR.bits.mode == 0) emu_halt(); |
|
| 247 |
- //if((NDS_ARM9.R[15]&0xFFFFF000)==0) emu_halt(); |
|
| 248 |
- //if((NDS_ARM9.R[15]==0x0201B4F4)&&(NDS_ARM9.R[1]==0x0)) emu_halt(); |
|
| 249 |
- //AOE |
|
| 250 |
- //if((NDS_ARM9.R[15]==0x01FFE194)&&(NDS_ARM9.R[0]==0)) emu_halt(); |
|
| 251 |
- //if((NDS_ARM9.R[15]==0x01FFE134)&&(NDS_ARM9.R[0]==0)) emu_halt(); |
|
| 252 |
- |
|
| 253 |
- //BBMAN |
|
| 254 |
- //if(NDS_ARM9.R[15]==0x02098B4C) emu_halt(); |
|
| 255 |
- //if(NDS_ARM9.R[15]==0x02004924) emu_halt(); |
|
| 256 |
- //if(NDS_ARM9.R[15]==0x02004890) emu_halt(); |
|
| 257 |
- |
|
| 258 |
- //if(NDS_ARM9.R[15]==0x0202B800) emu_halt(); |
|
| 259 |
- //if(NDS_ARM9.R[15]==0x0202B3DC) emu_halt(); |
|
| 260 |
- //if((NDS_ARM9.R[1]==0x9AC29AC1)&&(!fait)) {emu_halt();fait = true;}
|
|
| 261 |
- //if(NDS_ARM9.R[1]==0x0400004A) {emu_halt();fait = true;}
|
|
| 262 |
- if(NDS_ARM9.R[4]==0x2E33373C) emu_halt(); |
|
| 263 |
- if(NDS_ARM9.R[15]==0x02036668) //emu_halt(); |
|
| 264 |
- {
|
|
| 265 |
- nds.logcount++; |
|
| 266 |
- sprintf(logbuf, "%d %08X", nds.logcount, NDS_ARM9.R[13]); |
|
| 267 |
- log::ajouter(logbuf); |
|
| 268 |
- if(nds.logcount==89) execute=false; |
|
| 269 |
- } |
|
| 270 |
- //if(NDS_ARM9.instruction==0) emu_halt(); |
|
| 271 |
- //if((NDS_ARM9.R[15]>>28)) emu_halt(); |
|
| 272 |
-}*/ |
|
| 273 |
- |
|
| 274 |
-//#define DSGBA_LOADER_SIZE 512 |
|
| 275 |
-/*enum |
|
| 276 |
-{
|
|
| 277 |
- ROM_NDS = 0, |
|
| 278 |
- ROM_DSGBA |
|
| 279 |
-};*/ |
|
| 280 |
- |
|
| 281 |
-#if 0 /* not used */ |
|
| 282 |
-//http://www.aggregate.org/MAGIC/#Population%20Count%20(Ones%20Count) |
|
| 283 |
-static uint32_t ones32(uint32_t x) |
|
| 284 |
-{
|
|
| 285 |
- /* 32-bit recursive reduction using SWAR... |
|
| 286 |
- but first step is mapping 2-bit values |
|
| 287 |
- into sum of 2 1-bit values in sneaky way |
|
| 288 |
- */ |
|
| 289 |
- x -= ((x >> 1) & 0x55555555); |
|
| 290 |
- x = (((x >> 2) & 0x33333333) + (x & 0x33333333)); |
|
| 291 |
- x = (((x >> 4) + x) & 0x0f0f0f0f); |
|
| 292 |
- x += (x >> 8); |
|
| 293 |
- x += (x >> 16); |
|
| 294 |
- return x & 0x0000003f; |
|
| 295 |
-} |
|
| 296 |
-#endif |
|
| 297 |
- |
|
| 298 | 135 |
RomBanner::RomBanner(bool defaultInit) |
| 299 | 136 |
{
|
| 300 |
- if(!defaultInit) return; |
|
| 301 |
- version = 1; //Version (0001h) |
|
| 302 |
- crc16 = 0; //CRC16 across entries 020h..83Fh |
|
| 303 |
- memset(reserved,0,sizeof(reserved)); |
|
| 304 |
- memset(bitmap,0,sizeof(bitmap)); |
|
| 305 |
- memset(palette,0,sizeof(palette)); |
|
| 306 |
- memset(titles,0,sizeof(titles)); |
|
| 307 |
- memset(end0xFF,0,sizeof(end0xFF)); |
|
| 308 |
-} |
|
| 309 |
- |
|
| 310 |
-/*bool GameInfo::hasRomBanner() |
|
| 311 |
-{
|
|
| 312 |
- if(header.IconOff + sizeof(RomBanner) > romsize) |
|
| 313 |
- return false; |
|
| 314 |
- else return true; |
|
| 315 |
-}*/ |
|
| 316 |
- |
|
| 317 |
-/*const RomBanner& GameInfo::getRomBanner() |
|
| 318 |
-{
|
|
| 319 |
- //we may not have a valid banner. return a default one |
|
| 320 |
- if(!hasRomBanner()) |
|
| 321 |
- {
|
|
| 322 |
- static RomBanner defaultBanner(true); |
|
| 323 |
- return defaultBanner; |
|
| 324 |
- } |
|
| 325 |
- |
|
| 326 |
- return *(RomBanner*)(romdata+header.IconOff); |
|
| 327 |
-}*/ |
|
| 328 |
- |
|
| 329 |
-/*void GameInfo::populate() |
|
| 330 |
-{
|
|
| 331 |
- const char *regions[] = { "JPFSEDIRKH",
|
|
| 332 |
- "JPN", |
|
| 333 |
- "EUR", |
|
| 334 |
- "FRA", |
|
| 335 |
- "ESP", |
|
| 336 |
- "USA", |
|
| 337 |
- "NOE", |
|
| 338 |
- "ITA", |
|
| 339 |
- "RUS", |
|
| 340 |
- "KOR", |
|
| 341 |
- "HOL", |
|
| 342 |
- |
|
| 343 |
- }; |
|
| 344 |
- |
|
| 345 |
- NDS_header * _header = NDS_getROMHeader(); |
|
| 346 |
- header = *_header; |
|
| 347 |
- delete _header; |
|
| 348 |
- |
|
| 349 |
- memset(ROMserial, 0, sizeof(ROMserial)); |
|
| 350 |
- memset(ROMname, 0, sizeof(ROMname)); |
|
| 351 |
- |
|
| 352 |
- if ( |
|
| 353 |
- //Option 1. - look for this instruction in the game title |
|
| 354 |
- //(did this ever work?) |
|
| 355 |
- //(header->gameTile[0] == 0x2E) && |
|
| 356 |
- //(header->gameTile[1] == 0x00) && |
|
| 357 |
- //(header->gameTile[2] == 0x00) && |
|
| 358 |
- //(header->gameTile[3] == 0xEA) |
|
| 359 |
- //) && |
|
| 360 |
- //option 2. - look for gamecode #### (default for ndstool) |
|
| 361 |
- //or an invalid gamecode |
|
| 362 |
- ( |
|
| 363 |
- ((header.gameCode[0] == 0x23) && |
|
| 364 |
- (header.gameCode[1] == 0x23) && |
|
| 365 |
- (header.gameCode[2] == 0x23) && |
|
| 366 |
- (header.gameCode[3] == 0x23) |
|
| 367 |
- ) || |
|
| 368 |
- (header.gameCode[0] == 0x00) |
|
| 369 |
- ) |
|
| 370 |
- && |
|
| 371 |
- header.makerCode == 0x0 |
|
| 372 |
- ) |
|
| 373 |
- {
|
|
| 374 |
- //we can't really make a serial for a homebrew game that hasnt set a game code |
|
| 375 |
- strcpy(ROMserial, "Homebrew"); |
|
| 376 |
- } |
|
| 377 |
- else |
|
| 378 |
- {
|
|
| 379 |
- strcpy(ROMserial,"NTR- -"); |
|
| 380 |
- memcpy(ROMserial+4, header.gameCode, 4); |
|
| 381 |
- |
|
| 382 |
- uint32_t region = (uint32_t)(std::max<int32_t>(strchr(regions[0],header.gameCode[3]) - regions[0] + 1, 0)); |
|
| 383 |
- if (region != 0) |
|
| 384 |
- strcat(ROMserial, regions[region]); |
|
| 385 |
- else |
|
| 386 |
- strcat(ROMserial, "Unknown"); |
|
| 387 |
- } |
|
| 388 |
- |
|
| 389 |
- //rom name is probably set even in homebrew |
|
| 390 |
- memset(ROMname, 0, sizeof(ROMname)); |
|
| 391 |
- memcpy(ROMname, header.gameTile, 12); |
|
| 392 |
- trim(ROMname,20); |
|
| 393 |
- |
|
| 394 |
- if(header.IconOff < romsize) |
|
| 395 |
- {
|
|
| 396 |
- uint8_t num = (T1ReadByte((uint8_t*)romdata, header.IconOff) == 1)?6:7; |
|
| 397 |
- for (int i = 0; i < num; i++) |
|
| 398 |
- {
|
|
| 399 |
- wcstombs(ROMfullName[i], (wchar_t *)(romdata+header.IconOff+0x240+(i*0x100)), 0x100); |
|
| 400 |
- trim(ROMfullName[i]); |
|
| 401 |
- } |
|
| 402 |
- } |
|
| 403 |
- |
|
| 404 |
- //this may look like a poor heuristic for detecting homebrew, but it is actually pretty good. |
|
| 405 |
- //setting your own game code is stupid, so homebrew should just leave it. |
|
| 406 |
- //however, non-devkitARM-default makefiles may not have set this. |
|
| 407 |
- isHomebrew = !memcmp(header.gameCode,"####",4); |
|
| 408 |
-}*/ |
|
| 409 |
- |
|
| 410 |
-/*#ifdef _WINDOWS |
|
| 411 |
- |
|
| 412 |
-//static std::vector<char> buffer; |
|
| 413 |
-//static std::vector<char> v; |
|
| 414 |
- |
|
| 415 |
-static void loadrom(std::string fname) {
|
|
| 416 |
- |
|
| 417 |
- FILE* inf = fopen(fname.c_str(),"rb"); |
|
| 418 |
- if(!inf) return; |
|
| 419 |
- |
|
| 420 |
- fseek(inf,0,SEEK_END); |
|
| 421 |
- int size = ftell(inf); |
|
| 422 |
- fseek(inf,0,SEEK_SET); |
|
| 423 |
- |
|
| 424 |
- gameInfo.resize(size); |
|
| 425 |
- fread(gameInfo.romdata,1,size,inf); |
|
| 426 |
- gameInfo.fillGap(); |
|
| 427 |
- |
|
| 428 |
- fclose(inf); |
|
| 429 |
-} |
|
| 430 |
- |
|
| 431 |
-static int rom_init_path(const char *filename, const char *logicalFilename) |
|
| 432 |
-{
|
|
| 433 |
- int type = ROM_NDS; |
|
| 434 |
- |
|
| 435 |
- path.init(logicalFilename); |
|
| 436 |
- |
|
| 437 |
- if ( path.isdsgba(path.path)) {
|
|
| 438 |
- type = ROM_DSGBA; |
|
| 439 |
- loadrom(path.path); |
|
| 440 |
- } |
|
| 441 |
- else if ( !strcasecmp(path.extension().c_str(), "nds")) {
|
|
| 442 |
- type = ROM_NDS; |
|
| 443 |
- loadrom(path.path); //n.b. this does nothing if the file can't be found (i.e. if it was an extracted tempfile)... |
|
| 444 |
- //...but since the data was extracted to gameInfo then it is ok |
|
| 445 |
- } |
|
| 446 |
- //ds.gba in archives, it's already been loaded into memory at this point |
|
| 447 |
- else if (path.isdsgba(std::string(logicalFilename))) {
|
|
| 448 |
- type = ROM_DSGBA; |
|
| 449 |
- } else {
|
|
| 450 |
- //well, try to load it as an nds rom anyway |
|
| 451 |
- type = ROM_NDS; |
|
| 452 |
- loadrom(path.path); |
|
| 453 |
- } |
|
| 454 |
- |
|
| 455 |
- if(type == ROM_DSGBA) |
|
| 456 |
- {
|
|
| 457 |
- std::vector<char> v(gameInfo.romdata + DSGBA_LOADER_SIZE, gameInfo.romdata + gameInfo.romsize); |
|
| 458 |
- gameInfo.loadData(&v[0],gameInfo.romsize - DSGBA_LOADER_SIZE); |
|
| 459 |
- } |
|
| 460 |
- |
|
| 461 |
- //check that size is at least the size of the header |
|
| 462 |
- if (gameInfo.romsize < 352) {
|
|
| 463 |
- return -1; |
|
| 464 |
- } |
|
| 465 |
- |
|
| 466 |
- return 1; |
|
| 467 |
-} |
|
| 468 |
-#else |
|
| 469 |
-static int rom_init_path(const char *filename, const char *logicalFilename) |
|
| 470 |
-{
|
|
| 471 |
- int ret; |
|
| 472 |
- int type; |
|
| 473 |
- ROMReader_struct *reader; |
|
| 474 |
- void *file; |
|
| 475 |
- uint32_t size; |
|
| 476 |
- char *noext; |
|
| 477 |
- |
|
| 478 |
- noext = strdup(filename); |
|
| 479 |
- reader = ROMReaderInit(&noext); |
|
| 480 |
- free(noext); |
|
| 481 |
- |
|
| 482 |
- if (logicalFilename) |
|
| 483 |
- path.init(logicalFilename); |
|
| 484 |
- else |
|
| 485 |
- path.init(filename); |
|
| 486 |
- |
|
| 487 |
- if (!strcasecmp(path.extension().c_str(), "zip")) |
|
| 488 |
- type = ROM_NDS; |
|
| 489 |
- else if (!strcasecmp(path.extension().c_str(), "nds")) |
|
| 490 |
- type = ROM_NDS; |
|
| 491 |
- else if (path.isdsgba(path.path)) |
|
| 492 |
- type = ROM_DSGBA; |
|
| 493 |
- else |
|
| 494 |
- type = ROM_NDS; |
|
| 495 |
- |
|
| 496 |
- file = reader->Init(filename); |
|
| 497 |
- if (!file) |
|
| 498 |
- {
|
|
| 499 |
- reader->DeInit(file); |
|
| 500 |
- return -1; |
|
| 501 |
- } |
|
| 502 |
- |
|
| 503 |
- size = reader->Size(file); |
|
| 504 |
- |
|
| 505 |
- if(type == ROM_DSGBA) |
|
| 506 |
- {
|
|
| 507 |
- reader->Seek(file, DSGBA_LOADER_SIZE, SEEK_SET); |
|
| 508 |
- size -= DSGBA_LOADER_SIZE; |
|
| 509 |
- } |
|
| 510 |
- |
|
| 511 |
- //check that size is at least the size of the header |
|
| 512 |
- if (size < 352) {
|
|
| 513 |
- reader->DeInit(file); |
|
| 514 |
- return -1; |
|
| 515 |
- } |
|
| 516 |
- |
|
| 517 |
- // Make sure old ROM is freed first(at least this way we won't be eating |
|
| 518 |
- // up a ton of ram before the old ROM is freed) |
|
| 519 |
- if(MMU.CART_ROM != MMU.UNUSED_RAM) |
|
| 520 |
- NDS_FreeROM(); |
|
| 521 |
- |
|
| 522 |
- gameInfo.resize(size); |
|
| 523 |
- ret = reader->Read(file, gameInfo.romdata, size); |
|
| 524 |
- gameInfo.fillGap(); |
|
| 525 |
- reader->DeInit(file); |
|
| 526 |
- |
|
| 527 |
- return ret; |
|
| 137 |
+ if (!defaultInit) |
|
| 138 |
+ return; |
|
| 139 |
+ this->version = 1; //Version (0001h) |
|
| 140 |
+ this->crc16 = 0; //CRC16 across entries 020h..83Fh |
|
| 141 |
+ memset(this->reserved, 0, sizeof(this->reserved)); |
|
| 142 |
+ memset(this->bitmap, 0, sizeof(this->bitmap)); |
|
| 143 |
+ memset(this->palette, 0, sizeof(this->palette)); |
|
| 144 |
+ memset(this->titles, 0, sizeof(this->titles)); |
|
| 145 |
+ memset(this->end0xFF, 0, sizeof(this->end0xFF)); |
|
| 528 | 146 |
} |
| 529 |
-#endif*/ |
|
| 530 |
- |
|
| 531 |
-/*int NDS_LoadROM(const char *filename, const char *logicalFilename) |
|
| 532 |
-{
|
|
| 533 |
- int ret; |
|
| 534 |
- char buf[MAX_PATH]; |
|
| 535 |
- |
|
| 536 |
- if (filename == NULL) |
|
| 537 |
- return -1; |
|
| 538 |
- |
|
| 539 |
- ret = rom_init_path(filename, logicalFilename); |
|
| 540 |
- if (ret < 1) |
|
| 541 |
- return ret; |
|
| 542 |
- |
|
| 543 |
- //decrypt if necessary.. |
|
| 544 |
- //but this is untested and suspected to fail on big endian, so lets not support this on big endian |
|
| 545 |
-#ifndef WORDS_BIGENDIAN |
|
| 546 |
- bool okRom = DecryptSecureArea((uint8_t*)gameInfo.romdata,gameInfo.romsize); |
|
| 547 |
- |
|
| 548 |
- if(!okRom) {
|
|
| 549 |
- printf("Specified file is not a valid rom\n");
|
|
| 550 |
- return -1; |
|
| 551 |
- } |
|
| 552 |
-#endif |
|
| 553 |
- |
|
| 554 |
- if (cheatSearch) |
|
| 555 |
- cheatSearch->close(); |
|
| 556 |
- FCEUI_StopMovie(); |
|
| 557 |
- |
|
| 558 |
- MMU_unsetRom(); |
|
| 559 |
- NDS_SetROM((uint8_t*)gameInfo.romdata, gameInfo.mask); |
|
| 560 |
- |
|
| 561 |
- gameInfo.populate(); |
|
| 562 |
- gameInfo.crc = crc32(0,(uint8_t*)gameInfo.romdata,gameInfo.romsize); |
|
| 563 |
- //INFO("\nROM game code: %c%c%c%c\n", gameInfo.header.gameCode[0], gameInfo.header.gameCode[1], gameInfo.header.gameCode[2], gameInfo.header.gameCode[3]);
|
|
| 564 |
- //INFO("ROM crc: %08X\n", gameInfo.crc);
|
|
| 565 |
- //INFO("ROM serial: %s\n", gameInfo.ROMserial);
|
|
| 566 |
- //INFO("ROM internal name: %s\n", gameInfo.ROMname);
|
|
| 567 |
- |
|
| 568 |
- memset(buf, 0, MAX_PATH); |
|
| 569 |
- strcpy(buf, path.pathToModule); |
|
| 570 |
- strcat(buf, "desmume.ddb"); // DeSmuME database :) |
|
| 571 |
- advsc.setDatabase(buf); |
|
| 572 |
- buf[0] = gameInfo.header.gameCode[0]; |
|
| 573 |
- buf[1] = gameInfo.header.gameCode[1]; |
|
| 574 |
- buf[2] = gameInfo.header.gameCode[2]; |
|
| 575 |
- buf[3] = gameInfo.header.gameCode[3]; |
|
| 576 |
- buf[4] = 0; |
|
| 577 |
- if (advsc.checkDB(buf)) |
|
| 578 |
- {
|
|
| 579 |
- u8 sv = advsc.getSaveType(); |
|
| 580 |
- printf("ADVANsCEne database:\n");
|
|
| 581 |
- printf("\t* ROM save type: ");
|
|
| 582 |
- if (sv == 0xFF) |
|
| 583 |
- printf("Unknown");
|
|
| 584 |
- else |
|
| 585 |
- if (sv == 0xFE) |
|
| 586 |
- printf("None");
|
|
| 587 |
- else |
|
| 588 |
- {
|
|
| 589 |
- printf("%s", save_names[sv]);
|
|
| 590 |
- if (CommonSettings.autodetectBackupMethod == 1) |
|
| 591 |
- backup_setManualBackupType(sv+1); |
|
| 592 |
- } |
|
| 593 |
- printf("\n\t* ROM crc: %08X\n", advsc.getCRC32());
|
|
| 594 |
- } |
|
| 595 |
- printf("\n");
|
|
| 596 |
- |
|
| 597 |
- //for homebrew, try auto-patching DLDI. should be benign if there is no DLDI or if it fails |
|
| 598 |
- if(gameInfo.isHomebrew) |
|
| 599 |
- DLDI::tryPatch((void*)gameInfo.romdata, gameInfo.romsize); |
|
| 600 |
- |
|
| 601 |
- memset(buf, 0, MAX_PATH); |
|
| 602 |
- path.getpathnoext(path.BATTERY, buf); |
|
| 603 |
- strcat(buf, ".dsv"); // DeSmuME memory card :) |
|
| 604 |
- MMU_new.backupDevice.load_rom(buf); |
|
| 605 |
- |
|
| 606 |
- memset(buf, 0, MAX_PATH); |
|
| 607 |
- path.getpathnoext(path.CHEATS, buf); |
|
| 608 |
- strcat(buf, ".dct"); // DeSmuME cheat :) |
|
| 609 |
- cheats->init(buf); |
|
| 610 |
- |
|
| 611 |
- NDS_Reset(); |
|
| 612 |
- |
|
| 613 |
- return ret; |
|
| 614 |
-}*/ |
|
| 615 | 147 |
|
| 616 | 148 |
void NDS_FreeROM() |
| 617 | 149 |
{
|
| 618 |
- //FCEUI_StopMovie(); |
|
| 619 |
- if ((uint8_t*)MMU.CART_ROM == (uint8_t*)gameInfo.romdata) |
|
| 620 |
- gameInfo.romdata = NULL; |
|
| 150 |
+ if (MMU.CART_ROM == reinterpret_cast<uint8_t *>(&gameInfo.romdata[0])) |
|
| 151 |
+ gameInfo.romdata.reset(); |
|
| 621 | 152 |
if (MMU.CART_ROM != MMU.UNUSED_RAM) |
| 622 | 153 |
delete [] MMU.CART_ROM; |
| 623 | 154 |
MMU_unsetRom(); |
| 624 | 155 |
} |
| 625 | 156 |
|
| 626 |
- |
|
| 627 |
- |
|
| 628 |
-/*int NDS_ImportSave(const char *filename) |
|
| 629 |
-{
|
|
| 630 |
- if (strlen(filename) < 4) |
|
| 631 |
- return 0; |
|
| 632 |
- |
|
| 633 |
- if (memcmp(filename+strlen(filename)-4, ".duc", 4) == 0) |
|
| 634 |
- return MMU_new.backupDevice.load_duc(filename); |
|
| 635 |
- else |
|
| 636 |
- if (MMU_new.backupDevice.load_no_gba(filename)) |
|
| 637 |
- return 1; |
|
| 638 |
- else |
|
| 639 |
- return MMU_new.backupDevice.load_raw(filename); |
|
| 640 |
- |
|
| 641 |
- //return 0; |
|
| 642 |
-}*/ |
|
| 643 |
- |
|
| 644 |
-/*bool NDS_ExportSave(const char *filename) |
|
| 645 |
-{
|
|
| 646 |
- if (strlen(filename) < 4) |
|
| 647 |
- return false; |
|
| 648 |
- |
|
| 649 |
- if (memcmp(filename+strlen(filename)-5, ".sav*", 5) == 0) |
|
| 650 |
- {
|
|
| 651 |
- char tmp[MAX_PATH]; |
|
| 652 |
- memset(tmp, 0, MAX_PATH); |
|
| 653 |
- strcpy(tmp, filename); |
|
| 654 |
- tmp[strlen(tmp)-1] = 0; |
|
| 655 |
- return MMU_new.backupDevice.save_no_gba(tmp); |
|
| 656 |
- } |
|
| 657 |
- |
|
| 658 |
- if (memcmp(filename+strlen(filename)-4, ".sav", 4) == 0) |
|
| 659 |
- return MMU_new.backupDevice.save_raw(filename); |
|
| 660 |
- |
|
| 661 |
- return false; |
|
| 662 |
-}*/ |
|
| 663 |
- |
|
| 664 |
-/*static int WritePNGChunk(FILE *fp, uint32 size, const char *type, const uint8 *data) |
|
| 665 |
-{
|
|
| 666 |
- uint32 crc; |
|
| 667 |
- |
|
| 668 |
- uint8 tempo[4]; |
|
| 669 |
- |
|
| 670 |
- tempo[0]=size>>24; |
|
| 671 |
- tempo[1]=size>>16; |
|
| 672 |
- tempo[2]=size>>8; |
|
| 673 |
- tempo[3]=size; |
|
| 674 |
- |
|
| 675 |
- if(fwrite(tempo,4,1,fp)!=1) |
|
| 676 |
- return 0; |
|
| 677 |
- if(fwrite(type,4,1,fp)!=1) |
|
| 678 |
- return 0; |
|
| 679 |
- |
|
| 680 |
- if(size) |
|
| 681 |
- if(fwrite(data,1,size,fp)!=size) |
|
| 682 |
- return 0; |
|
| 683 |
- |
|
| 684 |
- crc = crc32(0,(uint8 *)type,4); |
|
| 685 |
- if(size) |
|
| 686 |
- crc = crc32(crc,data,size); |
|
| 687 |
- |
|
| 688 |
- tempo[0]=crc>>24; |
|
| 689 |
- tempo[1]=crc>>16; |
|
| 690 |
- tempo[2]=crc>>8; |
|
| 691 |
- tempo[3]=crc; |
|
| 692 |
- |
|
| 693 |
- if(fwrite(tempo,4,1,fp)!=1) |
|
| 694 |
- return 0; |
|
| 695 |
- return 1; |
|
| 696 |
-}*/ |
|
| 697 |
-/*int NDS_WritePNG(const char *fname) |
|
| 698 |
-{
|
|
| 699 |
- int x, y; |
|
| 700 |
- int width=256; |
|
| 701 |
- int height=192*2; |
|
| 702 |
- uint16_t * bmp = (uint16_t *)GPU_screen; |
|
| 703 |
- FILE *pp=NULL; |
|
| 704 |
- uint8 *compmem = NULL; |
|
| 705 |
- uLongf compmemsize = (uLongf)( (height * (width + 1) * 3 * 1.001 + 1) + 12 ); |
|
| 706 |
- |
|
| 707 |
- if(!(compmem=(uint8 *)malloc(compmemsize))) |
|
| 708 |
- return 0; |
|
| 709 |
- |
|
| 710 |
- if(!(pp=fopen(fname, "wb"))) |
|
| 711 |
- {
|
|
| 712 |
- goto PNGerr; |
|
| 713 |
- } |
|
| 714 |
- {
|
|
| 715 |
- const uint8 header[8]={137,80,78,71,13,10,26,10};
|
|
| 716 |
- if(fwrite(header,8,1,pp)!=1) |
|
| 717 |
- goto PNGerr; |
|
| 718 |
- } |
|
| 719 |
- |
|
| 720 |
- {
|
|
| 721 |
- uint8 chunko[13]; |
|
| 722 |
- |
|
| 723 |
- chunko[0] = width >> 24; // Width |
|
| 724 |
- chunko[1] = width >> 16; |
|
| 725 |
- chunko[2] = width >> 8; |
|
| 726 |
- chunko[3] = width; |
|
| 727 |
- |
|
| 728 |
- chunko[4] = height >> 24; // Height |
|
| 729 |
- chunko[5] = height >> 16; |
|
| 730 |
- chunko[6] = height >> 8; |
|
| 731 |
- chunko[7] = height; |
|
| 732 |
- |
|
| 733 |
- chunko[8]=8; // 8 bits per sample(24 bits per pixel) |
|
| 734 |
- chunko[9]=2; // Color type; RGB triplet |
|
| 735 |
- chunko[10]=0; // compression: deflate |
|
| 736 |
- chunko[11]=0; // Basic adapative filter set(though none are used). |
|
| 737 |
- chunko[12]=0; // No interlace. |
|
| 738 |
- |
|
| 739 |
- if(!WritePNGChunk(pp,13,"IHDR",chunko)) |
|
| 740 |
- goto PNGerr; |
|
| 741 |
- } |
|
| 742 |
- |
|
| 743 |
- {
|
|
| 744 |
- uint8 *tmp_buffer; |
|
| 745 |
- uint8 *tmp_inc; |
|
| 746 |
- tmp_inc = tmp_buffer = (uint8 *)malloc((width * 3 + 1) * height); |
|
| 747 |
- |
|
| 748 |
- for(y=0;y<height;y++) |
|
| 749 |
- {
|
|
| 750 |
- *tmp_inc = 0; |
|
| 751 |
- tmp_inc++; |
|
| 752 |
- for(x=0;x<width;x++) |
|
| 753 |
- {
|
|
| 754 |
- int r,g,b; |
|
| 755 |
- uint16_t pixel = bmp[y*256+x]; |
|
| 756 |
- r = pixel>>10; |
|
| 757 |
- pixel-=r<<10; |
|
| 758 |
- g = pixel>>5; |
|
| 759 |
- pixel-=g<<5; |
|
| 760 |
- b = pixel; |
|
| 761 |
- r*=255/31; |
|
| 762 |
- g*=255/31; |
|
| 763 |
- b*=255/31; |
|
| 764 |
- tmp_inc[0] = b; |
|
| 765 |
- tmp_inc[1] = g; |
|
| 766 |
- tmp_inc[2] = r; |
|
| 767 |
- tmp_inc += 3; |
|
| 768 |
- } |
|
| 769 |
- } |
|
| 770 |
- |
|
| 771 |
- if(compress(compmem, &compmemsize, tmp_buffer, height * (width * 3 + 1))!=Z_OK) |
|
| 772 |
- {
|
|
| 773 |
- if(tmp_buffer) free(tmp_buffer); |
|
| 774 |
- goto PNGerr; |
|
| 775 |
- } |
|
| 776 |
- if(tmp_buffer) free(tmp_buffer); |
|
| 777 |
- if(!WritePNGChunk(pp,compmemsize,"IDAT",compmem)) |
|
| 778 |
- goto PNGerr; |
|
| 779 |
- } |
|
| 780 |
- if(!WritePNGChunk(pp,0,"IEND",0)) |
|
| 781 |
- goto PNGerr; |
|
| 782 |
- |
|
| 783 |
- free(compmem); |
|
| 784 |
- fclose(pp); |
|
| 785 |
- |
|
| 786 |
- return 1; |
|
| 787 |
- |
|
| 788 |
-PNGerr: |
|
| 789 |
- if(compmem) |
|
| 790 |
- free(compmem); |
|
| 791 |
- if(pp) |
|
| 792 |
- fclose(pp); |
|
| 793 |
- return 0; |
|
| 794 |
-}*/ |
|
| 795 |
- |
|
| 796 |
-/*typedef struct |
|
| 797 |
-{
|
|
| 798 |
- uint32_t size; |
|
| 799 |
- int32_t width; |
|
| 800 |
- int32_t height; |
|
| 801 |
- uint16_t planes; |
|
| 802 |
- uint16_t bpp; |
|
| 803 |
- uint32_t cmptype; |
|
| 804 |
- uint32_t imgsize; |
|
| 805 |
- int32_t hppm; |
|
| 806 |
- int32_t vppm; |
|
| 807 |
- uint32_t numcol; |
|
| 808 |
- uint32_t numimpcol; |
|
| 809 |
-} bmpimgheader_struct; |
|
| 810 |
- |
|
| 811 |
-#include "PACKED.h" |
|
| 812 |
-typedef struct |
|
| 813 |
-{
|
|
| 814 |
- uint16_t id __PACKED; |
|
| 815 |
- uint32_t size __PACKED; |
|
| 816 |
- uint16_t reserved1 __PACKED; |
|
| 817 |
- uint16_t reserved2 __PACKED; |
|
| 818 |
- uint32_t imgoffset __PACKED; |
|
| 819 |
-} bmpfileheader_struct; |
|
| 820 |
-#include "PACKED_END.h"*/ |
|
| 821 |
- |
|
| 822 |
-/*int NDS_WriteBMP(const char *filename) |
|
| 823 |
-{
|
|
| 824 |
- bmpfileheader_struct fileheader; |
|
| 825 |
- bmpimgheader_struct imageheader; |
|
| 826 |
- FILE *file; |
|
| 827 |
- int i,j; |
|
| 828 |
- uint16_t * bmp = (uint16_t *)GPU_screen; |
|
| 829 |
- size_t elems_written = 0; |
|
| 830 |
- |
|
| 831 |
- memset(&fileheader, 0, sizeof(fileheader)); |
|
| 832 |
- fileheader.size = sizeof(fileheader); |
|
| 833 |
- fileheader.id = 'B' | ('M' << 8);
|
|
| 834 |
- fileheader.imgoffset = sizeof(fileheader)+sizeof(imageheader); |
|
| 835 |
- |
|
| 836 |
- memset(&imageheader, 0, sizeof(imageheader)); |
|
| 837 |
- imageheader.size = sizeof(imageheader); |
|
| 838 |
- imageheader.width = 256; |
|
| 839 |
- imageheader.height = 192*2; |
|
| 840 |
- imageheader.planes = 1; |
|
| 841 |
- imageheader.bpp = 24; |
|
| 842 |
- imageheader.cmptype = 0; // None |
|
| 843 |
- imageheader.imgsize = imageheader.width * imageheader.height * 3; |
|
| 844 |
- |
|
| 845 |
- if ((file = fopen(filename,"wb")) == NULL) |
|
| 846 |
- return 0; |
|
| 847 |
- |
|
| 848 |
- elems_written += fwrite(&fileheader, 1, sizeof(fileheader), file); |
|
| 849 |
- elems_written += fwrite(&imageheader, 1, sizeof(imageheader), file); |
|
| 850 |
- |
|
| 851 |
- for(j=0;j<192*2;j++) |
|
| 852 |
- {
|
|
| 853 |
- for(i=0;i<256;i++) |
|
| 854 |
- {
|
|
| 855 |
- uint8_t r,g,b; |
|
| 856 |
- uint16_t pixel = bmp[(192*2-j-1)*256+i]; |
|
| 857 |
- r = pixel>>10; |
|
| 858 |
- pixel-=r<<10; |
|
| 859 |
- g = pixel>>5; |
|
| 860 |
- pixel-=g<<5; |
|
| 861 |
- b = (uint8_t)pixel; |
|
| 862 |
- r*=255/31; |
|
| 863 |
- g*=255/31; |
|
| 864 |
- b*=255/31; |
|
| 865 |
- elems_written += fwrite(&r, 1, sizeof(uint8_t), file); |
|
| 866 |
- elems_written += fwrite(&g, 1, sizeof(uint8_t), file); |
|
| 867 |
- elems_written += fwrite(&b, 1, sizeof(uint8_t), file); |
|
| 868 |
- } |
|
| 869 |
- } |
|
| 870 |
- fclose(file); |
|
| 871 |
- |
|
| 872 |
- return 1; |
|
| 873 |
-}*/ |
|
| 874 |
- |
|
| 875 |
-/*int NDS_WriteBMP_32bppBuffer(int width, int height, const void* buf, const char *filename) |
|
| 876 |
-{
|
|
| 877 |
- bmpfileheader_struct fileheader; |
|
| 878 |
- bmpimgheader_struct imageheader; |
|
| 879 |
- FILE *file; |
|
| 880 |
- size_t elems_written = 0; |
|
| 881 |
- memset(&fileheader, 0, sizeof(fileheader)); |
|
| 882 |
- fileheader.size = sizeof(fileheader); |
|
| 883 |
- fileheader.id = 'B' | ('M' << 8);
|
|
| 884 |
- fileheader.imgoffset = sizeof(fileheader)+sizeof(imageheader); |
|
| 885 |
- |
|
| 886 |
- memset(&imageheader, 0, sizeof(imageheader)); |
|
| 887 |
- imageheader.size = sizeof(imageheader); |
|
| 888 |
- imageheader.width = width; |
|
| 889 |
- imageheader.height = height; |
|
| 890 |
- imageheader.planes = 1; |
|
| 891 |
- imageheader.bpp = 32; |
|
| 892 |
- imageheader.cmptype = 0; // None |
|
| 893 |
- imageheader.imgsize = imageheader.width * imageheader.height * 4; |
|
| 894 |
- |
|
| 895 |
- if ((file = fopen(filename,"wb")) == NULL) |
|
| 896 |
- return 0; |
|
| 897 |
- |
|
| 898 |
- elems_written += fwrite(&fileheader, 1, sizeof(fileheader), file); |
|
| 899 |
- elems_written += fwrite(&imageheader, 1, sizeof(imageheader), file); |
|
| 900 |
- |
|
| 901 |
- for(int i=0;i<height;i++) |
|
| 902 |
- for(int x=0;x<width;x++) |
|
| 903 |
- {
|
|
| 904 |
- uint8_t* pixel = (uint8_t*)buf + (height-i-1)*width*4; |
|
| 905 |
- pixel += (x*4); |
|
| 906 |
- elems_written += fwrite(pixel+2,1,1,file); |
|
| 907 |
- elems_written += fwrite(pixel+1,1,1,file); |
|
| 908 |
- elems_written += fwrite(pixel+0,1,1,file); |
|
| 909 |
- elems_written += fwrite(pixel+3,1,1,file); |
|
| 910 |
- } |
|
| 911 |
- fclose(file); |
|
| 912 |
- |
|
| 913 |
- return 1; |
|
| 914 |
-}*/ |
|
| 915 |
- |
|
| 916 | 157 |
void NDS_Sleep() { nds.sleeping = true; }
|
| 917 |
-/*void NDS_ToggleCardEject() |
|
| 918 |
-{
|
|
| 919 |
- if(!nds.cardEjected) |
|
| 920 |
- {
|
|
| 921 |
- //staff of kings will test this (it also uses the arm9 0xB8 poll) |
|
| 922 |
- NDS_makeIrq(ARMCPU_ARM7, IRQ_BIT_GC_IREQ_MC); |
|
| 923 |
- } |
|
| 924 |
- nds.cardEjected ^= true; |
|
| 925 |
-}*/ |
|
| 926 |
- |
|
| 927 |
- |
|
| 928 |
-/*class FrameSkipper |
|
| 929 |
-{
|
|
| 930 |
-public: |
|
| 931 |
- void RequestSkip() |
|
| 932 |
- {
|
|
| 933 |
- nextSkip = true; |
|
| 934 |
- } |
|
| 935 |
- void OmitSkip(bool force, bool forceEvenIfCapturing=false) |
|
| 936 |
- {
|
|
| 937 |
- nextSkip = false; |
|
| 938 |
- if((force && consecutiveNonCaptures > 30) || forceEvenIfCapturing) |
|
| 939 |
- {
|
|
| 940 |
- SkipCur2DFrame = false; |
|
| 941 |
- SkipCur3DFrame = false; |
|
| 942 |
- SkipNext2DFrame = false; |
|
| 943 |
- if(forceEvenIfCapturing) |
|
| 944 |
- consecutiveNonCaptures = 0; |
|
| 945 |
- } |
|
| 946 |
- } |
|
| 947 |
- void Advance() |
|
| 948 |
- {
|
|
| 949 |
- bool capturing = false*//*(MainScreen.gpu->dispCapCnt.enabled || (MainScreen.gpu->dispCapCnt.val & 0x80000000))*//*; |
|
| 950 |
- |
|
| 951 |
- if(capturing && consecutiveNonCaptures > 30) |
|
| 952 |
- {
|
|
| 953 |
- // the worst-looking graphics corruption problems from frameskip |
|
| 954 |
- // are the result of skipping the capture on first frame it turns on. |
|
| 955 |
- // so we do this to handle the capture immediately, |
|
| 956 |
- // despite the risk of 1 frame of 2d/3d mismatch or wrong screen display. |
|
| 957 |
- SkipNext2DFrame = false; |
|
| 958 |
- nextSkip = false; |
|
| 959 |
- } |
|
| 960 |
- else if(*//*lastOffset != MainScreen.offset && *//*lastSkip && !skipped) |
|
| 961 |
- {
|
|
| 962 |
- // if we're switching from not skipping to skipping |
|
| 963 |
- // and the screens are also switching around this frame, |
|
| 964 |
- // go for 1 extra frame without skipping. |
|
| 965 |
- // this avoids the scenario where we only draw one of the two screens |
|
| 966 |
- // when a game is switching screens every frame. |
|
| 967 |
- nextSkip = false; |
|
| 968 |
- } |
|
| 969 |
- |
|
| 970 |
- if(capturing) |
|
| 971 |
- consecutiveNonCaptures = 0; |
|
| 972 |
- else if(!(consecutiveNonCaptures > 9000)) // arbitrary cap to avoid eventual wrap |
|
| 973 |
- consecutiveNonCaptures++; |
|
| 974 |
- lastLastOffset = lastOffset; |
|
| 975 |
- //lastOffset = MainScreen.offset; |
|
| 976 |
- lastSkip = skipped; |
|
| 977 |
- skipped = nextSkip; |
|
| 978 |
- nextSkip = false; |
|
| 979 |
- |
|
| 980 |
- SkipCur2DFrame = SkipNext2DFrame; |
|
| 981 |
- SkipCur3DFrame = skipped; |
|
| 982 |
- SkipNext2DFrame = skipped; |
|
| 983 |
- } |
|
| 984 |
- inline bool ShouldSkip2D() |
|
| 985 |
- {
|
|
| 986 |
- return SkipCur2DFrame; |
|
| 987 |
- } |
|
| 988 |
- inline bool ShouldSkip3D() |
|
| 989 |
- {
|
|
| 990 |
- return SkipCur3DFrame; |
|
| 991 |
- } |
|
| 992 |
- FrameSkipper() |
|
| 993 |
- {
|
|
| 994 |
- nextSkip = false; |
|
| 995 |
- skipped = false; |
|
| 996 |
- lastSkip = false; |
|
| 997 |
- lastOffset = 0; |
|
| 998 |
- SkipCur2DFrame = false; |
|
| 999 |
- SkipCur3DFrame = false; |
|
| 1000 |
- SkipNext2DFrame = false; |
|
| 1001 |
- consecutiveNonCaptures = 0; |
|
| 1002 |
- } |
|
| 1003 |
-private: |
|
| 1004 |
- bool nextSkip; |
|
| 1005 |
- bool skipped; |
|
| 1006 |
- bool lastSkip; |
|
| 1007 |
- int lastOffset; |
|
| 1008 |
- int lastLastOffset; |
|
| 1009 |
- int consecutiveNonCaptures; |
|
| 1010 |
- bool SkipCur2DFrame; |
|
| 1011 |
- bool SkipCur3DFrame; |
|
| 1012 |
- bool SkipNext2DFrame; |
|
| 1013 |
-};*/ |
|
| 1014 |
-//static FrameSkipper frameSkipper; |
|
| 1015 |
- |
|
| 1016 |
- |
|
| 1017 |
-/*void NDS_SkipNextFrame() {
|
|
| 1018 |
- //if (!driver->AVI_IsRecording()) {
|
|
| 1019 |
- //frameSkipper.RequestSkip(); |
|
| 1020 |
- //} |
|
| 1021 |
-}*/ |
|
| 1022 |
-/*void NDS_OmitFrameSkip(int force) {
|
|
| 1023 |
- //frameSkipper.OmitSkip(force > 0, force > 1); |
|
| 1024 |
-}*/ |
|
| 1025 |
- |
|
| 1026 |
-//#define INDEX(i) ((((i)>>16)&0xFF0)|(((i)>>4)&0xF)) |
|
| 1027 |
- |
|
| 1028 | 158 |
|
| 1029 | 159 |
enum ESI_DISPCNT |
| 1030 | 160 |
{
|
| ... | ... |
@@ -1042,235 +172,164 @@ struct TSequenceItem |
| 1042 | 172 |
uint32_t param; |
| 1043 | 173 |
bool enabled; |
| 1044 | 174 |
|
| 1045 |
- /*virtual void save(EMUFILE* os) |
|
| 1046 |
- {
|
|
| 1047 |
- write64le(timestamp,os); |
|
| 1048 |
- write32le(param,os); |
|
| 1049 |
- writebool(enabled,os); |
|
| 1050 |
- }*/ |
|
| 1051 |
- |
|
| 1052 |
- virtual bool load(EMUFILE* is) |
|
| 175 |
+ virtual bool isTriggered() const |
|
| 1053 | 176 |
{
|
| 1054 |
- if(read64le(×tamp,is) != 1) return false; |
|
| 1055 |
- if(read32le(¶m,is) != 1) return false; |
|
| 1056 |
- if(readbool(&enabled,is) != 1) return false; |
|
| 1057 |
- return true; |
|
| 177 |
+ return this->enabled && nds_timer >= this->timestamp; |
|
| 1058 | 178 |
} |
| 1059 | 179 |
|
| 1060 |
- inline bool isTriggered() |
|
| 180 |
+ virtual uint64_t next() const |
|
| 1061 | 181 |
{
|
| 1062 |
- return enabled && nds_timer >= timestamp; |
|
| 1063 |
- } |
|
| 1064 |
- |
|
| 1065 |
- inline uint64_t next() |
|
| 1066 |
- {
|
|
| 1067 |
- return timestamp; |
|
| 182 |
+ return this->timestamp; |
|
| 1068 | 183 |
} |
| 1069 | 184 |
}; |
| 1070 | 185 |
|
| 1071 |
-/*struct TSequenceItem_GXFIFO : public TSequenceItem |
|
| 1072 |
-{
|
|
| 1073 |
- inline bool isTriggered() |
|
| 1074 |
- {
|
|
| 1075 |
- return enabled && nds_timer >= MMU.gfx3dCycles; |
|
| 1076 |
- } |
|
| 1077 |
- |
|
| 1078 |
- inline void exec() |
|
| 1079 |
- {
|
|
| 1080 |
- IF_DEVELOPER(DEBUG_statistics.sequencerExecutionCounters[4]++); |
|
| 1081 |
- while(isTriggered()) {
|
|
| 1082 |
- enabled = false; |
|
| 1083 |
- //gfx3d_execute3D(); |
|
| 1084 |
- } |
|
| 1085 |
- } |
|
| 1086 |
- |
|
| 1087 |
- inline uint64_t next() |
|
| 1088 |
- {
|
|
| 1089 |
- if(enabled) return MMU.gfx3dCycles; |
|
| 1090 |
- else return kNever; |
|
| 1091 |
- } |
|
| 1092 |
-};*/ |
|
| 1093 |
- |
|
| 1094 | 186 |
template<int procnum, int num> struct TSequenceItem_Timer : public TSequenceItem |
| 1095 | 187 |
{
|
| 1096 |
- inline bool isTriggered() |
|
| 188 |
+ bool isTriggered() const |
|
| 1097 | 189 |
{
|
| 1098 |
- return enabled && nds_timer >= nds.timerCycle[procnum][num]; |
|
| 190 |
+ return this->enabled && nds_timer >= nds.timerCycle[procnum][num]; |
|
| 1099 | 191 |
} |
| 1100 | 192 |
|
| 1101 |
- inline void schedule() |
|
| 193 |
+ void schedule() |
|
| 1102 | 194 |
{
|
| 1103 |
- enabled = MMU.timerON[procnum][num] && MMU.timerMODE[procnum][num] != 0xFFFF; |
|
| 195 |
+ this->enabled = MMU.timerON[procnum][num] && MMU.timerMODE[procnum][num] != 0xFFFF; |
|
| 1104 | 196 |
} |
| 1105 | 197 |
|
| 1106 |
- inline uint64_t next() |
|
| 198 |
+ uint64_t next() const |
|
| 1107 | 199 |
{
|
| 1108 | 200 |
return nds.timerCycle[procnum][num]; |
| 1109 | 201 |
} |
| 1110 | 202 |
|
| 1111 |
- inline void exec() |
|
| 203 |
+ void exec() |
|
| 1112 | 204 |
{
|
| 1113 |
- IF_DEVELOPER(DEBUG_statistics.sequencerExecutionCounters[13+procnum*4+num]++); |
|
| 1114 |
- uint8_t* regs = procnum==0?MMU.ARM9_REG:MMU.ARM7_REG; |
|
| 205 |
+ uint8_t *regs = !procnum ? MMU.ARM9_REG : MMU.ARM7_REG; |
|
| 1115 | 206 |
bool first = true, over; |
| 1116 |
- //we'll need to check chained timers.. |
|
| 1117 |
- for(int i=num;i<4;i++) |
|
| 207 |
+ // we'll need to check chained timers.. |
|
| 208 |
+ for (int i = num; i < 4; ++i) |
|
| 1118 | 209 |
{
|
| 1119 |
- //maybe too many checks if this is here, but we need it here for now |
|
| 1120 |
- if(!MMU.timerON[procnum][i]) return; |
|
| 210 |
+ // maybe too many checks if this is here, but we need it here for now |
|
| 211 |
+ if (!MMU.timerON[procnum][i]) |
|
| 212 |
+ return; |
|
| 1121 | 213 |
|
| 1122 |
- if(MMU.timerMODE[procnum][i] == 0xFFFF) |
|
| 214 |
+ if (MMU.timerMODE[procnum][i] == 0xFFFF) |
|
| 1123 | 215 |
{
|
| 1124 |
- ++(MMU.timer[procnum][i]); |
|
| 216 |
+ ++MMU.timer[procnum][i]; |
|
| 1125 | 217 |
over = !MMU.timer[procnum][i]; |
| 1126 | 218 |
} |
| 1127 | 219 |
else |
| 1128 | 220 |
{
|
| 1129 |
- if(!first) break; //this timer isn't chained. break the chain |
|
| 221 |
+ if (!first) |
|
| 222 |
+ break; // this timer isn't chained. break the chain |
|
| 1130 | 223 |
first = false; |
| 1131 | 224 |
|
| 1132 | 225 |
over = true; |
| 1133 | 226 |
int remain = 65536 - MMU.timerReload[procnum][i]; |
| 1134 |
- int ctr=0; |
|
| 1135 |
- while(nds.timerCycle[procnum][i] <= nds_timer) {
|
|
| 1136 |
- nds.timerCycle[procnum][i] += (remain << MMU.timerMODE[procnum][i]); |
|
| 1137 |
- ctr++; |
|
| 227 |
+ int ctr = 0; |
|
| 228 |
+ while (nds.timerCycle[procnum][i] <= nds_timer) |
|
| 229 |
+ {
|
|
| 230 |
+ nds.timerCycle[procnum][i] += remain << MMU.timerMODE[procnum][i]; |
|
| 231 |
+ ++ctr; |
|
| 1138 | 232 |
} |
| 1139 | 233 |
#ifndef NDEBUG |
| 1140 |
- if(ctr>1) {
|
|
| 234 |
+ if (ctr > 1) |
|
| 1141 | 235 |
printf("yikes!!!!! please report!\n");
|
| 1142 |
- } |
|
| 1143 | 236 |
#endif |
| 1144 | 237 |
} |
| 1145 | 238 |
|
| 1146 |
- if(over) |
|
| 239 |
+ if (over) |
|
| 1147 | 240 |
{
|
| 1148 | 241 |
MMU.timer[procnum][i] = MMU.timerReload[procnum][i]; |
| 1149 |
- if(T1ReadWord(regs, 0x102 + i*4) & 0x40) |
|
| 1150 |
- {
|
|
| 242 |
+ if (T1ReadWord(regs, 0x102 + i * 4) & 0x40) |
|
| 1151 | 243 |
NDS_makeIrq(procnum, IRQ_BIT_TIMER_0 + i); |
| 1152 |
- } |
|
| 1153 | 244 |
} |
| 1154 | 245 |
else |
| 1155 |
- break; //no more chained timers to trigger. we're done here |
|
| 246 |
+ break; // no more chained timers to trigger. we're done here |
|
| 1156 | 247 |
} |
| 1157 | 248 |
} |
| 1158 | 249 |
}; |
| 1159 | 250 |
|
| 1160 | 251 |
template<int procnum, int chan> struct TSequenceItem_DMA : public TSequenceItem |
| 1161 | 252 |
{
|
| 1162 |
- DmaController* controller; |
|
| 253 |
+ DmaController *controller; |
|
| 1163 | 254 |
|
| 1164 |
- inline bool isTriggered() |
|
| 255 |
+ bool isTriggered() const |
|
| 1165 | 256 |
{
|
| 1166 |
- return controller->dmaCheck && nds_timer>= controller->nextEvent; |
|
| 257 |
+ return this->controller->dmaCheck && nds_timer>= this->controller->nextEvent; |
|
| 1167 | 258 |
} |
| 1168 | 259 |
|
| 1169 |
- inline bool isEnabled() {
|
|
| 1170 |
- return controller->dmaCheck?true:false; |
|
| 260 |
+ bool isEnabled() const |
|
| 261 |
+ {
|
|
| 262 |
+ return this->controller->dmaCheck; |
|
| 1171 | 263 |
} |
| 1172 | 264 |
|
| 1173 |
- inline uint64_t next() |
|
| 265 |
+ uint64_t next() const |
|
| 1174 | 266 |
{
|
| 1175 |
- return controller->nextEvent; |
|
| 267 |
+ return this->controller->nextEvent; |
|
| 1176 | 268 |
} |
| 1177 | 269 |
|
| 1178 |
- inline void exec() |
|
| 270 |
+ void exec() |
|
| 1179 | 271 |
{
|
| 1180 |
- IF_DEVELOPER(DEBUG_statistics.sequencerExecutionCounters[5+procnum*4+chan]++); |
|
| 1181 |
- |
|
| 1182 |
- //if (nds.freezeBus) return; |
|
| 1183 |
- |
|
| 1184 | 272 |
//printf("exec from TSequenceItem_DMA: %d %d\n",procnum,chan);
|
| 1185 |
- controller->exec(); |
|
| 1186 |
-// //give gxfifo dmas a chance to re-trigger |
|
| 1187 |
-// if(MMU.DMAStartTime[procnum][chan] == EDMAMode_GXFifo) {
|
|
| 1188 |
-// MMU.DMAing[procnum][chan] = false; |
|
| 1189 |
-// if (gxFIFO.size <= 127) |
|
| 1190 |
-// {
|
|
| 1191 |
-// execHardware_doDma(procnum,chan,EDMAMode_GXFifo); |
|
| 1192 |
-// if (MMU.DMACompleted[procnum][chan]) |
|
| 1193 |
-// goto docomplete; |
|
| 1194 |
-// else return; |
|
| 1195 |
-// } |
|
| 1196 |
-// } |
|
| 1197 |
-// |
|
| 1198 |
-//docomplete: |
|
| 1199 |
-// if (MMU.DMACompleted[procnum][chan]) |
|
| 1200 |
-// {
|
|
| 1201 |
-// uint8_t* regs = procnum==0?MMU.ARM9_REG:MMU.ARM7_REG; |
|
| 1202 |
-// |
|
| 1203 |
-// //disable the channel |
|
| 1204 |
-// if(MMU.DMAStartTime[procnum][chan] != EDMAMode_GXFifo) {
|
|
| 1205 |
-// T1WriteLong(regs, 0xB8 + (0xC*chan), T1ReadLong(regs, 0xB8 + (0xC*chan)) & 0x7FFFFFFF); |
|
| 1206 |
-// MMU.DMACrt[procnum][chan] &= 0x7FFFFFFF; //blehhh i hate this shit being mirrored in memory |
|
| 1207 |
-// } |
|
| 1208 |
-// |
|
| 1209 |
-// if((MMU.DMACrt[procnum][chan])&(1<<30)) {
|
|
| 1210 |
-// if(procnum==0) NDS_makeARM9Int(8+chan); |
|
| 1211 |
-// else NDS_makeARM7Int(8+chan); |
|
| 1212 |
-// } |
|
| 1213 |
-// |
|
| 1214 |
-// MMU.DMAing[procnum][chan] = false; |
|
| 1215 |
-// } |
|
| 1216 |
- |
|
| 273 |
+ this->controller->exec(); |
|
| 1217 | 274 |
} |
| 1218 | 275 |
}; |
| 1219 | 276 |
|
| 1220 | 277 |
struct TSequenceItem_divider : public TSequenceItem |
| 1221 | 278 |
{
|
| 1222 |
- inline bool isTriggered() |
|
| 279 |
+ bool isTriggered() const |
|
| 1223 | 280 |
{
|
| 1224 | 281 |
return MMU.divRunning && nds_timer >= MMU.divCycles; |
| 1225 | 282 |
} |
| 1226 | 283 |
|
| 1227 |
- bool isEnabled() { return MMU.divRunning!=0; }
|
|
| 284 |
+ bool isEnabled() |
|
| 285 |
+ {
|
|
| 286 |
+ return MMU.divRunning; |
|
| 287 |
+ } |
|
| 1228 | 288 |
|
| 1229 |
- inline uint64_t next() |
|
| 289 |
+ uint64_t next() const |
|
| 1230 | 290 |
{
|
| 1231 | 291 |
return MMU.divCycles; |
| 1232 | 292 |
} |
| 1233 | 293 |
|
| 1234 | 294 |
void exec() |
| 1235 | 295 |
{
|
| 1236 |
- IF_DEVELOPER(DEBUG_statistics.sequencerExecutionCounters[2]++); |
|
| 1237 | 296 |
MMU_new.div.busy = 0; |
| 1238 | 297 |
#ifdef _WIN64 |
| 1239 | 298 |
T1WriteQuad(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A0, MMU.divResult); |
| 1240 | 299 |
T1WriteQuad(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A8, MMU.divMod); |
| 1241 | 300 |
#else |
| 1242 |
- T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A0, (uint32_t)MMU.divResult); |
|
| 1243 |
- T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A4, (uint32_t)(MMU.divResult >> 32)); |
|
| 1244 |
- T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A8, (uint32_t)MMU.divMod); |
|
| 1245 |
- T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2AC, (uint32_t)(MMU.divMod >> 32)); |
|
| 301 |
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A0, static_cast<uint32_t>(MMU.divResult)); |
|
| 302 |
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A4, static_cast<uint32_t>(MMU.divResult >> 32)); |
|
| 303 |
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A8, static_cast<uint32_t>(MMU.divMod)); |
|
| 304 |
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2AC, static_cast<uint32_t>(MMU.divMod >> 32)); |
|
| 1246 | 305 |
#endif |
| 1247 | 306 |
MMU.divRunning = false; |
| 1248 | 307 |
} |
| 1249 |
- |
|
| 1250 | 308 |
}; |
| 1251 | 309 |
|
| 1252 | 310 |
struct TSequenceItem_sqrtunit : public TSequenceItem |
| 1253 | 311 |
{
|
| 1254 |
- inline bool isTriggered() |
|
| 312 |
+ bool isTriggered() const |
|
| 1255 | 313 |
{
|
| 1256 | 314 |
return MMU.sqrtRunning && nds_timer >= MMU.sqrtCycles; |
| 1257 | 315 |
} |
| 1258 | 316 |
|
| 1259 |
- bool isEnabled() { return MMU.sqrtRunning!=0; }
|
|
| 317 |
+ bool isEnabled() |
|
| 318 |
+ {
|
|
| 319 |
+ return MMU.sqrtRunning; |
|
| 320 |
+ } |
|
| 1260 | 321 |
|
| 1261 |
- inline uint64_t next() |
|
| 322 |
+ uint64_t next() const |
|
| 1262 | 323 |
{
|
| 1263 | 324 |
return MMU.sqrtCycles; |
| 1264 | 325 |
} |
| 1265 | 326 |
|
| 1266 |
- inline void exec() |
|
| 327 |
+ void exec() |
|
| 1267 | 328 |
{
|
| 1268 |
- IF_DEVELOPER(DEBUG_statistics.sequencerExecutionCounters[3]++); |
|
| 1269 | 329 |
MMU_new.sqrt.busy = 0; |
| 1270 | 330 |
T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2B4, MMU.sqrtResult); |
| 1271 | 331 |
MMU.sqrtRunning = false; |
| 1272 | 332 |
} |
| 1273 |
- |
|
| 1274 | 333 |
}; |
| 1275 | 334 |
|
| 1276 | 335 |
struct Sequencer |
| ... | ... |
@@ -1282,75 +341,26 @@ struct Sequencer |
| 1282 | 341 |
TSequenceItem_divider divider; |
| 1283 | 342 |
TSequenceItem_sqrtunit sqrtunit; |
| 1284 | 343 |
TSequenceItem/*_GXFIFO*/ gxfifo; |
| 1285 |
- TSequenceItem_DMA<0,0> dma_0_0; TSequenceItem_DMA<0,1> dma_0_1; |
|
| 1286 |
- TSequenceItem_DMA<0,2> dma_0_2; TSequenceItem_DMA<0,3> dma_0_3; |
|
| 1287 |
- TSequenceItem_DMA<1,0> dma_1_0; TSequenceItem_DMA<1,1> dma_1_1; |
|
| 1288 |
- TSequenceItem_DMA<1,2> dma_1_2; TSequenceItem_DMA<1,3> dma_1_3; |
|
| 1289 |
- TSequenceItem_Timer<0,0> timer_0_0; TSequenceItem_Timer<0,1> timer_0_1; |
|
| 1290 |
- TSequenceItem_Timer<0,2> timer_0_2; TSequenceItem_Timer<0,3> timer_0_3; |
|
| 1291 |
- TSequenceItem_Timer<1,0> timer_1_0; TSequenceItem_Timer<1,1> timer_1_1; |
|
| 1292 |
- TSequenceItem_Timer<1,2> timer_1_2; TSequenceItem_Timer<1,3> timer_1_3; |
|
| 344 |
+ TSequenceItem_DMA<0, 0> dma_0_0; TSequenceItem_DMA<0, 1> dma_0_1; |
|
| 345 |
+ TSequenceItem_DMA<0, 2> dma_0_2; TSequenceItem_DMA<0, 3> dma_0_3; |
|
| 346 |
+ TSequenceItem_DMA<1, 0> dma_1_0; TSequenceItem_DMA<1, 1> dma_1_1; |
|
| 347 |
+ TSequenceItem_DMA<1, 2> dma_1_2; TSequenceItem_DMA<1, 3> dma_1_3; |
|
| 348 |
+ TSequenceItem_Timer<0, 0> timer_0_0; TSequenceItem_Timer<0, 1> timer_0_1; |
|
| 349 |
+ TSequenceItem_Timer<0, 2> timer_0_2; TSequenceItem_Timer<0, 3> timer_0_3; |
|
| 350 |
+ TSequenceItem_Timer<1, 0> timer_1_0; TSequenceItem_Timer<1, 1> timer_1_1; |
|
| 351 |
+ TSequenceItem_Timer<1, 2> timer_1_2; TSequenceItem_Timer<1, 3> timer_1_3; |
|
| 1293 | 352 |
|
| 1294 | 353 |
void init(); |
| 1295 | 354 |
|
| 1296 | 355 |
void execHardware(); |
| 1297 | 356 |
uint64_t findNext(); |
| 1298 |
- |
|
| 1299 |
- /*void save(EMUFILE* os) |
|
| 1300 |
- {
|
|
| 1301 |
- write64le(nds_timer,os); |
|
| 1302 |
- write64le(nds_arm9_timer,os); |
|
| 1303 |
- write64le(nds_arm7_timer,os); |
|
| 1304 |
- dispcnt.save(os); |
|
| 1305 |
- divider.save(os); |
|
| 1306 |
- sqrtunit.save(os); |
|
| 1307 |
- gxfifo.save(os); |
|
| 1308 |
- wifi.save(os); |
|
| 1309 |
-#define SAVE(I,X,Y) I##_##X##_##Y .save(os); |
|
| 1310 |
- SAVE(timer,0,0); SAVE(timer,0,1); SAVE(timer,0,2); SAVE(timer,0,3); |
|
| 1311 |
- SAVE(timer,1,0); SAVE(timer,1,1); SAVE(timer,1,2); SAVE(timer,1,3); |
|
| 1312 |
- SAVE(dma,0,0); SAVE(dma,0,1); SAVE(dma,0,2); SAVE(dma,0,3); |
|
| 1313 |
- SAVE(dma,1,0); SAVE(dma,1,1); SAVE(dma,1,2); SAVE(dma,1,3); |
|
| 1314 |
-#undef SAVE |
|
| 1315 |
- }*/ |
|
| 1316 |
- |
|
| 1317 |
- bool load(EMUFILE* is, int version) |
|
| 1318 |
- {
|
|
| 1319 |
- if(read64le(&nds_timer,is) != 1) return false; |
|
| 1320 |
- if(read64le(&nds_arm9_timer,is) != 1) return false; |
|
| 1321 |
- if(read64le(&nds_arm7_timer,is) != 1) return false; |
|
| 1322 |
- if(!dispcnt.load(is)) return false; |
|
| 1323 |
- if(!divider.load(is)) return false; |
|
| 1324 |
- if(!sqrtunit.load(is)) return false; |
|
| 1325 |
- if(!gxfifo.load(is)) return false; |
|
| 1326 |
- if(version >= 1) if(!wifi.load(is)) return false; |
|
| 1327 |
-#define LOAD(I,X,Y) if(!I##_##X##_##Y .load(is)) return false; |
|
| 1328 |
- LOAD(timer,0,0); LOAD(timer,0,1); LOAD(timer,0,2); LOAD(timer,0,3); |
|
| 1329 |
- LOAD(timer,1,0); LOAD(timer,1,1); LOAD(timer,1,2); LOAD(timer,1,3); |
|
| 1330 |
- LOAD(dma,0,0); LOAD(dma,0,1); LOAD(dma,0,2); LOAD(dma,0,3); |
|
| 1331 |
- LOAD(dma,1,0); LOAD(dma,1,1); LOAD(dma,1,2); LOAD(dma,1,3); |
|
| 1332 |
-#undef LOAD |
|
| 1333 |
- |
|
| 1334 |
- return true; |
|
| 1335 |
- } |
|
| 1336 |
- |
|
| 1337 | 357 |
} sequencer; |
| 1338 | 358 |
|
| 1339 |
-/*void NDS_RescheduleGXFIFO(uint32_t cost) |
|
| 1340 |
-{
|
|
| 1341 |
- //if(!sequencer.gxfifo.enabled) {
|
|
| 1342 |
- //MMU.gfx3dCycles = nds_timer; |
|
| 1343 |
- //sequencer.gxfifo.enabled = true; |
|
| 1344 |
- //} |
|
| 1345 |
- //MMU.gfx3dCycles += cost; |
|
| 1346 |
- NDS_Reschedule(); |
|
| 1347 |
-}*/ |
|
| 1348 |
- |
|
| 1349 | 359 |
void NDS_RescheduleTimers() |
| 1350 | 360 |
{
|
| 1351 |
-#define check(X,Y) sequencer.timer_##X##_##Y .schedule(); |
|
| 1352 |
- check(0,0); check(0,1); check(0,2); check(0,3); |
|
| 1353 |
- check(1,0); check(1,1); check(1,2); check(1,3); |
|
| 361 |
+#define check(X, Y) sequencer.timer_##X##_##Y .schedule(); |
|
| 362 |
+ check(0, 0); check(0, 1); check(0, 2); check(0, 3); |
|
| 363 |
+ check(1, 0); check(1, 1); check(1, 2); check(1, 3); |
|
| 1354 | 364 |
#undef check |
| 1355 | 365 |
|
| 1356 | 366 |
NDS_Reschedule(); |
| ... | ... |
@@ -1360,21 +370,19 @@ void NDS_RescheduleDMA() |
| 1360 | 370 |
{
|
| 1361 | 371 |
//TBD |
| 1362 | 372 |
NDS_Reschedule(); |
| 1363 |
- |
|
| 1364 | 373 |
} |
| 1365 | 374 |
|
| 1366 | 375 |
static void initSchedule() |
| 1367 | 376 |
{
|
| 1368 | 377 |
sequencer.init(); |
| 1369 | 378 |
|
| 1370 |
- //begin at the very end of the last scanline |
|
| 1371 |
- //so that at t=0 we can increment to scanline=0 |
|
| 379 |
+ // begin at the very end of the last scanline |
|
| 380 |
+ // so that at t=0 we can increment to scanline=0 |
|
| 1372 | 381 |
nds.VCount = 262; |
| 1373 | 382 |
|
| 1374 | 383 |
sequencer.nds_vblankEnded = false; |
| 1375 | 384 |
} |
| 1376 | 385 |
|
| 1377 |
- |
|
| 1378 | 386 |
// 2196372 ~= (ARM7_CLOCK << 16) / 1000000 |
| 1379 | 387 |
// This value makes more sense to me, because: |
| 1380 | 388 |
// ARM7_CLOCK = 33.51 mhz |
| ... | ... |
@@ -1388,93 +396,51 @@ void Sequencer::init() |
| 1388 | 396 |
NDS_RescheduleTimers(); |
| 1389 | 397 |
NDS_RescheduleDMA(); |
| 1390 | 398 |
|
| 1391 |
- reschedule = false; |
|
| 399 |
+ this->reschedule = false; |
|
| 1392 | 400 |
nds_timer = 0; |
| 1393 | 401 |
nds_arm9_timer = 0; |
| 1394 | 402 |
nds_arm7_timer = 0; |
| 1395 | 403 |
|
| 1396 |
- dispcnt.enabled = true; |
|
| 1397 |
- dispcnt.param = ESI_DISPCNT_HStart; |
|
| 1398 |
- dispcnt.timestamp = 0; |
|
| 1399 |
- |
|
| 1400 |
- //gxfifo.enabled = false; |
|
| 1401 |
- |
|
| 1402 |
- dma_0_0.controller = &MMU_new.dma[0][0]; |
|
| 1403 |
- dma_0_1.controller = &MMU_new.dma[0][1]; |
|
| 1404 |
- dma_0_2.controller = &MMU_new.dma[0][2]; |
|
| 1405 |
- dma_0_3.controller = &MMU_new.dma[0][3]; |
|
| 1406 |
- dma_1_0.controller = &MMU_new.dma[1][0]; |
|
| 1407 |
- dma_1_1.controller = &MMU_new.dma[1][1]; |
|
| 1408 |
- dma_1_2.controller = &MMU_new.dma[1][2]; |
|
| 1409 |
- dma_1_3.controller = &MMU_new.dma[1][3]; |
|
| 1410 |
- |
|
| 1411 |
- |
|
| 1412 |
- /*#ifdef EXPERIMENTAL_WIFI_COMM |
|
| 1413 |
- wifi.enabled = true; |
|
| 1414 |
- wifi.timestamp = kWifiCycles; |
|
| 1415 |
- #else |
|
| 1416 |
- wifi.enabled = false; |
|
| 1417 |
- #endif*/ |
|
| 404 |
+ this->dispcnt.enabled = true; |
|
| 405 |
+ this->dispcnt.param = ESI_DISPCNT_HStart; |
|
| 406 |
+ this->dispcnt.timestamp = 0; |
|
| 407 |
+ |
|
| 408 |
+ this->dma_0_0.controller = &MMU_new.dma[0][0]; |
|
| 409 |
+ this->dma_0_1.controller = &MMU_new.dma[0][1]; |
|
| 410 |
+ this->dma_0_2.controller = &MMU_new.dma[0][2]; |
|
| 411 |
+ this->dma_0_3.controller = &MMU_new.dma[0][3]; |
|
| 412 |
+ this->dma_1_0.controller = &MMU_new.dma[1][0]; |
|
| 413 |
+ this->dma_1_1.controller = &MMU_new.dma[1][1]; |
|
| 414 |
+ this->dma_1_2.controller = &MMU_new.dma[1][2]; |
|
| 415 |
+ this->dma_1_3.controller = &MMU_new.dma[1][3]; |
|
| 1418 | 416 |
} |
| 1419 | 417 |
|
| 1420 |
-//this isnt helping much right now. work on it later |
|
| 1421 |
-//#include "utils/task.h" |
|
| 1422 |
-//Task taskSubGpu(true); |
|
| 1423 |
-//void* renderSubScreen(void*) |
|
| 1424 |
-//{
|
|
| 1425 |
-// GPU_RenderLine(&SubScreen, nds.VCount, SkipCur2DFrame); |
|
| 1426 |
-// return NULL; |
|
| 1427 |
-//} |
|
| 1428 |
- |
|
| 1429 | 418 |
static void execHardware_hblank() |
| 1430 | 419 |
{
|
| 1431 |
- //this logic keeps moving around. |
|
| 1432 |
- //now, we try and give the game as much time as possible to finish doing its work for the scanline, |
|
| 1433 |
- //by drawing scanline N at the end of drawing time (but before subsequent interrupt or hdma-driven events happen) |
|
| 1434 |
- //don't try to do this at the end of the scanline, because some games (sonic classics) may use hblank IRQ to set |
|
| 1435 |
- //scroll regs for the next scanline |
|
| 1436 |
- if(nds.VCount<192) |
|
| 1437 |
- {
|
|
| 1438 |
- //taskSubGpu.execute(renderSubScreen,NULL); |
|
| 1439 |
- //GPU_RenderLine(&MainScreen, nds.VCount, frameSkipper.ShouldSkip2D()); |
|
| 1440 |
- //GPU_RenderLine(&SubScreen, nds.VCount, frameSkipper.ShouldSkip2D()); |
|
| 1441 |
- //taskSubGpu.finish(); |
|
| 1442 |
- |
|
| 1443 |
- //trigger hblank dmas |
|
| 1444 |
- //but notice, we do that just after we finished drawing the line |
|
| 1445 |
- //(values copied by this hdma should not be used until the next scanline) |
|
| 420 |
+ // this logic keeps moving around. |
|
| 421 |
+ // now, we try and give the game as much time as possible to finish doing its work for the scanline, |
|
| 422 |
+ // by drawing scanline N at the end of drawing time (but before subsequent interrupt or hdma-driven events happen) |
|
| 423 |
+ // don't try to do this at the end of the scanline, because some games (sonic classics) may use hblank IRQ to set |
|
| 424 |
+ // scroll regs for the next scanline |
|
| 425 |
+ if (nds.VCount < 192) |
|
| 426 |
+ // trigger hblank dmas |
|
| 427 |
+ // but notice, we do that just after we finished drawing the line |
|
| 428 |
+ // (values copied by this hdma should not be used until the next scanline) |
|
| 1446 | 429 |
triggerDma(EDMAMode_HBlank); |
| 1447 |
- } |
|
| 1448 | 430 |
|
| 1449 |
- if(nds.VCount==262) |
|
| 1450 |
- {
|
|
| 1451 |
- //we need to trigger one last hblank dma since |
|
| 1452 |
- //a. we're sort of lagged behind by one scanline |
|
| 1453 |
- //b. i think that 193 hblanks actually fire (one for the hblank in scanline 262) |
|
| 1454 |
- //this is demonstrated by NSMB splot-parallaxing clouds |
|
| 1455 |
- //for some reason the game will setup two hdma scroll register buffers |
|
| 1456 |
- //to be run consecutively, and unless we do this, the second buffer will be offset by one scanline |
|
| 1457 |
- //causing a glitch in the 0th scanline |
|
| 1458 |
- //triggerDma(EDMAMode_HBlank); |
|
| 1459 |
- |
|
| 1460 |
- //BUT! this was removed in order to make glitches in megaman zero collection (mmz 4 1st level) work. |
|
| 1461 |
- //and, it seems that it is no longer necessary in nsmb. perhaps something else fixed it |
|
| 1462 |
- } |
|
| 1463 |
- |
|
| 1464 |
- |
|
| 1465 |
- //turn on hblank status bit |
|
| 431 |
+ // turn on hblank status bit |
|
| 1466 | 432 |
T1WriteWord(MMU.ARM9_REG, 4, T1ReadWord(MMU.ARM9_REG, 4) | 2); |
| 1467 | 433 |
T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) | 2); |
| 1468 | 434 |
|
| 1469 |
- //fire hblank interrupts if necessary |
|
| 1470 |
- if(T1ReadWord(MMU.ARM9_REG, 4) & 0x10) NDS_makeIrq(ARMCPU_ARM9,IRQ_BIT_LCD_HBLANK); |
|
| 1471 |
- if(T1ReadWord(MMU.ARM7_REG, 4) & 0x10) NDS_makeIrq(ARMCPU_ARM7,IRQ_BIT_LCD_HBLANK); |
|
| 435 |
+ // fire hblank interrupts if necessary |
|
| 436 |
+ if (T1ReadWord(MMU.ARM9_REG, 4) & 0x10) |
|
| 437 |
+ NDS_makeIrq(ARMCPU_ARM9, IRQ_BIT_LCD_HBLANK); |
|
| 438 |
+ if (T1ReadWord(MMU.ARM7_REG, 4) & 0x10) |
|
| 439 |
+ NDS_makeIrq(ARMCPU_ARM7, IRQ_BIT_LCD_HBLANK); |
|
| 1472 | 440 |
|
| 1473 |
- //emulation housekeeping. for some reason we always do this at hblank, |
|
| 1474 |
- //even though it sounds more reasonable to do it at hstart |
|
| 441 |
+ // emulation housekeeping. for some reason we always do this at hblank, |
|
| 442 |
+ // even though it sounds more reasonable to do it at hstart |
|
| 1475 | 443 |
SPU_Emulate_core(); |
| 1476 |
- //driver->AVI_SoundUpdate(SPU_core->outbuf,spu_core_samples); |
|
| 1477 |
- //WAV_WavSoundUpdate(SPU_core->outbuf,spu_core_samples); |
|
| 1478 | 444 |
} |
| 1479 | 445 |
|
| 1480 | 446 |
static void execHardware_hstart_vblankEnd() |
| ... | ... |
@@ -1482,201 +448,156 @@ static void execHardware_hstart_vblankEnd() |
| 1482 | 448 |
sequencer.nds_vblankEnded = true; |
| 1483 | 449 |
sequencer.reschedule = true; |
| 1484 | 450 |
|
| 1485 |
- //turn off vblank status bit |
|
| 451 |
+ // turn off vblank status bit |
|
| 1486 | 452 |
T1WriteWord(MMU.ARM9_REG, 4, T1ReadWord(MMU.ARM9_REG, 4) & ~1); |
| 1487 | 453 |
T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) & ~1); |
| 1488 |
- |
|
| 1489 |
- //some emulation housekeeping |
|
| 1490 |
- //frameSkipper.Advance(); |
|
| 1491 | 454 |
} |
| 1492 | 455 |
|
| 1493 | 456 |
static void execHardware_hstart_vblankStart() |
| 1494 | 457 |
{
|
| 1495 | 458 |
//printf("--------VBLANK!!!--------\n");
|
| 1496 | 459 |
|
| 1497 |
- //fire vblank interrupts if necessary |
|
| 1498 |
- for(int i=0;i<2;i++) |
|
| 1499 |
- if(MMU.reg_IF_pending[i] & (1<<IRQ_BIT_LCD_VBLANK)) |
|
| 460 |
+ // fire vblank interrupts if necessary |
|
| 461 |
+ for (int i = 0; i < 2; ++i) |
|
| 462 |
+ if (MMU.reg_IF_pending[i] & (1 << IRQ_BIT_LCD_VBLANK)) |
|
| 1500 | 463 |
{
|
| 1501 |
- MMU.reg_IF_pending[i] &= ~(1<<IRQ_BIT_LCD_VBLANK); |
|
| 1502 |
- NDS_makeIrq(i,IRQ_BIT_LCD_VBLANK); |
|
| 464 |
+ MMU.reg_IF_pending[i] &= ~(1 << IRQ_BIT_LCD_VBLANK); |
|
| 465 |
+ NDS_makeIrq(i, IRQ_BIT_LCD_VBLANK); |
|
| 1503 | 466 |
} |
| 1504 | 467 |
|
| 1505 |
- //trigger vblank dmas |
|
| 468 |
+ // trigger vblank dmas |
|
| 1506 | 469 |
triggerDma(EDMAMode_VBlank); |
| 1507 |
- |
|
| 1508 |
- //tracking for arm9 load average |
|
| 1509 |
- //nds.runCycleCollector[0][nds.idleFrameCounter] = 1120380-nds.idleCycles[0]; |
|
| 1510 |
- //nds.runCycleCollector[1][nds.idleFrameCounter] = 1120380-nds.idleCycles[1]; |
|
| 1511 |
- //nds.idleFrameCounter++; |
|
| 1512 |
- //nds.idleFrameCounter &= 15; |
|
| 1513 |
- //nds.idleCycles[0] = 0; |
|
| 1514 |
- //nds.idleCycles[1] = 0; |
|
| 1515 | 470 |
} |
| 1516 | 471 |
|
| 1517 | 472 |
static uint16_t execHardware_gen_vmatch_goal() |
| 1518 | 473 |
{
|
| 1519 | 474 |
uint16_t vmatch = T1ReadWord(MMU.ARM9_REG, 4); |
| 1520 |
- vmatch = ((vmatch>>8)|((vmatch<<1)&(1<<8))); |
|
| 475 |
+ vmatch = (vmatch >> 8) | ((vmatch << 1) & (1 << 8)); |
|
| 1521 | 476 |
return vmatch; |
| 1522 | 477 |
} |
| 1523 | 478 |
|
| 1524 | 479 |
static void execHardware_hstart_vcount_irq() |
| 1525 | 480 |
{
|
| 1526 |
- //trigger pending VMATCH irqs |
|
| 1527 |
- if(MMU.reg_IF_pending[ARMCPU_ARM9] & (1<<IRQ_BIT_LCD_VMATCH)) |
|
| 481 |
+ // trigger pending VMATCH irqs |
|
| 482 |
+ if (MMU.reg_IF_pending[ARMCPU_ARM9] & (1 << IRQ_BIT_LCD_VMATCH)) |
|
| 1528 | 483 |
{
|
| 1529 |
- MMU.reg_IF_pending[ARMCPU_ARM9] &= ~(1<<IRQ_BIT_LCD_VMATCH); |
|
| 1530 |
- NDS_makeIrq(ARMCPU_ARM9,IRQ_BIT_LCD_VMATCH); |
|
| 484 |
+ MMU.reg_IF_pending[ARMCPU_ARM9] &= ~(1 << IRQ_BIT_LCD_VMATCH); |
|
| 485 |
+ NDS_makeIrq(ARMCPU_ARM9, IRQ_BIT_LCD_VMATCH); |
|
| 1531 | 486 |
} |
| 1532 |
- if(MMU.reg_IF_pending[ARMCPU_ARM7] & (1<<IRQ_BIT_LCD_VMATCH)) |
|
| 487 |
+ if(MMU.reg_IF_pending[ARMCPU_ARM7] & (1 << IRQ_BIT_LCD_VMATCH)) |
|
| 1533 | 488 |
{
|
| 1534 |
- MMU.reg_IF_pending[ARMCPU_ARM7] &= ~(1<<IRQ_BIT_LCD_VMATCH); |
|
| 1535 |
- NDS_makeIrq(ARMCPU_ARM7,IRQ_BIT_LCD_VMATCH); |
|
| 489 |
+ MMU.reg_IF_pending[ARMCPU_ARM7] &= ~(1 << IRQ_BIT_LCD_VMATCH); |
|
| 490 |
+ NDS_makeIrq(ARMCPU_ARM7, IRQ_BIT_LCD_VMATCH); |
|
| 1536 | 491 |
} |
| 1537 | 492 |
} |
| 1538 | 493 |
|
| 1539 | 494 |
static void execHardware_hstart_vcount() |
| 1540 | 495 |
{
|
| 1541 | 496 |
uint16_t vmatch = execHardware_gen_vmatch_goal(); |
| 1542 |
- if(nds.VCount==vmatch) |
|
| 497 |
+ if (nds.VCount == vmatch) |
|
| 1543 | 498 |
{
|
| 1544 |
- //arm9 vmatch |
|
| 499 |
+ // arm9 vmatch |
|
| 1545 | 500 |
T1WriteWord(MMU.ARM9_REG, 4, T1ReadWord(MMU.ARM9_REG, 4) | 4); |
| 1546 |
- if(T1ReadWord(MMU.ARM9_REG, 4) & 32) {
|
|
| 1547 |
- MMU.reg_IF_pending[ARMCPU_ARM9] |= (1<<IRQ_BIT_LCD_VMATCH); |
|
| 1548 |
- } |
|
| 501 |
+ if (T1ReadWord(MMU.ARM9_REG, 4) & 32) |
|
| 502 |
+ MMU.reg_IF_pending[ARMCPU_ARM9] |= 1 << IRQ_BIT_LCD_VMATCH; |
|
| 1549 | 503 |
} |
| 1550 | 504 |
else |
| 1551 | 505 |
T1WriteWord(MMU.ARM9_REG, 4, T1ReadWord(MMU.ARM9_REG, 4) & 0xFFFB); |
| 1552 | 506 |
|
| 1553 | 507 |
vmatch = T1ReadWord(MMU.ARM7_REG, 4); |
| 1554 |
- vmatch = ((vmatch>>8)|((vmatch<<1)&(1<<8))); |
|
| 1555 |
- if(nds.VCount==vmatch) |
|
| 508 |
+ vmatch = (vmatch >> 8) | ((vmatch << 1) & (1 << 8)); |
|
| 509 |
+ if (nds.VCount == vmatch) |
|
| 1556 | 510 |
{
|
| 1557 |
- //arm7 vmatch |
|
| 511 |
+ // arm7 vmatch |
|
| 1558 | 512 |
T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) | 4); |
| 1559 |
- if(T1ReadWord(MMU.ARM7_REG, 4) & 32) |
|
| 1560 |
- MMU.reg_IF_pending[ARMCPU_ARM7] |= (1<<IRQ_BIT_LCD_VMATCH); |
|
| 513 |
+ if (T1ReadWord(MMU.ARM7_REG, 4) & 32) |
|
| 514 |
+ MMU.reg_IF_pending[ARMCPU_ARM7] |= 1 << IRQ_BIT_LCD_VMATCH; |
|
| 1561 | 515 |
} |
| 1562 | 516 |
else |
| 1563 | 517 |
T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) & 0xFFFB); |
| 1564 | 518 |
} |
| 1565 | 519 |
|
| 1566 |
-static void execHardware_hdraw() |
|
| 1567 |
-{
|
|
| 1568 |
- //due to hacks in our selection of rendering time, we do not actually render here as intended. |
|
| 1569 |
- //consider changing this if there is some problem with raster fx timing but check the documentation near the gpu rendering calls |
|
| 1570 |
- //to make sure you check for regressions (nsmb, sonic classics, et al) |
|
| 1571 |
-} |
|
| 1572 |
- |
|
| 1573 | 520 |
static void execHardware_hstart_irq() |
| 1574 | 521 |
{
|
| 1575 |
- //this function very soon after the registers get updated to trigger IRQs |
|
| 1576 |
- //this is necessary to fix "egokoro kyoushitsu" which idles waiting for vcount=192, which never happens due to a long vblank irq |
|
| 1577 |
- //100% accurate emulation would require the read of VCOUNT to be in the pipeline already with the irq coming in behind it, thus |
|
| 1578 |
- //allowing the vcount to register as 192 occasionally (maybe about 1 out of 28 frames) |
|
| 1579 |
- //the actual length of the delay is in execHardware() where the events are scheduled |
|
| 522 |
+ // this function very soon after the registers get updated to trigger IRQs |
|
| 523 |
+ // this is necessary to fix "egokoro kyoushitsu" which idles waiting for vcount=192, which never happens due to a long vblank irq |
|
| 524 |
+ // 100% accurate emulation would require the read of VCOUNT to be in the pipeline already with the irq coming in behind it, thus |
|
| 525 |
+ // allowing the vcount to register as 192 occasionally (maybe about 1 out of 28 frames) |
|
| 526 |
+ // the actual length of the delay is in execHardware() where the events are scheduled |
|
| 1580 | 527 |
sequencer.reschedule = true; |
| 1581 |
- if(nds.VCount==192) |
|
| 1582 |
- {
|
|
| 1583 |
- //when the vcount hits 192, vblank begins |
|
| 528 |
+ if (nds.VCount == 192) |
|
| 529 |
+ // when the vcount hits 192, vblank begins |
|
| 1584 | 530 |
execHardware_hstart_vblankStart(); |
| 1585 |
- } |
|
| 1586 | 531 |
|
| 1587 | 532 |
execHardware_hstart_vcount_irq(); |
| 1588 | 533 |
} |
| 1589 | 534 |
|
| 1590 | 535 |
static void execHardware_hstart() |
| 1591 | 536 |
{
|
| 1592 |
- nds.VCount++; |
|
| 1593 |
- |
|
| 1594 |
- //end of 3d vblank |
|
| 1595 |
- //this should be 214, but we are going to be generous for games with tight timing |
|
| 1596 |
- //they shouldnt be changing any textures at 262 but they might accidentally still be at 214 |
|
| 1597 |
- //so.. |
|
| 1598 |
- /*if((CommonSettings.rigorous_timing && nds.VCount==214) || (!CommonSettings.rigorous_timing && nds.VCount==262)) |
|
| 1599 |
- {
|
|
| 1600 |
- gfx3d_VBlankEndSignal(frameSkipper.ShouldSkip3D()); |
|
| 1601 |
- }*/ |
|
| 537 |
+ ++nds.VCount; |
|
| 1602 | 538 |
|
| 1603 |
- if(nds.VCount==263) |
|
| 1604 |
- {
|
|
| 1605 |
- //when the vcount hits 263 it rolls over to 0 |
|
| 1606 |
- nds.VCount=0; |
|
| 1607 |
- } |
|
| 1608 |
- if(nds.VCount==262) |
|
| 1609 |
- {
|
|
| 1610 |
- //when the vcount hits 262, vblank ends (oam pre-renders by one scanline) |
|
| 539 |
+ if (nds.VCount == 263) |
|
| 540 |
+ // when the vcount hits 263 it rolls over to 0 |
|
| 541 |
+ nds.VCount = 0; |
|
| 542 |
+ if (nds.VCount == 262) |
|
| 543 |
+ // when the vcount hits 262, vblank ends (oam pre-renders by one scanline) |
|
| 1611 | 544 |
execHardware_hstart_vblankEnd(); |
| 1612 |
- } |
|
| 1613 |
- /*else if(nds.VCount==191) |
|
| 1614 |
- {
|
|
| 1615 |
- //when the vcount hits 191, the 3d vblank occurs (maybe because OAM doesnt need to run anymore, so we can power it down, and give the 3d as much time as possible?) |
|
| 1616 |
- gfx3d_VBlankSignal(); |
|
| 1617 |
- }*/ |
|
| 1618 |
- else if(nds.VCount==192) |
|
| 545 |
+ else if (nds.VCount == 192) |
|
| 1619 | 546 |
{
|
| 1620 |
- //turn on vblank status bit |
|
| 547 |
+ // turn on vblank status bit |
|
| 1621 | 548 |
T1WriteWord(MMU.ARM9_REG, 4, T1ReadWord(MMU.ARM9_REG, 4) | 1); |
| 1622 | 549 |
T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) | 1); |
| 1623 | 550 |
|
| 1624 |
- //check whether we'll need to fire vblank irqs |
|
| 1625 |
- if(T1ReadWord(MMU.ARM9_REG, 4) & 0x8) MMU.reg_IF_pending[ARMCPU_ARM9] |= (1<<IRQ_BIT_LCD_VBLANK); |
|
| 1626 |
- if(T1ReadWord(MMU.ARM7_REG, 4) & 0x8) MMU.reg_IF_pending[ARMCPU_ARM7] |= (1<<IRQ_BIT_LCD_VBLANK); |
|
| 551 |
+ // check whether we'll need to fire vblank irqs |
|
| 552 |
+ if (T1ReadWord(MMU.ARM9_REG, 4) & 0x8) |
|
| 553 |
+ MMU.reg_IF_pending[ARMCPU_ARM9] |= 1 << IRQ_BIT_LCD_VBLANK; |
|
| 554 |
+ if (T1ReadWord(MMU.ARM7_REG, 4) & 0x8) |
|
| 555 |
+ MMU.reg_IF_pending[ARMCPU_ARM7] |= 1 << IRQ_BIT_LCD_VBLANK; |
|
| 1627 | 556 |
} |
| 1628 | 557 |
|
| 1629 |
- //write the new vcount |
|
| 558 |
+ // write the new vcount |
|
| 1630 | 559 |
T1WriteWord(MMU.ARM9_REG, 6, static_cast<uint16_t>(nds.VCount)); |
| 1631 | 560 |
T1WriteWord(MMU.ARM9_REG, 0x1006, static_cast<uint16_t>(nds.VCount)); |
| 1632 | 561 |
T1WriteWord(MMU.ARM7_REG, 6, static_cast<uint16_t>(nds.VCount)); |
| 1633 | 562 |
T1WriteWord(MMU.ARM7_REG, 0x1006, static_cast<uint16_t>(nds.VCount)); |
| 1634 | 563 |
|
| 1635 |
- //turn off hblank status bit |
|
| 564 |
+ // turn off hblank status bit |
|
| 1636 | 565 |
T1WriteWord(MMU.ARM9_REG, 4, T1ReadWord(MMU.ARM9_REG, 4) & 0xFFFD); |
| 1637 | 566 |
T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) & 0xFFFD); |
| 1638 | 567 |
|
| 1639 |
- //handle vcount status |
|
| 568 |
+ // handle vcount status |
|
| 1640 | 569 |
execHardware_hstart_vcount(); |
| 1641 | 570 |
|
| 1642 |
- //trigger hstart dmas |
|
| 571 |
+ // trigger hstart dmas |
|
| 1643 | 572 |
triggerDma(EDMAMode_HStart); |
| 1644 | 573 |
|
| 1645 |
- if(nds.VCount<192) |
|
| 1646 |
- {
|
|
| 1647 |
- //this is hacky. |
|
| 1648 |
- //there is a corresponding hack in doDMA. |
|
| 1649 |
- //it should be driven by a fifo (and generate just in time as the scanline is displayed) |
|
| 1650 |
- //but that isnt even possible until we have some sort of sub-scanline timing. |
|
| 1651 |
- //it may not be necessary. |
|
| 574 |
+ if (nds.VCount < 192) |
|
| 575 |
+ // this is hacky. |
|
| 576 |
+ // there is a corresponding hack in doDMA. |
|
| 577 |
+ // it should be driven by a fifo (and generate just in time as the scanline is displayed) |
|
| 578 |
+ // but that isnt even possible until we have some sort of sub-scanline timing. |
|
| 579 |
+ // it may not be necessary. |
|
| 1652 | 580 |
triggerDma(EDMAMode_MemDisplay); |
| 1653 |
- } |
|
| 1654 | 581 |
} |
| 1655 | 582 |
|
| 1656 | 583 |
void NDS_Reschedule() |
| 1657 | 584 |
{
|
| 1658 |
- IF_DEVELOPER(if(!sequencer.reschedule) DEBUG_statistics.sequencerExecutionCounters[0]++;); |
|
| 1659 | 585 |
sequencer.reschedule = true; |
| 1660 | 586 |
} |
| 1661 | 587 |
|
| 1662 |
-/*inline uint32_t _fast_min32(uint32_t a, uint32_t b, uint32_t c, uint32_t d) |
|
| 588 |
+static inline uint64_t _fast_min(uint64_t a, uint64_t b) |
|
| 1663 | 589 |
{
|
| 1664 |
- return (( ((int32_t)(a-b)) >> (32-1)) & (c^d)) ^ d; |
|
| 1665 |
-}*/ |
|
| 1666 |
- |
|
| 1667 |
-inline uint64_t _fast_min(uint64_t a, uint64_t b) |
|
| 1668 |
-{
|
|
| 1669 |
- //you might find that this is faster on a 64bit system; someone should try it |
|
| 1670 |
- //http://aggregate.org/MAGIC/#Integer%20Selection |
|
| 590 |
+ // you might find that this is faster on a 64bit system; someone should try it |
|
| 591 |
+ // http://aggregate.org/MAGIC/#Integer%20Selection |
|
| 1671 | 592 |
//uint64_t ret = (((((s64)(a-b)) >> (64-1)) & (a^b)) ^ b); |
| 1672 | 593 |
//assert(ret==min(a,b)); |
| 1673 | 594 |
//return ret; |
| 1674 | 595 |
|
| 1675 |
- //but this ends up being the fastest on 32bits |
|
| 596 |
+ // but this ends up being the fastest on 32bits |
|
| 1676 | 597 |
return a<b?a:b; |
| 1677 | 598 |
|
| 1678 |
- //just for the record, I tried to do the 64bit math on a 32bit proc |
|
| 1679 |
- //using sse2 and it was really slow |
|
| 599 |
+ // just for the record, I tried to do the 64bit math on a 32bit proc |
|
| 600 |
+ // using sse2 and it was really slow |
|
| 1680 | 601 |
//__m128i __a; __a.m128i_u64[0] = a; |
| 1681 | 602 |
//__m128i __b; __b.m128i_u64[0] = b; |
| 1682 | 603 |
//__m128i xorval = _mm_xor_si128(__a,__b); |
| ... | ... |
@@ -1687,28 +608,27 @@ inline uint64_t _fast_min(uint64_t a, uint64_t b) |
| 1687 | 608 |
//return temp.m128i_u64[0]; |
| 1688 | 609 |
} |
| 1689 | 610 |
|
| 1690 |
- |
|
| 1691 |
- |
|
| 1692 | 611 |
uint64_t Sequencer::findNext() |
| 1693 | 612 |
{
|
| 1694 |
- //this one is always enabled so dont bother to check it |
|
| 1695 |
- uint64_t next = dispcnt.next(); |
|
| 1696 |
- |
|
| 1697 |
- if(divider.isEnabled()) next = _fast_min(next,divider.next()); |
|
| 1698 |
- if(sqrtunit.isEnabled()) next = _fast_min(next,sqrtunit.next()); |
|
| 1699 |
- //if(gxfifo.enabled) next = _fast_min(next,gxfifo.next()); |
|
| 613 |
+ // this one is always enabled so dont bother to check it |
|
| 614 |
+ uint64_t next = this->dispcnt.next(); |
|
| 1700 | 615 |
|
| 1701 |
-#ifdef EXPERIMENTAL_WIFI_COMM |
|
| 1702 |
- next = _fast_min(next,wifi.next()); |
|
| 1703 |
-#endif |
|
| 616 |
+ if (this->divider.isEnabled()) |
|
| 617 |
+ next = _fast_min(next, this->divider.next()); |
|
| 618 |
+ if (this->sqrtunit.isEnabled()) |
|
| 619 |
+ next = _fast_min(next, this->sqrtunit.next()); |
|
| 1704 | 620 |
|
| 1705 |
-#define test(X,Y) if(dma_##X##_##Y .isEnabled()) next = _fast_min(next,dma_##X##_##Y .next()); |
|
| 1706 |
- test(0,0); test(0,1); test(0,2); test(0,3); |
|
| 1707 |
- test(1,0); test(1,1); test(1,2); test(1,3); |
|
| 621 |
+#define test(X, Y) \ |
|
| 622 |
+ if (this->dma_##X##_##Y .isEnabled()) \ |
|
| 623 |
+ next = _fast_min(next, this->dma_##X##_##Y .next()); |
|
| 624 |
+ test(0, 0); test(0, 1); test(0, 2); test(0, 3); |
|
| 625 |
+ test(1, 0); test(1, 1); test(1, 2); test(1, 3); |
|
| 1708 | 626 |
#undef test |
| 1709 |
-#define test(X,Y) if(timer_##X##_##Y .enabled) next = _fast_min(next,timer_##X##_##Y .next()); |
|
| 1710 |
- test(0,0); test(0,1); test(0,2); test(0,3); |
|
| 1711 |
- test(1,0); test(1,1); test(1,2); test(1,3); |
|
| 627 |
+#define test(X, Y) \ |
|
| 628 |
+ if (this->timer_##X##_##Y .enabled) \ |
|
| 629 |
+ next = _fast_min(next, this->timer_##X##_##Y .next()); |
|
| 630 |
+ test(0, 0); test(0, 1); test(0, 2); test(0, 3); |
|
| 631 |
+ test(1, 0); test(1, 1); test(1, 2); test(1, 3); |
|
| 1712 | 632 |
#undef test |
| 1713 | 633 |
|
| 1714 | 634 |
return next; |
| ... | ... |
@@ -1716,197 +636,70 @@ uint64_t Sequencer::findNext() |
| 1716 | 636 |
|
| 1717 | 637 |
void Sequencer::execHardware() |
| 1718 | 638 |
{
|
| 1719 |
- if(dispcnt.isTriggered()) |
|
| 639 |
+ if (this->dispcnt.isTriggered()) |
|
| 1720 | 640 |
{
|
| 1721 |
- |
|
| 1722 |
- IF_DEVELOPER(DEBUG_statistics.sequencerExecutionCounters[1]++); |
|
| 1723 |
- |
|
| 1724 |
- switch(dispcnt.param) |
|
| 641 |
+ switch (this->dispcnt.param) |
|
| 1725 | 642 |
{
|
| 1726 |
- case ESI_DISPCNT_HStart: |
|
| 1727 |
- execHardware_hstart(); |
|
| 1728 |
- //(used to be 3168) |
|
| 1729 |
- //hstart is actually 8 dots before the visible drawing begins |
|
| 1730 |
- //we're going to run 1 here and then run 7 in the next case |
|
| 1731 |
- dispcnt.timestamp += 1*6*2; |
|
| 1732 |
- dispcnt.param = ESI_DISPCNT_HStartIRQ; |
|
| 1733 |
- break; |
|
| 1734 |
- case ESI_DISPCNT_HStartIRQ: |
|
| 1735 |
- execHardware_hstart_irq(); |
|
| 1736 |
- dispcnt.timestamp += 7*6*2; |
|
| 1737 |
- dispcnt.param = ESI_DISPCNT_HDraw; |
|
| 1738 |
- break; |
|
| 1739 |
- |
|
| 1740 |
- case ESI_DISPCNT_HDraw: |
|
| 1741 |
- execHardware_hdraw(); |
|
| 1742 |
- //duration of non-blanking period is ~1606 clocks (gbatek agrees) [but says its different on arm7] |
|
| 1743 |
- //im gonna call this 267 dots = 267*6=1602 |
|
| 1744 |
- //so, this event lasts 267 dots minus the 8 dot preroll |
|
| 1745 |
- dispcnt.timestamp += (267-8)*6*2; |
|
| 1746 |
- dispcnt.param = ESI_DISPCNT_HBlank; |
|
| 1747 |
- break; |
|
| 1748 |
- |
|
| 1749 |
- case ESI_DISPCNT_HBlank: |
|
| 1750 |
- execHardware_hblank(); |
|
| 1751 |
- //(once this was 1092 or 1092/12=91 dots.) |
|
| 1752 |
- //there are surely 355 dots per scanline, less 267 for non-blanking period. the rest is hblank and then after that is hstart |
|
| 1753 |
- dispcnt.timestamp += (355-267)*6*2; |
|
| 1754 |
- dispcnt.param = ESI_DISPCNT_HStart; |
|
| 1755 |
- break; |
|
| 643 |
+ case ESI_DISPCNT_HStart: |
|
| 644 |
+ execHardware_hstart(); |
|
| 645 |
+ // (used to be 3168) |
|
| 646 |
+ // hstart is actually 8 dots before the visible drawing begins |
|
| 647 |
+ // we're going to run 1 here and then run 7 in the next case |
|
| 648 |
+ this->dispcnt.timestamp += 12; |
|
| 649 |
+ this->dispcnt.param = ESI_DISPCNT_HStartIRQ; |
|
| 650 |
+ break; |
|
| 651 |
+ case ESI_DISPCNT_HStartIRQ: |
|
| 652 |
+ execHardware_hstart_irq(); |
|
| 653 |
+ this->dispcnt.timestamp += 84; |
|
| 654 |
+ this->dispcnt.param = ESI_DISPCNT_HDraw; |
|
| 655 |
+ break; |
|
| 656 |
+ case ESI_DISPCNT_HDraw: |
|
| 657 |
+ // duration of non-blanking period is ~1606 clocks (gbatek agrees) [but says its different on arm7] |
|
| 658 |
+ // im gonna call this 267 dots = 267*6=1602 |
|
| 659 |
+ // so, this event lasts 267 dots minus the 8 dot preroll |
|
| 660 |
+ this->dispcnt.timestamp += 3108; |
|
| 661 |
+ this->dispcnt.param = ESI_DISPCNT_HBlank; |
|
| 662 |
+ break; |
|
| 663 |
+ case ESI_DISPCNT_HBlank: |
|
| 664 |
+ execHardware_hblank(); |
|
| 665 |
+ // (once this was 1092 or 1092/12=91 dots.) |
|
| 666 |
+ // there are surely 355 dots per scanline, less 267 for non-blanking period. the rest is hblank and then after that is hstart |
|
| 667 |
+ this->dispcnt.timestamp += 1056; |
|
| 668 |
+ this->dispcnt.param = ESI_DISPCNT_HStart; |
|
| 1756 | 669 |
} |
| 1757 | 670 |
} |
| 1758 | 671 |
|
| 1759 |
-#ifdef EXPERIMENTAL_WIFI_COMM |
|
| 1760 |
- if(wifi.isTriggered()) |
|
| 1761 |
- {
|
|
| 1762 |
- WIFI_usTrigger(); |
|
| 1763 |
- wifi.timestamp += kWifiCycles; |
|
| 1764 |
- } |
|
| 1765 |
-#endif |
|
| 1766 |
- |
|
| 1767 |
- if(divider.isTriggered()) divider.exec(); |
|
| 1768 |
- if(sqrtunit.isTriggered()) sqrtunit.exec(); |
|
| 1769 |
- //if(gxfifo.isTriggered()) gxfifo.exec(); |
|
| 1770 |
- |
|
| 672 |
+ if (this->divider.isTriggered()) |
|
| 673 |
+ this->divider.exec(); |
|
| 674 |
+ if (this->sqrtunit.isTriggered()) |
|
| 675 |
+ this->sqrtunit.exec(); |
|
| 1771 | 676 |
|
| 1772 |
-#define test(X,Y) if(dma_##X##_##Y .isTriggered()) dma_##X##_##Y .exec(); |
|
| 1773 |
- test(0,0); test(0,1); test(0,2); test(0,3); |
|
| 1774 |
- test(1,0); test(1,1); test(1,2); test(1,3); |
|
| 677 |
+#define test(X, Y) \ |
|
| 678 |
+ if (this->dma_##X##_##Y .isTriggered()) \ |
|
| 679 |
+ this->dma_##X##_##Y .exec(); |
|
| 680 |
+ test(0, 0); test(0, 1); test(0, 2); test(0, 3); |
|
| 681 |
+ test(1, 0); test(1, 1); test(1, 2); test(1, 3); |
|
| 1775 | 682 |
#undef test |
| 1776 |
-#define test(X,Y) if(timer_##X##_##Y .enabled) if(timer_##X##_##Y .isTriggered()) timer_##X##_##Y .exec(); |
|
| 1777 |
- test(0,0); test(0,1); test(0,2); test(0,3); |
|
| 1778 |
- test(1,0); test(1,1); test(1,2); test(1,3); |
|
| 683 |
+#define test(X, Y) \ |
|
| 684 |
+ if (this->timer_##X##_##Y .enabled && this->timer_##X##_##Y .isTriggered()) \ |
|
| 685 |
+ this->timer_##X##_##Y .exec(); |
|
| 686 |
+ test(0, 0); test(0, 1); test(0, 2); test(0, 3); |
|
| 687 |
+ test(1, 0); test(1, 1); test(1, 2); test(1, 3); |
|
| 1779 | 688 |
#undef test |
| 1780 | 689 |
} |
| 1781 | 690 |
|
| 1782 | 691 |
void execHardware_interrupts(); |
| 1783 | 692 |
|
| 1784 |
-//static void saveUserInput(EMUFILE* os); |
|
| 1785 |
-static bool loadUserInput(EMUFILE* is, int version); |
|
| 1786 |
- |
|
| 1787 |
-/*void nds_savestate(EMUFILE* os) |
|
| 1788 |
-{
|
|
| 1789 |
- //version |
|
| 1790 |
- write32le(3,os); |
|
| 1791 |
- |
|
| 1792 |
- //sequencer.save(os); |
|
| 1793 |
- |
|
| 1794 |
- saveUserInput(os); |
|
| 1795 |
- |
|
| 1796 |
- write32le(LidClosed,os); |
|
| 1797 |
- write8le(countLid,os); |
|
| 1798 |
-}*/ |
|
| 1799 |
- |
|
| 1800 |
-bool nds_loadstate(EMUFILE* is, int) |
|
| 1801 |
-{
|
|
| 1802 |
- // this isn't part of the savestate loading logic, but |
|
| 1803 |
- // don't skip the next frame after loading a savestate |
|
| 1804 |
- //frameSkipper.OmitSkip(true, true); |
|
| 1805 |
- |
|
| 1806 |
- //read version |
|
| 1807 |
- uint32_t version; |
|
| 1808 |
- if(read32le(&version,is) != 1) return false; |
|
| 1809 |
- |
|
| 1810 |
- if(version > 3) return false; |
|
| 1811 |
- |
|
| 1812 |
- bool temp = true; |
|
| 1813 |
- temp &= sequencer.load(is, version); |
|
| 1814 |
- if(version <= 1 || !temp) return temp; |
|
| 1815 |
- temp &= loadUserInput(is, version); |
|
| 1816 |
- |
|
| 1817 |
- if(version < 3) return temp; |
|
| 1818 |
- |
|
| 1819 |
- uint32_t tmpu32; |
|
| 1820 |
- read32le(&tmpu32,is); |
|
| 1821 |
- uint8_t tmpu8; |
|
| 1822 |
- read8le(&tmpu8,is); |
|
| 1823 |
- |
|
| 1824 |
- return temp; |
|
| 1825 |
-} |
|
| 1826 |
- |
|
| 1827 |
-/*inline void arm9log() |
|
| 1828 |
-{
|
|
| 1829 |
-#ifdef LOG_ARM9 |
|
| 1830 |
- if(dolog) |
|
| 1831 |
- {
|
|
| 1832 |
- char dasmbuf[4096]; |
|
| 1833 |
- if(NDS_ARM9.CPSR.bits.T) |
|
| 1834 |
- des_thumb_instructions_set[((NDS_ARM9.instruction)>>6)&1023](NDS_ARM9.instruct_adr, NDS_ARM9.instruction, dasmbuf); |
|
| 1835 |
- else |
|
| 1836 |
- des_arm_instructions_set[INDEX(NDS_ARM9.instruction)](NDS_ARM9.instruct_adr, NDS_ARM9.instruction, dasmbuf); |
|
| 1837 |
- |
|
| 1838 |
-#ifdef LOG_TO_FILE |
|
| 1839 |
- if (!fp_dis9) return; |
|
| 1840 |
-#ifdef LOG_TO_FILE_REGS |
|
| 1841 |
- fprintf(fp_dis9, "\t\t;R0:%08X R1:%08X R2:%08X R3:%08X R4:%08X R5:%08X R6:%08X R7:%08X R8:%08X R9:%08X\n\t\t;R10:%08X R11:%08X R12:%08X R13:%08X R14:%08X R15:%08X| next %08X, N:%i Z:%i C:%i V:%i\n", |
|
| 1842 |
- NDS_ARM9.R[0], NDS_ARM9.R[1], NDS_ARM9.R[2], NDS_ARM9.R[3], NDS_ARM9.R[4], NDS_ARM9.R[5], NDS_ARM9.R[6], NDS_ARM9.R[7], |
|
| 1843 |
- NDS_ARM9.R[8], NDS_ARM9.R[9], NDS_ARM9.R[10], NDS_ARM9.R[11], NDS_ARM9.R[12], NDS_ARM9.R[13], NDS_ARM9.R[14], NDS_ARM9.R[15], |
|
| 1844 |
- NDS_ARM9.next_instruction, NDS_ARM9.CPSR.bits.N, NDS_ARM9.CPSR.bits.Z, NDS_ARM9.CPSR.bits.C, NDS_ARM9.CPSR.bits.V); |
|
| 1845 |
-#endif |
|
| 1846 |
- fprintf(fp_dis9, "%s %08X\t%08X \t%s\n", NDS_ARM9.CPSR.bits.T?"THUMB":"ARM", NDS_ARM9.instruct_adr, NDS_ARM9.instruction, dasmbuf);*/ |
|
| 1847 |
- /*if (NDS_ARM9.instruction == 0) |
|
| 1848 |
- {
|
|
| 1849 |
- dolog = false; |
|
| 1850 |
- INFO("Disassembler is stopped\n");
|
|
| 1851 |
- }*/ |
|
| 1852 |
-/*#else |
|
| 1853 |
- printf("%05d:%03d %12lld 9:%08X %08X %-30s R00:%08X R01:%08X R02:%08X R03:%08X R04:%08X R05:%08X R06:%08X R07:%08X R08:%08X R09:%08X R10:%08X R11:%08X R12:%08X R13:%08X R14:%08X R15:%08X\n",
|
|
| 1854 |
- currFrameCounter, nds.VCount, nds_timer, |
|
| 1855 |
- NDS_ARM9.instruct_adr,NDS_ARM9.instruction, dasmbuf, |
|
| 1856 |
- NDS_ARM9.R[0], NDS_ARM9.R[1], NDS_ARM9.R[2], NDS_ARM9.R[3], NDS_ARM9.R[4], NDS_ARM9.R[5], NDS_ARM9.R[6], NDS_ARM9.R[7], |
|
| 1857 |
- NDS_ARM9.R[8], NDS_ARM9.R[9], NDS_ARM9.R[10], NDS_ARM9.R[11], NDS_ARM9.R[12], NDS_ARM9.R[13], NDS_ARM9.R[14], NDS_ARM9.R[15]); |
|
| 1858 |
-#endif |
|
| 1859 |
- } |
|
| 1860 |
-#endif |
|
| 1861 |
-}*/ |
|
| 1862 |
- |
|
| 1863 |
-/*inline void arm7log() |
|
| 1864 |
-{
|
|
| 1865 |
-#ifdef LOG_ARM7 |
|
| 1866 |
- if(dolog) |
|
| 1867 |
- {
|
|
| 1868 |
- char dasmbuf[4096]; |
|
| 1869 |
- if(NDS_ARM7.CPSR.bits.T) |
|
| 1870 |
- des_thumb_instructions_set[((NDS_ARM7.instruction)>>6)&1023](NDS_ARM7.instruct_adr, NDS_ARM7.instruction, dasmbuf); |
|
| 1871 |
- else |
|
| 1872 |
- des_arm_instructions_set[INDEX(NDS_ARM7.instruction)](NDS_ARM7.instruct_adr, NDS_ARM7.instruction, dasmbuf); |
|
| 1873 |
-#ifdef LOG_TO_FILE |
|
| 1874 |
- if (!fp_dis7) return; |
|
| 1875 |
-#ifdef LOG_TO_FILE_REGS |
|
| 1876 |
- fprintf(fp_dis7, "\t\t;R0:%08X R1:%08X R2:%08X R3:%08X R4:%08X R5:%08X R6:%08X R7:%08X R8:%08X R9:%08X\n\t\t;R10:%08X R11:%08X R12:%08X R13:%08X R14:%08X R15:%08X| next %08X, N:%i Z:%i C:%i V:%i\n", |
|
| 1877 |
- NDS_ARM7.R[0], NDS_ARM7.R[1], NDS_ARM7.R[2], NDS_ARM7.R[3], NDS_ARM7.R[4], NDS_ARM7.R[5], NDS_ARM7.R[6], NDS_ARM7.R[7], |
|
| 1878 |
- NDS_ARM7.R[8], NDS_ARM7.R[9], NDS_ARM7.R[10], NDS_ARM7.R[11], NDS_ARM7.R[12], NDS_ARM7.R[13], NDS_ARM7.R[14], NDS_ARM7.R[15], |
|
| 1879 |
- NDS_ARM7.next_instruction, NDS_ARM7.CPSR.bits.N, NDS_ARM7.CPSR.bits.Z, NDS_ARM7.CPSR.bits.C, NDS_ARM7.CPSR.bits.V); |
|
| 1880 |
-#endif |
|
| 1881 |
- fprintf(fp_dis7, "%s %08X\t%08X \t%s\n", NDS_ARM7.CPSR.bits.T?"THUMB":"ARM", NDS_ARM7.instruct_adr, NDS_ARM7.instruction, dasmbuf);*/ |
|
| 1882 |
- /*if (NDS_ARM7.instruction == 0) |
|
| 1883 |
- {
|
|
| 1884 |
- dolog = false; |
|
| 1885 |
- INFO("Disassembler is stopped\n");
|
|
| 1886 |
- }*/ |
|
| 1887 |
-/*#else |
|
| 1888 |
- printf("%05d:%03d %12lld 7:%08X %08X %-30s R00:%08X R01:%08X R02:%08X R03:%08X R04:%08X R05:%08X R06:%08X R07:%08X R08:%08X R09:%08X R10:%08X R11:%08X R12:%08X R13:%08X R14:%08X R15:%08X\n",
|
|
| 1889 |
- currFrameCounter, nds.VCount, nds_timer, |
|
| 1890 |
- NDS_ARM7.instruct_adr,NDS_ARM7.instruction, dasmbuf, |
|
| 1891 |
- NDS_ARM7.R[0], NDS_ARM7.R[1], NDS_ARM7.R[2], NDS_ARM7.R[3], NDS_ARM7.R[4], NDS_ARM7.R[5], NDS_ARM7.R[6], NDS_ARM7.R[7], |
|
| 1892 |
- NDS_ARM7.R[8], NDS_ARM7.R[9], NDS_ARM7.R[10], NDS_ARM7.R[11], NDS_ARM7.R[12], NDS_ARM7.R[13], NDS_ARM7.R[14], NDS_ARM7.R[15]); |
|
| 1893 |
-#endif |
|
| 1894 |
- } |
|
| 1895 |
-#endif |
|
| 1896 |
-}*/ |
|
| 1897 |
- |
|
| 1898 |
-//these have not been tuned very well yet. |
|
| 693 |
+// these have not been tuned very well yet. |
|
| 1899 | 694 |
static const int kMaxWork = 4000; |
| 1900 | 695 |
static const int kIrqWait = 4000; |
| 1901 | 696 |
|
| 1902 |
- |
|
| 1903 |
-template<bool doarm9, bool doarm7> |
|
| 1904 |
-static inline int32_t minarmtime(int32_t arm9, int32_t arm7) |
|
| 697 |
+template<bool doarm9, bool doarm7> static inline int32_t minarmtime(int32_t arm9, int32_t arm7) |
|
| 1905 | 698 |
{
|
| 1906 |
- if(doarm9) |
|
| 699 |
+ if (doarm9) |
|
| 1907 | 700 |
{
|
| 1908 |
- if(doarm7) |
|
| 1909 |
- return std::min(arm9,arm7); |
|
| 701 |
+ if (doarm7) |
|
| 702 |
+ return std::min(arm9, arm7); |
|
| 1910 | 703 |
else |
| 1911 | 704 |
return arm9; |
| 1912 | 705 |
} |
| ... | ... |
@@ -1914,206 +707,124 @@ static inline int32_t minarmtime(int32_t arm9, int32_t arm7) |
| 1914 | 707 |
return arm7; |
| 1915 | 708 |
} |
| 1916 | 709 |
|
| 710 |
+#ifdef HAVE_JIT |
|
| 711 |
+template<bool doarm9, bool doarm7, bool jit> |
|
| 712 |
+#else |
|
| 1917 | 713 |
template<bool doarm9, bool doarm7> |
| 1918 |
-static /*donotinline*/ std::pair<int32_t,int32_t> armInnerLoop( |
|
| 1919 |
- const uint64_t nds_timer_base, const int32_t s32next, int32_t arm9, int32_t arm7) |
|
| 714 |
+#endif |
|
| 715 |
+static std::pair<int32_t, int32_t> armInnerLoop(uint64_t nds_timer_base, int32_t s32next, int32_t arm9, int32_t arm7) |
|
| 1920 | 716 |
{
|
| 1921 |
- int32_t timer = minarmtime<doarm9,doarm7>(arm9,arm7); |
|
| 1922 |
- while(timer < s32next && !sequencer.reschedule && execute) |
|
| 717 |
+ int32_t timer = minarmtime<doarm9, doarm7>(arm9, arm7); |
|
| 718 |
+ while (timer < s32next && !sequencer.reschedule && execute) |
|
| 1923 | 719 |
{
|
| 1924 |
- if(doarm9 && (!doarm7 || arm9 <= timer)) |
|
| 720 |
+ if (doarm9 && (!doarm7 || arm9 <= timer)) |
|
| 1925 | 721 |
{
|
| 1926 |
- if(!NDS_ARM9.waitIRQ&&!nds.freezeBus) |
|
| 722 |
+ if (!NDS_ARM9.waitIRQ && !nds.freezeBus) |
|
| 1927 | 723 |
{
|
| 1928 |
- //arm9log(); |
|
| 724 |
+#ifdef HAVE_JIT |
|
| 725 |
+ arm9 += armcpu_exec<ARMCPU_ARM9, jit>(); |
|
| 726 |
+#else |
|
| 1929 | 727 |
arm9 += armcpu_exec<ARMCPU_ARM9>(); |
| 1930 |
- #ifdef DEVELOPER |
|
| 1931 |
- nds_debug_continuing[0] = false; |
|
| 1932 |
- #endif |
|
| 728 |
+#endif |
|
| 1933 | 729 |
} |
| 1934 | 730 |
else |
| 1935 |
- {
|
|
| 1936 |
- //int32_t temp = arm9; |
|
| 1937 | 731 |
arm9 = std::min(s32next, arm9 + kIrqWait); |
| 1938 |
- //nds.idleCycles[0] += arm9-temp; |
|
| 1939 |
- //if (gxFIFO.size < 255) nds.freezeBus = false; |
|
| 1940 |
- } |
|
| 1941 | 732 |
} |
| 1942 |
- if(doarm7 && (!doarm9 || arm7 <= timer)) |
|
| 733 |
+ if (doarm7 && (!doarm9 || arm7 <= timer)) |
|
| 1943 | 734 |
{
|
| 1944 |
- if(!NDS_ARM7.waitIRQ&&!nds.freezeBus) |
|
| 735 |
+ if (!NDS_ARM7.waitIRQ && !nds.freezeBus) |
|
| 1945 | 736 |
{
|
| 1946 |
- //arm7log(); |
|
| 1947 |
- arm7 += (armcpu_exec<ARMCPU_ARM7>()<<1); |
|
| 1948 |
- #ifdef DEVELOPER |
|
| 1949 |
- nds_debug_continuing[1] = false; |
|
| 1950 |
- #endif |
|
| 737 |
+#ifdef HAVE_JIT |
|
| 738 |
+ arm7 += armcpu_exec<ARMCPU_ARM7, jit>() << 1; |
|
| 739 |
+#else |
|
| 740 |
+ arm7 += armcpu_exec<ARMCPU_ARM7>() << 1; |
|
| 741 |
+#endif |
|
| 1951 | 742 |
} |
| 1952 | 743 |
else |
| 1953 | 744 |
{
|
| 1954 |
- //int32_t temp = arm7; |
|
| 1955 | 745 |
arm7 = std::min(s32next, arm7 + kIrqWait); |
| 1956 |
- //nds.idleCycles[1] += arm7-temp; |
|
| 1957 |
- if(arm7 == s32next) |
|
| 746 |
+ if (arm7 == s32next) |
|
| 1958 | 747 |
{
|
| 1959 |
- nds_timer = nds_timer_base + minarmtime<doarm9,false>(arm9,arm7); |
|
| 1960 |
- return armInnerLoop<doarm9,false>(nds_timer_base, s32next, arm9, arm7); |
|
| 748 |
+ nds_timer = nds_timer_base + minarmtime<doarm9, false>(arm9, arm7); |
|
| 749 |
+#ifdef HAVE_JIT |
|
| 750 |
+ return armInnerLoop<doarm9, false, jit>(nds_timer_base, s32next, arm9, arm7); |
|
| 751 |
+#else |
|
| 752 |
+ return armInnerLoop<doarm9, false>(nds_timer_base, s32next, arm9, arm7); |
|
| 753 |
+#endif |
|
| 1961 | 754 |
} |
| 1962 | 755 |
} |
| 1963 | 756 |
} |
| 1964 | 757 |
|
| 1965 |
- timer = minarmtime<doarm9,doarm7>(arm9,arm7); |
|
| 758 |
+ timer = minarmtime<doarm9, doarm7>(arm9, arm7); |
|
| 1966 | 759 |
nds_timer = nds_timer_base + timer; |
| 1967 | 760 |
} |
| 1968 | 761 |
|
| 1969 | 762 |
return std::make_pair(arm9, arm7); |
| 1970 | 763 |
} |
| 1971 | 764 |
|
| 1972 |
-/*void NDS_debug_break() |
|
| 1973 |
-{
|
|
| 1974 |
- NDS_ARM9.stalled = NDS_ARM7.stalled = 1; |
|
| 1975 |
- |
|
| 1976 |
- //triggers an immediate exit from the cpu loop |
|
| 1977 |
- NDS_Reschedule(); |
|
| 1978 |
-}*/ |
|
| 1979 |
- |
|
| 1980 |
-/*void NDS_debug_continue() |
|
| 1981 |
-{
|
|
| 1982 |
- NDS_ARM9.stalled = NDS_ARM7.stalled = 0; |
|
| 1983 |
-}*/ |
|
| 1984 |
- |
|
| 1985 |
-/*void NDS_debug_step() |
|
| 765 |
+template<bool FORCE> void NDS_exec(int32_t) |
|
| 1986 | 766 |
{
|
| 1987 |
- NDS_debug_continue(); |
|
| 1988 |
- singleStep = true; |
|
| 1989 |
-}*/ |
|
| 1990 |
- |
|
| 1991 |
-template<bool FORCE> |
|
| 1992 |
-void NDS_exec(int32_t) |
|
| 1993 |
-{
|
|
| 1994 |
- //LagFrameFlag=1; |
|
| 1995 |
- |
|
| 1996 |
- /*if((currFrameCounter&63) == 0) |
|
| 1997 |
- MMU_new.backupDevice.lazy_flush();*/ |
|
| 1998 |
- |
|
| 1999 | 767 |
sequencer.nds_vblankEnded = false; |
| 2000 | 768 |
|
| 2001 |
- //nds.cpuloopIterationCount = 0; |
|
| 2002 |
- |
|
| 2003 |
- IF_DEVELOPER(for(int i=0;i<32;i++) DEBUG_statistics.sequencerExecutionCounters[i] = 0); |
|
| 2004 |
- |
|
| 2005 |
- if(nds.sleeping) |
|
| 769 |
+ if (nds.sleeping) |
|
| 2006 | 770 |
{
|
| 2007 |
- //speculative code: if ANY irq happens, wake up the arm7. |
|
| 2008 |
- //I think the arm7 program analyzes the system and may decide not to wake up |
|
| 2009 |
- //if it is dissatisfied with the conditions |
|
| 2010 |
- if((MMU.reg_IE[1] & MMU.gen_IF<1>())) |
|
| 2011 |
- {
|
|
| 771 |
+ // speculative code: if ANY irq happens, wake up the arm7. |
|
| 772 |
+ // I think the arm7 program analyzes the system and may decide not to wake up |
|
| 773 |
+ // if it is dissatisfied with the conditions |
|
| 774 |
+ if (MMU.reg_IE[1] & MMU.gen_IF<1>()) |
|
| 2012 | 775 |
nds.sleeping = false; |
| 2013 |
- } |
|
| 2014 | 776 |
} |
| 2015 | 777 |
else |
| 2016 | 778 |
{
|
| 2017 |
- for(;;) |
|
| 779 |
+ for (;;) |
|
| 2018 | 780 |
{
|
| 2019 |
- //trap the debug-stalled condition |
|
| 2020 |
- #ifdef DEVELOPER |
|
| 2021 |
- singleStep = false; |
|
| 2022 |
- //(gdb stub doesnt yet know how to trigger these immediately by calling reschedule) |
|
| 2023 |
- while((NDS_ARM9.stalled || NDS_ARM7.stalled) && execute) |
|
| 2024 |
- {
|
|
| 2025 |
- driver->EMU_DebugIdleUpdate(); |
|
| 2026 |
- nds_debug_continuing[0] = nds_debug_continuing[1] = true; |
|
| 2027 |
- } |
|
| 2028 |
- #endif |
|
| 2029 |
- |
|
| 2030 |
- //nds.cpuloopIterationCount++; |
|
| 2031 | 781 |
sequencer.execHardware(); |
| 2032 | 782 |
|
| 2033 |
- //break out once per frame |
|
| 2034 |
- if(sequencer.nds_vblankEnded) break; |
|
| 2035 |
- //it should be benign to execute execHardware in the next frame, |
|
| 2036 |
- //since there won't be anything for it to do (everything should be scheduled in the future) |
|
| 783 |
+ // break out once per frame |
|
| 784 |
+ if (sequencer.nds_vblankEnded) |
|
| 785 |
+ break; |
|
| 786 |
+ // it should be benign to execute execHardware in the next frame, |
|
| 787 |
+ // since there won't be anything for it to do (everything should be scheduled in the future) |
|
| 2037 | 788 |
|
| 2038 |
- //bail in case the system halted |
|
| 2039 |
- if(!execute) break; |
|
| 789 |
+ // bail in case the system halted |
|
| 790 |
+ if (!execute) |
|
| 791 |
+ break; |
|
| 2040 | 792 |
|
| 2041 | 793 |
execHardware_interrupts(); |
| 2042 | 794 |
|
| 2043 |
- //find next work unit: |
|
| 795 |
+ // find next work unit: |
|
| 2044 | 796 |
uint64_t next = sequencer.findNext(); |
| 2045 |
- next = std::min(next,nds_timer+kMaxWork); //lets set an upper limit for now |
|
| 797 |
+ next = std::min(next, nds_timer + kMaxWork); // lets set an upper limit for now |
|
| 2046 | 798 |
|
| 2047 |
- //printf("%d\n",(next-nds_timer));
|
|
| 799 |
+ //printf("%d\n", next - nds_timer);
|
|
| 2048 | 800 |
|
| 2049 | 801 |
sequencer.reschedule = false; |
| 2050 | 802 |
|
| 2051 |
- //cast these down to 32bits so that things run faster on 32bit procs |
|
| 803 |
+ // cast these down to 32bits so that things run faster on 32bit procs |
|
| 2052 | 804 |
uint64_t nds_timer_base = nds_timer; |
| 2053 |
- int32_t arm9 = (int32_t)(nds_arm9_timer-nds_timer); |
|
| 2054 |
- int32_t arm7 = (int32_t)(nds_arm7_timer-nds_timer); |
|
| 2055 |
- int32_t s32next = (int32_t)(next-nds_timer); |
|
| 2056 |
- |
|
| 2057 |
- #ifdef DEVELOPER |
|
| 2058 |
- if(singleStep) |
|
| 2059 |
- {
|
|
| 2060 |
- s32next = 1; |
|
| 2061 |
- } |
|
| 2062 |
- #endif |
|
| 2063 |
- |
|
| 2064 |
- std::pair<int32_t,int32_t> arm9arm7 = armInnerLoop<true,true>(nds_timer_base,s32next,arm9,arm7); |
|
| 805 |
+ int32_t arm9 = static_cast<int32_t>(nds_arm9_timer - nds_timer); |
|
| 806 |
+ int32_t arm7 = static_cast<int32_t>(nds_arm7_timer - nds_timer); |
|
| 807 |
+ int32_t s32next = static_cast<int32_t>(next - nds_timer); |
|
| 2065 | 808 |
|
| 2066 |
- #ifdef DEVELOPER |
|
| 2067 |
- if(singleStep) |
|
| 2068 |
- {
|
|
| 2069 |
- NDS_ARM9.stalled = NDS_ARM7.stalled = 1; |
|
| 2070 |
- } |
|
| 2071 |
- #endif |
|
| 809 |
+#ifdef HAVE_JIT |
|
| 810 |
+ auto arm9arm7 = CommonSettings.use_jit ? armInnerLoop<true, true, true>(nds_timer_base, s32next, arm9, arm7) : armInnerLoop<true, true, false>(nds_timer_base, s32next, arm9, arm7); |
|
| 811 |
+#else |
|
| 812 |
+ auto arm9arm7 = armInnerLoop<true, true>(nds_timer_base, s32next, arm9, arm7); |
|
| 813 |
+#endif |
|
| 2072 | 814 |
|
| 2073 | 815 |
arm9 = arm9arm7.first; |
| 2074 | 816 |
arm7 = arm9arm7.second; |
| 2075 |
- nds_arm7_timer = nds_timer_base+arm7; |
|
| 2076 |
- nds_arm9_timer = nds_timer_base+arm9; |
|
| 817 |
+ nds_arm7_timer = nds_timer_base + arm7; |
|
| 818 |
+ nds_arm9_timer = nds_timer_base + arm9; |
|
| 2077 | 819 |
|
| 2078 |
-#ifndef NDEBUG |
|
| 2079 |
- //what we find here is dependent on the timing constants above |
|
| 2080 |
- //if(nds_timer>next && (nds_timer-next)>22) |
|
| 2081 |
- // printf("curious. please report: over by %d\n",(int)(nds_timer-next));
|
|
| 2082 |
-#endif |
|
| 2083 |
- |
|
| 2084 |
- //if we were waiting for an irq, don't wait too long: |
|
| 2085 |
- //let's re-analyze it after this hardware event (this rolls back a big burst of irq waiting which may have been interrupted by a resynch) |
|
| 2086 |
- if(NDS_ARM9.waitIRQ) |
|
| 2087 |
- {
|
|
| 2088 |
- //nds.idleCycles[0] -= (int32_t)(nds_arm9_timer-nds_timer); |
|
| 820 |
+ // if we were waiting for an irq, don't wait too long: |
|
| 821 |
+ // let's re-analyze it after this hardware event (this rolls back a big burst of irq waiting which may have been interrupted by a resynch) |
|
| 822 |
+ if (NDS_ARM9.waitIRQ) |
|
| 2089 | 823 |
nds_arm9_timer = nds_timer; |
| 2090 |
- } |
|
| 2091 |
- if(NDS_ARM7.waitIRQ) |
|
| 2092 |
- {
|
|
| 2093 |
- //nds.idleCycles[1] -= (int32_t)(nds_arm7_timer-nds_timer); |
|
| 824 |
+ if (NDS_ARM7.waitIRQ) |
|
| 2094 | 825 |
nds_arm7_timer = nds_timer; |
| 2095 |
- } |
|
| 2096 | 826 |
} |
| 2097 | 827 |
} |
| 2098 |
- |
|
| 2099 |
- //DEBUG_statistics.printSequencerExecutionCounters(); |
|
| 2100 |
- //DEBUG_statistics.print(); |
|
| 2101 |
- |
|
| 2102 |
- //end of frame emulation housekeeping |
|
| 2103 |
- /*if(LagFrameFlag) |
|
| 2104 |
- {
|
|
| 2105 |
- lagframecounter++; |
|
| 2106 |
- TotalLagFrames++; |
|
| 2107 |
- } |
|
| 2108 |
- else |
|
| 2109 |
- {
|
|
| 2110 |
- lastLag = lagframecounter; |
|
| 2111 |
- lagframecounter = 0; |
|
| 2112 |
- }*/ |
|
| 2113 |
- //currFrameCounter++; |
|
| 2114 |
- //DEBUG_Notify.NextFrame(); |
|
| 2115 |
- /*if (cheats) |
|
| 2116 |
- cheats->process();*/ |
|
| 2117 | 828 |
} |
| 2118 | 829 |
|
| 2119 | 830 |
template<int PROCNUM> static void execHardware_interrupts_core() |
| ... | ... |
@@ -2121,13 +832,13 @@ template<int PROCNUM> static void execHardware_interrupts_core() |
| 2121 | 832 |
uint32_t IF = MMU.gen_IF<PROCNUM>(); |
| 2122 | 833 |
uint32_t IE = MMU.reg_IE[PROCNUM]; |
| 2123 | 834 |
uint32_t masked = IF & IE; |
| 2124 |
- if(ARMPROC.halt_IE_and_IF && masked) |
|
| 835 |
+ if (ARMPROC.halt_IE_and_IF && masked) |
|
| 2125 | 836 |
{
|
| 2126 | 837 |
ARMPROC.halt_IE_and_IF = false; |
| 2127 | 838 |
ARMPROC.waitIRQ = false; |
| 2128 | 839 |
} |
| 2129 | 840 |
|
| 2130 |
- if(masked && MMU.reg_IME[PROCNUM] && !ARMPROC.CPSR.bits.I) |
|
| 841 |
+ if (masked && MMU.reg_IME[PROCNUM] && !ARMPROC.CPSR.bits.I) |
|
| 2131 | 842 |
{
|
| 2132 | 843 |
//printf("Executing IRQ on procnum %d with IF = %08X and IE = %08X\n",PROCNUM,IF,IE);
|
| 2133 | 844 |
armcpu_irqException(&ARMPROC); |
| ... | ... |
@@ -2140,115 +851,45 @@ void execHardware_interrupts() |
| 2140 | 851 |
execHardware_interrupts_core<ARMCPU_ARM7>(); |
| 2141 | 852 |
} |
| 2142 | 853 |
|
| 2143 |
-//static void resetUserInput(); |
|
| 2144 |
- |
|
| 2145 |
-//bool _HACK_DONT_STOPMOVIE = false; |
|
| 2146 |
-void NDS_Reset() |
|
| 854 |
+static void PrepareBiosARM7() |
|
| 2147 | 855 |
{
|
| 2148 |
- singleStep = false; |
|
| 2149 |
- //nds_debug_continuing[0] = nds_debug_continuing[1] = false; |
|
| 2150 |
- uint32_t src = 0; |
|
| 2151 |
- uint32_t dst = 0; |
|
| 2152 |
- bool fw_success = false; |
|
| 2153 |
- FILE* inf = NULL; |
|
| 2154 |
- NDS_header * header = NDS_getROMHeader(); |
|
| 2155 |
- |
|
| 2156 |
- //DEBUG_reset(); |
|
| 2157 |
- |
|
| 2158 |
- if (!header) return ; |
|
| 2159 |
- |
|
| 2160 |
- nds.sleeping = false; |
|
| 2161 |
- nds.cardEjected = false; |
|
| 2162 |
- nds.freezeBus = 0; |
|
| 2163 |
- //nds.power1.lcd = nds.power1.gpuMain = nds.power1.gfx3d_render = nds.power1.gfx3d_geometry = nds.power1.gpuSub = nds.power1.dispswap = 1; |
|
| 2164 |
- //nds.power2.speakers = 1; |
|
| 2165 |
- //nds.power2.wifi = 0; |
|
| 2166 |
- |
|
| 2167 |
- nds_timer = 0; |
|
| 2168 |
- nds_arm9_timer = 0; |
|
| 2169 |
- nds_arm7_timer = 0; |
|
| 2170 |
- |
|
| 2171 |
- /*if(movieMode != MOVIEMODE_INACTIVE && !_HACK_DONT_STOPMOVIE) |
|
| 2172 |
- movie_reset_command = true;*/ |
|
| 2173 |
- |
|
| 2174 |
- /*if(movieMode == MOVIEMODE_INACTIVE) {
|
|
| 2175 |
- //currFrameCounter = 0; |
|
| 2176 |
- lagframecounter = 0; |
|
| 2177 |
- LagFrameFlag = 0; |
|
| 2178 |
- lastLag = 0; |
|
| 2179 |
- TotalLagFrames = 0; |
|
| 2180 |
- }*/ |
|
| 2181 |
- |
|
| 2182 |
- SPU_DeInit(); |
|
| 2183 |
- |
|
| 2184 |
- MMU_Reset(); |
|
| 2185 |
- |
|
| 2186 |
- //put random garbage in vram for homebrew games, to help mimic the situation where libnds does not clear out junk |
|
| 2187 |
- //which the card's launcher may or may not have left behind |
|
| 2188 |
- //1. retail games dont clear TCM, so why should we jumble it and expect homebrew to clear it? |
|
| 2189 |
- //2. some retail games _dont boot_ if main memory is jumbled. wha...? |
|
| 2190 |
- //3. clearing this is not as useful as tracking uninitialized reads in dev+ builds |
|
| 2191 |
- //4. the vram clearing causes lots of graphical corruptions in badly coded homebrews. this reduces compatibility substantially |
|
| 2192 |
- //conclusion: disable it for now and bring it back as an option |
|
| 2193 |
- //if(gameInfo.isHomebrew) |
|
| 2194 |
- //{
|
|
| 2195 |
- // uint32_t w=100000,x=99,y=117,z=19382173; |
|
| 2196 |
- // CTASSERT(sizeof(MMU.ARM9_LCD) < sizeof(MMU.MAIN_MEM)); |
|
| 2197 |
- // CTASSERT(sizeof(MMU.ARM9_VMEM) < sizeof(MMU.MAIN_MEM)); |
|
| 2198 |
- // CTASSERT(sizeof(MMU.ARM9_ITCM) < sizeof(MMU.MAIN_MEM)); |
|
| 2199 |
- // CTASSERT(sizeof(MMU.ARM9_DTCM) < sizeof(MMU.MAIN_MEM)); |
|
| 2200 |
- // for(int i=0;i<sizeof(MMU.MAIN_MEM);i++) |
|
| 2201 |
- // {
|
|
| 2202 |
- // uint32_t t= (x^(x<<11)); |
|
| 2203 |
- // x=y; |
|
| 2204 |
- // y=z; |
|
| 2205 |
- // z=w; |
|
| 2206 |
- // t = (w= (w^(w>>19))^(t^(t>>8))); |
|
| 2207 |
- // //MMU.MAIN_MEM[i] = t; |
|
| 2208 |
- // if (i<sizeof(MMU.ARM9_LCD)) MMU.ARM9_LCD[i] = t; |
|
| 2209 |
- // if (i<sizeof(MMU.ARM9_VMEM)) MMU.ARM9_VMEM[i] = t; |
|
| 2210 |
- // //if (i<sizeof(MMU.ARM9_ITCM)) MMU.ARM9_ITCM[i] = t; |
|
| 2211 |
- // //if (i<sizeof(MMU.ARM9_DTCM)) MMU.ARM9_DTCM[i] = t; |
|
| 2212 |
- // } |
|
| 2213 |
- //} |
|
| 2214 |
- |
|
| 2215 | 856 |
NDS_ARM7.BIOS_loaded = false; |
| 2216 |
- NDS_ARM9.BIOS_loaded = false; |
|
| 2217 | 857 |
memset(MMU.ARM7_BIOS, 0, sizeof(MMU.ARM7_BIOS)); |
| 2218 |
- memset(MMU.ARM9_BIOS, 0, sizeof(MMU.ARM9_BIOS)); |
|
| 2219 |
- |
|
| 2220 |
- //ARM7 BIOS IRQ HANDLER |
|
| 2221 |
- if(CommonSettings.UseExtBIOS == true) |
|
| 2222 |
- inf = fopen(CommonSettings.ARM7BIOS,"rb"); |
|
| 2223 |
- else |
|
| 2224 |
- inf = NULL; |
|
| 2225 |
- |
|
| 2226 |
- if(inf) |
|
| 858 |
+ if (CommonSettings.UseExtBIOS) |
|
| 2227 | 859 |
{
|
| 2228 |
- if (fread(MMU.ARM7_BIOS,1,16384,inf) == 16384) NDS_ARM7.BIOS_loaded = true; |
|
| 2229 |
- fclose(inf); |
|
| 860 |
+ // read arm7 bios from inputfile and flag it if it succeeds |
|
| 861 |
+ FILE *arm7inf = fopen(CommonSettings.ARM7BIOS, "rb"); |
|
| 862 |
+ if (fread(MMU.ARM7_BIOS, 1, 16384, arm7inf) == 16384) |
|
| 863 |
+ NDS_ARM7.BIOS_loaded = true; |
|
| 864 |
+ fclose(arm7inf); |
|
| 865 |
+ } |
|
| 2230 | 866 |
|
| 2231 |
- if((CommonSettings.SWIFromBIOS) && (NDS_ARM7.BIOS_loaded)) NDS_ARM7.swi_tab = 0; |
|
| 2232 |
- else NDS_ARM7.swi_tab = ARM7_swi_tab; |
|
| 867 |
+ // choose to use SWI emulation or routines from bios |
|
| 868 |
+ if (CommonSettings.SWIFromBIOS && NDS_ARM7.BIOS_loaded) |
|
| 869 |
+ {
|
|
| 870 |
+ NDS_ARM7.swi_tab = 0; |
|
| 2233 | 871 |
|
| 872 |
+ // if we used routines from bios, apply patches |
|
| 2234 | 873 |
if (CommonSettings.PatchSWI3) |
| 2235 | 874 |
_MMU_write16<ARMCPU_ARM7>(0x00002F08, 0x4770); |
| 2236 |
- |
|
| 2237 |
- //INFO("ARM7 BIOS is %s.\n", NDS_ARM7.BIOS_loaded?"loaded":"failed");
|
|
| 2238 | 875 |
} |
| 2239 | 876 |
else |
| 877 |
+ NDS_ARM7.swi_tab = ARM_swi_tab[ARMCPU_ARM7]; |
|
| 878 |
+ |
|
| 879 |
+ if (!NDS_ARM7.BIOS_loaded) |
|
| 2240 | 880 |
{
|
| 2241 |
- NDS_ARM7.swi_tab = ARM7_swi_tab; |
|
| 881 |
+ // fake bios content, critical to normal operations, since we dont have a real bios. |
|
| 2242 | 882 |
|
| 2243 | 883 |
#if 0 |
| 884 |
+ // someone please document what is in progress here |
|
| 2244 | 885 |
// TODO |
| 2245 |
- T1WriteLong(MMU.ARM7_BIOS, 0x0000, 0xEAFFFFFE); // loop for Reset !!! |
|
| 2246 |
- T1WriteLong(MMU.ARM7_BIOS, 0x0004, 0xEAFFFFFE); // loop for Undef instr expection |
|
| 2247 |
- T1WriteLong(MMU.ARM7_BIOS, 0x0008, 0xEA00009C); // SWI |
|
| 2248 |
- T1WriteLong(MMU.ARM7_BIOS, 0x000C, 0xEAFFFFFE); // loop for Prefetch Abort |
|
| 2249 |
- T1WriteLong(MMU.ARM7_BIOS, 0x0010, 0xEAFFFFFE); // loop for Data Abort |
|
| 2250 |
- T1WriteLong(MMU.ARM7_BIOS, 0x0014, 0x00000000); // Reserved |
|
| 2251 |
- T1WriteLong(MMU.ARM7_BIOS, 0x001C, 0x00000000); // Fast IRQ |
|
| 886 |
+ T1WriteLong(MMU.ARM7_BIOS, 0x0000, 0xEAFFFFFE); // loop for Reset !!! |
|
| 887 |
+ T1WriteLong(MMU.ARM7_BIOS, 0x0004, 0xEAFFFFFE); // loop for Undef instr expection |
|
| 888 |
+ T1WriteLong(MMU.ARM7_BIOS, 0x0008, 0xEA00009C); // SWI |
|
| 889 |
+ T1WriteLong(MMU.ARM7_BIOS, 0x000C, 0xEAFFFFFE); // loop for Prefetch Abort |
|
| 890 |
+ T1WriteLong(MMU.ARM7_BIOS, 0x0010, 0xEAFFFFFE); // loop for Data Abort |
|
| 891 |
+ T1WriteLong(MMU.ARM7_BIOS, 0x0014, 0x00000000); // Reserved |
|
| 892 |
+ T1WriteLong(MMU.ARM7_BIOS, 0x001C, 0x00000000); // Fast IRQ |
|
| 2252 | 893 |
#endif |
| 2253 | 894 |
T1WriteLong(MMU.ARM7_BIOS, 0x0000, 0xE25EF002); |
| 2254 | 895 |
T1WriteLong(MMU.ARM7_BIOS, 0x0018, 0xEA000000); |
| ... | ... |
@@ -2259,52 +900,75 @@ void NDS_Reset() |
| 2259 | 900 |
T1WriteLong(MMU.ARM7_BIOS, 0x0030, 0xE8BD500F); |
| 2260 | 901 |
T1WriteLong(MMU.ARM7_BIOS, 0x0034, 0xE25EF004); |
| 2261 | 902 |
} |
| 903 |
+} |
|
| 2262 | 904 |
|
| 2263 |
- //ARM9 BIOS IRQ HANDLER |
|
| 2264 |
- if(CommonSettings.UseExtBIOS == true) |
|
| 2265 |
- inf = fopen(CommonSettings.ARM9BIOS,"rb"); |
|
| 2266 |
- else |
|
| 2267 |
- inf = NULL; |
|
| 2268 |
- |
|
| 2269 |
- if(inf) |
|
| 905 |
+static void PrepareBiosARM9() |
|
| 906 |
+{
|
|
| 907 |
+ memset(MMU.ARM9_BIOS, 0, sizeof(MMU.ARM9_BIOS)); |
|
| 908 |
+ NDS_ARM9.BIOS_loaded = false; |
|
| 909 |
+ if (CommonSettings.UseExtBIOS) |
|
| 2270 | 910 |
{
|
| 2271 |
- if (fread(MMU.ARM9_BIOS,1,4096,inf) == 4096) NDS_ARM9.BIOS_loaded = true; |
|
| 2272 |
- fclose(inf); |
|
| 2273 |
- |
|
| 2274 |
- if((CommonSettings.SWIFromBIOS) && (NDS_ARM9.BIOS_loaded)) NDS_ARM9.swi_tab = 0; |
|
| 2275 |
- else NDS_ARM9.swi_tab = ARM9_swi_tab; |
|
| 911 |
+ // read arm9 bios from inputfile and flag it if it succeeds |
|
| 912 |
+ FILE *arm9inf = fopen(CommonSettings.ARM9BIOS, "rb"); |
|
| 913 |
+ if (fread(MMU.ARM9_BIOS, 1, 4096, arm9inf) == 4096) |
|
| 914 |
+ NDS_ARM9.BIOS_loaded = true; |
|
| 915 |
+ fclose(arm9inf); |
|
| 916 |
+ } |
|
| 2276 | 917 |
|
| 918 |
+ // choose to use SWI emulation or routines from bios |
|
| 919 |
+ if (CommonSettings.SWIFromBIOS && NDS_ARM9.BIOS_loaded) |
|
| 920 |
+ {
|
|
| 921 |
+ NDS_ARM9.swi_tab = 0; |
|
| 922 |
+ |
|
| 923 |
+ // if we used routines from bios, apply patches |
|
| 2277 | 924 |
if (CommonSettings.PatchSWI3) |
| 2278 | 925 |
_MMU_write16<ARMCPU_ARM9>(0xFFFF07CC, 0x4770); |
| 2279 |
- |
|
| 2280 |
- //INFO("ARM9 BIOS is %s.\n", NDS_ARM9.BIOS_loaded?"loaded":"failed");
|
|
| 2281 | 926 |
} |
| 2282 | 927 |
else |
| 928 |
+ NDS_ARM9.swi_tab = ARM_swi_tab[ARMCPU_ARM9]; |
|
| 929 |
+ |
|
| 930 |
+ if (!NDS_ARM9.BIOS_loaded) |
|
| 2283 | 931 |
{
|
| 2284 |
- NDS_ARM9.swi_tab = ARM9_swi_tab; |
|
| 932 |
+ // fake bios content, critical to normal operations, since we dont have a real bios. |
|
| 933 |
+ // it'd be cool if we could write this in some kind of assembly language, inline or otherwise, without some bulky dependencies |
|
| 934 |
+ // perhaps we could build it with devkitarm? but thats bulky (offline) dependencies, to be sure.. |
|
| 2285 | 935 |
|
| 2286 |
- //bios chains data abort to fast irq |
|
| 936 |
+ // reminder: bios chains data abort to fast irq |
|
| 2287 | 937 |
|
| 2288 |
- //exception vectors: |
|
| 2289 |
- T1WriteLong(MMU.ARM9_BIOS, 0x0000, 0xEAFFFFFE); // (infinite loop for) Reset !!! |
|
| 2290 |
- //T1WriteLong(MMU.ARM9_BIOS, 0x0004, 0xEAFFFFFE); // (infinite loop for) Undefined instruction |
|
| 2291 |
- T1WriteLong(MMU.ARM9_BIOS, 0x0004, 0xEA000004); // Undefined instruction -> Fast IRQ (just guessing) |
|
| 2292 |
- T1WriteLong(MMU.ARM9_BIOS, 0x0008, 0xEA00009C); // SWI -> ????? |
|
| 2293 |
- T1WriteLong(MMU.ARM9_BIOS, 0x000C, 0xEAFFFFFE); // (infinite loop for) Prefetch Abort |
|
| 2294 |
- T1WriteLong(MMU.ARM9_BIOS, 0x0010, 0xEA000001); // Data Abort -> Fast IRQ |
|
| 2295 |
- T1WriteLong(MMU.ARM9_BIOS, 0x0014, 0x00000000); // Reserved |
|
| 2296 |
- T1WriteLong(MMU.ARM9_BIOS, 0x0018, 0xEA000095); // Normal IRQ -> 0x0274 |
|
| 2297 |
- T1WriteLong(MMU.ARM9_BIOS, 0x001C, 0xEA00009D); // Fast IRQ -> 0x0298 |
|
| 938 |
+ // exception vectors: |
|
| 939 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x0000, 0xEAFFFFFE); // (infinite loop for) Reset !!! |
|
| 940 |
+ //T1WriteLong(MMU.ARM9_BIOS, 0x0004, 0xEAFFFFFE); // (infinite loop for) Undefined instruction |
|
| 941 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x0004, 0xEA000004); // Undefined instruction -> Fast IRQ (just guessing) |
|
| 942 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x0008, 0xEA00009C); // SWI -> ????? |
|
| 943 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x000C, 0xEAFFFFFE); // (infinite loop for) Prefetch Abort |
|
| 944 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x0010, 0xEA000001); // Data Abort -> Fast IRQ |
|
| 945 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x0014, 0x00000000); // Reserved |
|
| 946 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x0018, 0xEA000095); // Normal IRQ -> 0x0274 |
|
| 947 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x001C, 0xEA00009D); // Fast IRQ -> 0x0298 |
|
| 948 |
+ |
|
| 949 |
+ static const uint8_t logo_data[] = |
|
| 950 |
+ {
|
|
| 951 |
+ 0x24, 0xFF, 0xAE, 0x51, 0x69, 0x9A, 0xA2, 0x21, 0x3D, 0x84, 0x82, 0x0A, 0x84, 0xE4, 0x09, 0xAD, |
|
| 952 |
+ 0x11, 0x24, 0x8B, 0x98, 0xC0, 0x81, 0x7F, 0x21, 0xA3, 0x52, 0xBE, 0x19, 0x93, 0x09, 0xCE, 0x20, |
|
| 953 |
+ 0x10, 0x46, 0x4A, 0x4A, 0xF8, 0x27, 0x31, 0xEC, 0x58, 0xC7, 0xE8, 0x33, 0x82, 0xE3, 0xCE, 0xBF, |
|
| 954 |
+ 0x85, 0xF4, 0xDF, 0x94, 0xCE, 0x4B, 0x09, 0xC1, 0x94, 0x56, 0x8A, 0xC0, 0x13, 0x72, 0xA7, 0xFC, |
|
| 955 |
+ 0x9F, 0x84, 0x4D, 0x73, 0xA3, 0xCA, 0x9A, 0x61, 0x58, 0x97, 0xA3, 0x27, 0xFC, 0x03, 0x98, 0x76, |
|
| 956 |
+ 0x23, 0x1D, 0xC7, 0x61, 0x03, 0x04, 0xAE, 0x56, 0xBF, 0x38, 0x84, 0x00, 0x40, 0xA7, 0x0E, 0xFD, |
|
| 957 |
+ 0xFF, 0x52, 0xFE, 0x03, 0x6F, 0x95, 0x30, 0xF1, 0x97, 0xFB, 0xC0, 0x85, 0x60, 0xD6, 0x80, 0x25, |
|
| 958 |
+ 0xA9, 0x63, 0xBE, 0x03, 0x01, 0x4E, 0x38, 0xE2, 0xF9, 0xA2, 0x34, 0xFF, 0xBB, 0x3E, 0x03, 0x44, |
|
| 959 |
+ 0x78, 0x00, 0x90, 0xCB, 0x88, 0x11, 0x3A, 0x94, 0x65, 0xC0, 0x7C, 0x63, 0x87, 0xF0, 0x3C, 0xAF, |
|
| 960 |
+ 0xD6, 0x25, 0xE4, 0x8B, 0x38, 0x0A, 0xAC, 0x72, 0x21, 0xD4, 0xF8, 0x07 |
|
| 961 |
+ }; |
|
| 2298 | 962 |
|
| 2299 | 963 |
// logo (do some games fail to boot without this? example?) |
| 2300 |
- for (int t = 0; t < 0x9C; t++) |
|
| 964 |
+ for (int t = 0; t < 0x9C; ++t) |
|
| 2301 | 965 |
MMU.ARM9_BIOS[t + 0x20] = logo_data[t]; |
| 2302 | 966 |
|
| 2303 | 967 |
//...0xBC: |
| 2304 | 968 |
|
| 2305 |
- //(now what goes in this gap??) |
|
| 969 |
+ // (now what goes in this gap??) |
|
| 2306 | 970 |
|
| 2307 |
- //IRQ handler: get dtcm address and jump to a vector in it |
|
| 971 |
+ // IRQ handler: get dtcm address and jump to a vector in it |
|
| 2308 | 972 |
T1WriteLong(MMU.ARM9_BIOS, 0x0274, 0xE92D500F); //STMDB SP!, {R0-R3,R12,LR}
|
| 2309 | 973 |
T1WriteLong(MMU.ARM9_BIOS, 0x0278, 0xEE190F11); //MRC CP15, 0, R0, CR9, CR1, 0 |
| 2310 | 974 |
T1WriteLong(MMU.ARM9_BIOS, 0x027C, 0xE1A00620); //MOV R0, R0, LSR #C |
| ... | ... |
@@ -2313,81 +977,100 @@ void NDS_Reset() |
| 2313 | 977 |
T1WriteLong(MMU.ARM9_BIOS, 0x0288, 0xE28FE000); //ADD LR, PC, #0 |
| 2314 | 978 |
T1WriteLong(MMU.ARM9_BIOS, 0x028C, 0xE510F004); //LDR PC, [R0, -#4] |
| 2315 | 979 |
|
| 2316 |
- //???? |
|
| 2317 |
- T1WriteLong(MMU.ARM9_BIOS, 0x0290, 0xE8BD500F); //LDMIA SP!, {R0-R3,R12,LR}
|
|
| 2318 |
- T1WriteLong(MMU.ARM9_BIOS, 0x0294, 0xE25EF004); //SUBS PC, LR, #4 |
|
| 2319 |
- |
|
| 2320 |
- //------- |
|
| 2321 |
- //FIQ and abort exception handler |
|
| 2322 |
- //TODO - this code is copied from the bios. refactor it |
|
| 2323 |
- //friendly reminder: to calculate an immediate offset: encoded = (desired_address-cur_address-8) |
|
| 980 |
+ // ???? |
|
| 981 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x0290, 0xE8BD500F); // LDMIA SP!, {R0-R3,R12,LR}
|
|
| 982 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x0294, 0xE25EF004); // SUBS PC, LR, #4 |
|
| 2324 | 983 |
|
| 2325 |
- T1WriteLong(MMU.ARM9_BIOS, 0x0298, 0xE10FD000); //MRS SP, CPSR |
|
| 2326 |
- T1WriteLong(MMU.ARM9_BIOS, 0x029C, 0xE38DD0C0); //ORR SP, SP, #C0 |
|
| 984 |
+ // ------- |
|
| 985 |
+ // FIQ and abort exception handler |
|
| 986 |
+ // TODO - this code is copied from the bios. refactor it |
|
| 987 |
+ // friendly reminder: to calculate an immediate offset: encoded = (desired_address-cur_address-8) |
|
| 2327 | 988 |
|
| 2328 |
- T1WriteLong(MMU.ARM9_BIOS, 0x02A0, 0xE12FF00D); //MSR CPSR_fsxc, SP |
|
| 2329 |
- T1WriteLong(MMU.ARM9_BIOS, 0x02A4, 0xE59FD000 | (0x2D4-0x2A4-8)); //LDR SP, [FFFF02D4] |
|
| 2330 |
- T1WriteLong(MMU.ARM9_BIOS, 0x02A8, 0xE28DD001); //ADD SP, SP, #1 |
|
| 2331 |
- T1WriteLong(MMU.ARM9_BIOS, 0x02AC, 0xE92D5000); //STMDB SP!, {R12,LR}
|
|
| 989 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x0298, 0xE10FD000); // MRS SP, CPSR |
|
| 990 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x029C, 0xE38DD0C0); // ORR SP, SP, #C0 |
|
| 2332 | 991 |
|
| 2333 |
- T1WriteLong(MMU.ARM9_BIOS, 0x02B0, 0xE14FE000); //MRS LR, SPSR |
|
| 2334 |
- T1WriteLong(MMU.ARM9_BIOS, 0x02B4, 0xEE11CF10); //MRC CP15, 0, R12, CR1, CR0, 0 |
|
| 2335 |
- T1WriteLong(MMU.ARM9_BIOS, 0x02B8, 0xE92D5000); //STMDB SP!, {R12,LR}
|
|
| 2336 |
- T1WriteLong(MMU.ARM9_BIOS, 0x02BC, 0xE3CCC001); //BIC R12, R12, #1 |
|
| 992 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x02A0, 0xE12FF00D); // MSR CPSR_fsxc, SP |
|
| 993 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x02A4, 0xE59FD028); // LDR SP, [FFFF02D4] |
|
| 994 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x02A8, 0xE28DD001); // ADD SP, SP, #1 |
|
| 995 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x02AC, 0xE92D5000); // STMDB SP!, {R12,LR}
|
|
| 2337 | 996 |
|
| 2338 |
- T1WriteLong(MMU.ARM9_BIOS, 0x02C0, 0xEE01CF10); //MCR CP15, 0, R12, CR1, CR0, 0 |
|
| 2339 |
- T1WriteLong(MMU.ARM9_BIOS, 0x02C4, 0xE3CDC001); //BIC R12, SP, #1 |
|
| 2340 |
- T1WriteLong(MMU.ARM9_BIOS, 0x02C8, 0xE59CC010); //LDR R12, [R12, #10] |
|
| 2341 |
- T1WriteLong(MMU.ARM9_BIOS, 0x02CC, 0xE35C0000); //CMP R12, #0 |
|
| 997 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x02B0, 0xE14FE000); // MRS LR, SPSR |
|
| 998 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x02B4, 0xEE11CF10); // MRC CP15, 0, R12, CR1, CR0, 0 |
|
| 999 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x02B8, 0xE92D5000); // STMDB SP!, {R12,LR}
|
|
| 1000 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x02BC, 0xE3CCC001); // BIC R12, R12, #1 |
|
| 2342 | 1001 |
|
| 2343 |
- T1WriteLong(MMU.ARM9_BIOS, 0x02D0, 0x112FFF3C); //BLXNE R12 |
|
| 2344 |
- T1WriteLong(MMU.ARM9_BIOS, 0x02D4, 0x027FFD9C); //0x027FFD9C |
|
| 2345 |
- //--------- |
|
| 1002 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x02C0, 0xEE01CF10); // MCR CP15, 0, R12, CR1, CR0, 0 |
|
| 1003 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x02C4, 0xE3CDC001); // BIC R12, SP, #1 |
|
| 1004 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x02C8, 0xE59CC010); // LDR R12, [R12, #10] |
|
| 1005 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x02CC, 0xE35C0000); // CMP R12, #0 |
|
| 2346 | 1006 |
|
| 1007 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x02D0, 0x112FFF3C); // BLXNE R12 |
|
| 1008 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x02D4, 0x027FFD9C); // 0x027FFD9C |
|
| 1009 |
+ // --------- |
|
| 2347 | 1010 |
} |
| 1011 |
+} |
|
| 2348 | 1012 |
|
| 2349 |
-#ifdef LOG_ARM7 |
|
| 2350 |
- if (fp_dis7 != NULL) |
|
| 2351 |
- {
|
|
| 2352 |
- fclose(fp_dis7); |
|
| 2353 |
- fp_dis7 = NULL; |
|
| 2354 |
- } |
|
| 2355 |
- fp_dis7 = fopen("D:\\desmume_dis7.asm", "w");
|
|
| 2356 |
-#endif |
|
| 1013 |
+void NDS_Reset() |
|
| 1014 |
+{
|
|
| 1015 |
+ singleStep = false; |
|
| 1016 |
+ bool fw_success = false; |
|
| 1017 |
+ auto header = NDS_getROMHeader(); |
|
| 2357 | 1018 |
|
| 2358 |
-#ifdef LOG_ARM9 |
|
| 2359 |
- if (fp_dis9 != NULL) |
|
| 2360 |
- {
|
|
| 2361 |
- fclose(fp_dis9); |
|
| 2362 |
- fp_dis9 = NULL; |
|
| 2363 |
- } |
|
| 2364 |
- fp_dis9 = fopen("D:\\desmume_dis9.asm", "w");
|
|
| 1019 |
+ if (!header) |
|
| 1020 |
+ return; |
|
| 1021 |
+ |
|
| 1022 |
+ nds.sleeping = false; |
|
| 1023 |
+ nds.cardEjected = false; |
|
| 1024 |
+ nds.freezeBus = 0; |
|
| 1025 |
+ |
|
| 1026 |
+ nds_timer = 0; |
|
| 1027 |
+ nds_arm9_timer = 0; |
|
| 1028 |
+ nds_arm7_timer = 0; |
|
| 1029 |
+ |
|
| 1030 |
+ SPU_DeInit(); |
|
| 1031 |
+ |
|
| 1032 |
+ MMU_Reset(); |
|
| 1033 |
+ |
|
| 1034 |
+#ifdef HAVE_JIT |
|
| 1035 |
+ arm_jit_reset(CommonSettings.use_jit); |
|
| 2365 | 1036 |
#endif |
| 2366 | 1037 |
|
| 2367 |
- if (firmware) |
|
| 2368 |
- {
|
|
| 2369 |
- delete firmware; |
|
| 2370 |
- firmware = NULL; |
|
| 2371 |
- } |
|
| 2372 |
- firmware = new CFIRMWARE(); |
|
| 1038 |
+ PrepareBiosARM7(); |
|
| 1039 |
+ PrepareBiosARM9(); |
|
| 1040 |
+ |
|
| 1041 |
+ // according to smea, this is initialized to 3 by the time we get into a user game program. who does this? |
|
| 1042 |
+ // well, the firmware load process is about to write a boot program into SIWRAM for the arm7. so we need it setup by now. |
|
| 1043 |
+ // but, this is a bit weird.. I would be expecting the bioses to do that. maybe we have some more detail to emulate. |
|
| 1044 |
+ // * is this setting the default, or does the bios do it before loading the firmware programs? |
|
| 1045 |
+ // at any, it's important that this be done long before the user code ever runs |
|
| 1046 |
+ _MMU_write08<ARMCPU_ARM9>(REG_WRAMCNT, 3); |
|
| 1047 |
+ |
|
| 1048 |
+ firmware.reset(new CFIRMWARE()); |
|
| 2373 | 1049 |
fw_success = firmware->load(); |
| 1050 |
+ |
|
| 2374 | 1051 |
if (NDS_ARM7.BIOS_loaded && NDS_ARM9.BIOS_loaded && CommonSettings.BootFromFirmware && fw_success) |
| 2375 | 1052 |
{
|
| 2376 |
- // Copy secure area to memory if needed |
|
| 2377 |
- if ((header->ARM9src >= 0x4000) && (header->ARM9src < 0x8000)) |
|
| 1053 |
+ // Copy secure area to memory if needed. |
|
| 1054 |
+ // could we get a comment about what's going on here? |
|
| 1055 |
+ // how does this stuff get copied before anything ever even runs? |
|
| 1056 |
+ // does it get mapped straight to the rom somehow? |
|
| 1057 |
+ // This code could be made more clear too. |
|
| 1058 |
+ if (header->ARM9src >= 0x4000 && header->ARM9src < 0x8000) |
|
| 2378 | 1059 |
{
|
| 2379 |
- src = header->ARM9src; |
|
| 2380 |
- dst = header->ARM9cpy; |
|
| 1060 |
+ uint32_t src = header->ARM9src; |
|
| 1061 |
+ uint32_t dst = header->ARM9cpy; |
|
| 2381 | 1062 |
|
| 2382 | 1063 |
uint32_t size = (0x8000 - src) >> 2; |
| 2383 |
- //INFO("Copy secure area from 0x%08X to 0x%08X (size %i/0x%08X)\n", src, dst, size, size);
|
|
| 2384 |
- for (uint32_t i = 0; i < size; i++) |
|
| 1064 |
+ |
|
| 1065 |
+ for (uint32_t i = 0; i < size; ++i) |
|
| 2385 | 1066 |
{
|
| 2386 | 1067 |
_MMU_write32<ARMCPU_ARM9>(dst, T1ReadLong(MMU.CART_ROM, src)); |
| 2387 |
- src += 4; dst += 4; |
|
| 1068 |
+ src += 4; |
|
| 1069 |
+ dst += 4; |
|
| 2388 | 1070 |
} |
| 2389 | 1071 |
} |
| 2390 | 1072 |
|
| 1073 |
+ // TODO someone describe why here |
|
| 2391 | 1074 |
if (firmware->patched) |
| 2392 | 1075 |
{
|
| 2393 | 1076 |
armcpu_init(&NDS_ARM7, 0x00000008); |
| ... | ... |
@@ -2395,138 +1078,107 @@ void NDS_Reset() |
| 2395 | 1078 |
} |
| 2396 | 1079 |
else |
| 2397 | 1080 |
{
|
| 2398 |
- //INFO("Booting at ARM9: 0x%08X, ARM7: 0x%08X\n", firmware->ARM9bootAddr, firmware->ARM7bootAddr);
|
|
| 2399 |
- // need for firmware |
|
| 2400 |
- //armcpu_init(&NDS_ARM7, 0x00000008); |
|
| 2401 |
- //armcpu_init(&NDS_ARM9, 0xFFFF0008); |
|
| 1081 |
+ // set the cpus to an initial state with their respective firmware program entrypoints |
|
| 2402 | 1082 |
armcpu_init(&NDS_ARM7, firmware->ARM7bootAddr); |
| 2403 | 1083 |
armcpu_init(&NDS_ARM9, firmware->ARM9bootAddr); |
| 2404 | 1084 |
} |
| 2405 | 1085 |
|
| 2406 |
- _MMU_write08<ARMCPU_ARM9>(0x04000300, 0); |
|
| 2407 |
- _MMU_write08<ARMCPU_ARM7>(0x04000300, 0); |
|
| 1086 |
+ // set REG_POSTFLG to the value indicating pre-firmware status |
|
| 1087 |
+ MMU.ARM9_REG[0x300] = 0; |
|
| 1088 |
+ MMU.ARM7_REG[0x300] = 0; |
|
| 2408 | 1089 |
} |
| 2409 | 1090 |
else |
| 2410 | 1091 |
{
|
| 2411 |
- src = header->ARM9src; |
|
| 2412 |
- dst = header->ARM9cpy; |
|
| 1092 |
+ // fake firmware boot-up process |
|
| 2413 | 1093 |
|
| 2414 |
- for(uint32_t i = 0; i < (header->ARM9binSize>>2); ++i) |
|
| 1094 |
+ // copy the arm9 program to the address specified by rom header |
|
| 1095 |
+ uint32_t src = header->ARM9src; |
|
| 1096 |
+ uint32_t dst = header->ARM9cpy; |
|
| 1097 |
+ for (uint32_t i = 0; i < (header->ARM9binSize >> 2); ++i) |
|
| 2415 | 1098 |
{
|
| 2416 | 1099 |
_MMU_write32<ARMCPU_ARM9>(dst, T1ReadLong(MMU.CART_ROM, src)); |
| 2417 | 1100 |
dst += 4; |
| 2418 | 1101 |
src += 4; |
| 2419 | 1102 |
} |
| 2420 | 1103 |
|
| 1104 |
+ // copy the arm7 program to the address specified by rom header |
|
| 2421 | 1105 |
src = header->ARM7src; |
| 2422 | 1106 |
dst = header->ARM7cpy; |
| 2423 | 1107 |
|
| 2424 |
- for(uint32_t i = 0; i < (header->ARM7binSize>>2); ++i) |
|
| 1108 |
+ for (uint32_t i = 0; i < (header->ARM7binSize >> 2); ++i) |
|
| 2425 | 1109 |
{
|
| 2426 | 1110 |
_MMU_write32<ARMCPU_ARM7>(dst, T1ReadLong(MMU.CART_ROM, src)); |
| 2427 | 1111 |
dst += 4; |
| 2428 | 1112 |
src += 4; |
| 2429 | 1113 |
} |
| 2430 | 1114 |
|
| 1115 |
+ // set the cpus to an initial state with their respective programs entrypoints |
|
| 2431 | 1116 |
armcpu_init(&NDS_ARM7, header->ARM7exe); |
| 2432 | 1117 |
armcpu_init(&NDS_ARM9, header->ARM9exe); |
| 2433 | 1118 |
|
| 2434 |
- _MMU_write08<ARMCPU_ARM9>(REG_POSTFLG, 1); |
|
| 2435 |
- _MMU_write08<ARMCPU_ARM7>(REG_POSTFLG, 1); |
|
| 1119 |
+ // set REG_POSTFLG to the value indicating post-firmware status |
|
| 1120 |
+ MMU.ARM9_REG[0x300] = 1; |
|
| 1121 |
+ MMU.ARM7_REG[0x300] = 1; |
|
| 2436 | 1122 |
} |
| 2437 |
- //bitbox 4k demo is so stripped down it relies on default stack values |
|
| 2438 |
- //otherwise the arm7 will crash before making a sound |
|
| 2439 |
- //(these according to gbatek softreset bios docs) |
|
| 1123 |
+ |
|
| 1124 |
+ // only ARM9 have co-processor |
|
| 1125 |
+ reconstruct(&cp15); |
|
| 1126 |
+ cp15.reset(&NDS_ARM9); |
|
| 1127 |
+ |
|
| 1128 |
+ // bitbox 4k demo is so stripped down it relies on default stack values |
|
| 1129 |
+ // otherwise the arm7 will crash before making a sound |
|
| 1130 |
+ // (these according to gbatek softreset bios docs) |
|
| 2440 | 1131 |
NDS_ARM7.R13_svc = 0x0380FFDC; |
| 2441 | 1132 |
NDS_ARM7.R13_irq = 0x0380FFB0; |
| 2442 | 1133 |
NDS_ARM7.R13_usr = 0x0380FF00; |
| 2443 | 1134 |
NDS_ARM7.R[13] = NDS_ARM7.R13_usr; |
| 2444 |
- //and let's set these for the arm9 while we're at it, though we have no proof |
|
| 1135 |
+ // and let's set these for the arm9 while we're at it, though we have no proof |
|
| 2445 | 1136 |
NDS_ARM9.R13_svc = 0x00803FC0; |
| 2446 | 1137 |
NDS_ARM9.R13_irq = 0x00803FA0; |
| 2447 | 1138 |
NDS_ARM9.R13_usr = 0x00803EC0; |
| 2448 |
- NDS_ARM9.R13_abt = NDS_ARM9.R13_usr; //????? |
|
| 2449 |
- //I think it is wrong to take gbatek's "SYS" and put it in USR--maybe USR doesnt matter. |
|
| 2450 |
- //i think SYS is all the misc modes. please verify by setting nonsensical stack values for USR here |
|
| 1139 |
+ NDS_ARM9.R13_abt = NDS_ARM9.R13_usr; // ????? |
|
| 1140 |
+ // I think it is wrong to take gbatek's "SYS" and put it in USR--maybe USR doesnt matter. |
|
| 1141 |
+ // i think SYS is all the misc modes. please verify by setting nonsensical stack values for USR here |
|
| 2451 | 1142 |
NDS_ARM9.R[13] = NDS_ARM9.R13_usr; |
| 2452 |
- //n.b.: im not sure about all these, I dont know enough about arm9 svc/irq/etc modes |
|
| 2453 |
- //and how theyre named in desmume to match them up correctly. i just guessed. |
|
| 1143 |
+ // n.b.: im not sure about all these, I dont know enough about arm9 svc/irq/etc modes |
|
| 1144 |
+ // and how theyre named in desmume to match them up correctly. i just guessed. |
|
| 2454 | 1145 |
|
| 2455 |
- //nds.wifiCycle = 0; |
|
| 2456 |
- memset(nds.timerCycle, 0, sizeof(uint64_t) * 2 * 4); |
|
| 1146 |
+ memset(nds.timerCycle, 0, sizeof(uint64_t) * 8); |
|
| 2457 | 1147 |
nds.old = 0; |
| 2458 |
- //nds.touchX = nds.touchY = 0; |
|
| 2459 |
- //nds.isTouch = 0; |
|
| 2460 |
- //nds.debugConsole = CommonSettings.DebugConsole; |
|
| 2461 |
- //nds.ensataEmulation = CommonSettings.EnsataEmulation; |
|
| 2462 |
- //nds.ensataHandshake = ENSATA_HANDSHAKE_none; |
|
| 2463 |
- //nds.ensataIpcSyncCounter = 0; |
|
| 2464 |
- SetupMMU(/*nds.Is_DebugConsole()*/false,nds.Is_DSI()); |
|
| 1148 |
+ SetupMMU(false, nds.Is_DSI()); |
|
| 2465 | 1149 |
|
| 2466 | 1150 |
_MMU_write16<ARMCPU_ARM9>(REG_KEYINPUT, 0x3FF); |
| 2467 | 1151 |
_MMU_write16<ARMCPU_ARM7>(REG_KEYINPUT, 0x3FF); |
| 2468 | 1152 |
_MMU_write08<ARMCPU_ARM7>(REG_EXTKEYIN, 0x43); |
| 2469 | 1153 |
|
| 2470 |
- //LidClosed = false; |
|
| 2471 |
- //countLid = 0; |
|
| 2472 |
- |
|
| 2473 |
- //resetUserInput(); |
|
| 2474 |
- |
|
| 2475 |
- //Setup a copy of the firmware user settings in memory. |
|
| 2476 |
- //(this is what the DS firmware would do). |
|
| 1154 |
+ // Setup a copy of the firmware user settings in memory. |
|
| 1155 |
+ // (this is what the DS firmware would do). |
|
| 2477 | 1156 |
{
|
| 2478 | 1157 |
uint8_t temp_buffer[NDS_FW_USER_SETTINGS_MEM_BYTE_COUNT]; |
| 2479 |
- int fw_index; |
|
| 2480 | 1158 |
|
| 2481 |
- if ( copy_firmware_user_data( temp_buffer, &MMU.fw.data[0])) {
|
|
| 2482 |
- for ( fw_index = 0; fw_index < NDS_FW_USER_SETTINGS_MEM_BYTE_COUNT; fw_index++) |
|
| 1159 |
+ if (copy_firmware_user_data(temp_buffer, &MMU.fw.data[0])) |
|
| 1160 |
+ for (int fw_index = 0; fw_index < NDS_FW_USER_SETTINGS_MEM_BYTE_COUNT; ++fw_index) |
|
| 2483 | 1161 |
_MMU_write08<ARMCPU_ARM9>(0x027FFC80 + fw_index, temp_buffer[fw_index]); |
| 2484 |
- } |
|
| 2485 | 1162 |
} |
| 2486 | 1163 |
|
| 2487 | 1164 |
// Copy the whole header to Main RAM 0x27FFE00 on startup. (http://nocash.emubase.de/gbatek.htm#dscartridgeheader) |
| 2488 |
- //once upon a time this copied 0x90 more. this was thought to be wrong, and changed. |
|
| 2489 |
- if(nds.Is_DSI()) |
|
| 1165 |
+ // once upon a time this copied 0x90 more. this was thought to be wrong, and changed. |
|
| 1166 |
+ if (nds.Is_DSI()) |
|
| 2490 | 1167 |
{
|
| 2491 |
- //dsi needs this copied later in memory. there are probably a number of things that get copied to a later location in memory.. thats where the NDS consoles tend to stash stuff. |
|
| 2492 |
- for (int i = 0; i < ((0x170)/4); i++) |
|
| 2493 |
- _MMU_write32<ARMCPU_ARM9>(0x02FFFE00+i*4, LE_TO_LOCAL_32(((uint32_t*)MMU.CART_ROM)[i])); |
|
| 1168 |
+ // dsi needs this copied later in memory. there are probably a number of things that get copied to a later location in memory.. thats where the NDS consoles tend to stash stuff. |
|
| 1169 |
+ for (int i = 0; i < 92; ++i) |
|
| 1170 |
+ _MMU_write32<ARMCPU_ARM9>(0x02FFFE00 + i * 4, LE_TO_LOCAL_32(reinterpret_cast<uint32_t *>(MMU.CART_ROM)[i])); |
|
| 2494 | 1171 |
} |
| 2495 | 1172 |
else |
| 2496 | 1173 |
{
|
| 2497 |
- for (int i = 0; i < ((0x170)/4); i++) |
|
| 2498 |
- _MMU_write32<ARMCPU_ARM9>(0x027FFE00+i*4, LE_TO_LOCAL_32(((uint32_t*)MMU.CART_ROM)[i])); |
|
| 1174 |
+ for (int i = 0; i < 92; ++i) |
|
| 1175 |
+ _MMU_write32<ARMCPU_ARM9>(0x027FFE00 + i * 4, LE_TO_LOCAL_32(reinterpret_cast<uint32_t *>(MMU.CART_ROM)[i])); |
|
| 2499 | 1176 |
} |
| 2500 | 1177 |
|
| 2501 | 1178 |
// Write the header checksum to memory (the firmware needs it to see the cart) |
| 2502 | 1179 |
_MMU_write16<ARMCPU_ARM9>(0x027FF808, T1ReadWord(MMU.CART_ROM, 0x15E)); |
| 2503 | 1180 |
|
| 2504 |
- //-------------------------------- |
|
| 2505 |
- //setup the homebrew argv |
|
| 2506 |
- //this is useful for nitrofs apps which are emulating themselves via cflash |
|
| 2507 |
- //struct __argv {
|
|
| 2508 |
- // int argvMagic; //!< argv magic number, set to 0x5f617267 ('_arg') if valid
|
|
| 2509 |
- // char *commandLine; //!< base address of command line, set of null terminated strings |
|
| 2510 |
- // int length; //!< total length of command line |
|
| 2511 |
- // int argc; //!< internal use, number of arguments |
|
| 2512 |
- // char **argv; //!< internal use, argv pointer |
|
| 2513 |
- //}; |
|
| 2514 |
- std::string rompath = "fat:/" + path.RomName; |
|
| 2515 |
- const uint32_t kCommandline = 0x027E0000; |
|
| 2516 |
- //const uint32_t kCommandline = 0x027FFF84; |
|
| 2517 |
- |
|
| 2518 |
- // |
|
| 2519 |
- _MMU_write32<ARMCPU_ARM9>(0x02FFFE70, 0x5f617267); |
|
| 2520 |
- _MMU_write32<ARMCPU_ARM9>(0x02FFFE74, kCommandline); //(commandline starts here) |
|
| 2521 |
- _MMU_write32<ARMCPU_ARM9>(0x02FFFE78, rompath.size()+1); |
|
| 2522 |
- //0x027FFF7C (argc) |
|
| 2523 |
- //0x027FFF80 (argv) |
|
| 2524 |
- for(size_t i=0;i<rompath.size();i++) |
|
| 2525 |
- _MMU_write08<ARMCPU_ARM9>(kCommandline+i, rompath[i]); |
|
| 2526 |
- _MMU_write08<ARMCPU_ARM9>(kCommandline+rompath.size(), 0); |
|
| 2527 |
- //-------------------------------- |
|
| 2528 |
- |
|
| 2529 |
- if ((firmware->patched) && (CommonSettings.UseExtBIOS == true) && (CommonSettings.BootFromFirmware == true) && (fw_success == true)) |
|
| 1181 |
+ if (firmware->patched && CommonSettings.UseExtBIOS && CommonSettings.BootFromFirmware && fw_success) |
|
| 2530 | 1182 |
{
|
| 2531 | 1183 |
// HACK! for flashme |
| 2532 | 1184 |
_MMU_write32<ARMCPU_ARM9>(0x27FFE24, firmware->ARM9bootAddr); |
| ... | ... |
@@ -2534,473 +1186,14 @@ void NDS_Reset() |
| 2534 | 1186 |
} |
| 2535 | 1187 |
|
| 2536 | 1188 |
// make system think it's booted from card -- EXTREMELY IMPORTANT!!! Thanks to cReDiAr |
| 2537 |
- _MMU_write08<ARMCPU_ARM9>(0x02FFFC40,0x1); |
|
| 2538 |
- _MMU_write08<ARMCPU_ARM7>(0x02FFFC40,0x1); |
|
| 2539 |
- |
|
| 2540 |
- // Save touchscreen calibration info in a structure |
|
| 2541 |
- // so we can easily access it at any time |
|
| 2542 |
- //TSCal.adc.x1 = _MMU_read16<ARMCPU_ARM7>(0x027FFC80 + 0x58); |
|
| 2543 |
- //TSCal.adc.y1 = _MMU_read16<ARMCPU_ARM7>(0x027FFC80 + 0x5A); |
|
| 2544 |
- //TSCal.scr.x1 = _MMU_read08<ARMCPU_ARM7>(0x027FFC80 + 0x5C); |
|
| 2545 |
- //TSCal.scr.y1 = _MMU_read08<ARMCPU_ARM7>(0x027FFC80 + 0x5D); |
|
| 2546 |
- //TSCal.adc.x2 = _MMU_read16<ARMCPU_ARM7>(0x027FFC80 + 0x5E); |
|
| 2547 |
- //TSCal.adc.y2 = _MMU_read16<ARMCPU_ARM7>(0x027FFC80 + 0x60); |
|
| 2548 |
- //TSCal.scr.x2 = _MMU_read08<ARMCPU_ARM7>(0x027FFC80 + 0x62); |
|
| 2549 |
- //TSCal.scr.y2 = _MMU_read08<ARMCPU_ARM7>(0x027FFC80 + 0x63); |
|
| 2550 |
- |
|
| 2551 |
- //TSCal.adc.width = (TSCal.adc.x2 - TSCal.adc.x1); |
|
| 2552 |
- //TSCal.adc.height = (TSCal.adc.y2 - TSCal.adc.y1); |
|
| 2553 |
- //TSCal.scr.width = (TSCal.scr.x2 - TSCal.scr.x1); |
|
| 2554 |
- //TSCal.scr.height = (TSCal.scr.y2 - TSCal.scr.y1); |
|
| 2555 |
- |
|
| 2556 |
- //MainScreen.offset = 0; |
|
| 2557 |
- //SubScreen.offset = 192; |
|
| 2558 |
- |
|
| 2559 |
- //_MMU_write32[ARMCPU_ARM9](0x02007FFC, 0xE92D4030); |
|
| 2560 |
- |
|
| 2561 |
- delete header; |
|
| 2562 |
- |
|
| 2563 |
- //Screen_Reset(); |
|
| 2564 |
- //gfx3d_reset(); |
|
| 2565 |
- //gpu3D->NDS_3D_Reset(); |
|
| 2566 |
- //slot1Reset(); |
|
| 2567 |
- |
|
| 2568 |
- //WIFI_Reset(); |
|
| 2569 |
- |
|
| 2570 |
- //memcpy(FW_Mac, (MMU.fw.data + 0x36), 6); |
|
| 1189 |
+ _MMU_write08<ARMCPU_ARM9>(0x02FFFC40, 0x1); |
|
| 1190 |
+ _MMU_write08<ARMCPU_ARM7>(0x02FFFC40, 0x1); |
|
| 2571 | 1191 |
|
| 2572 | 1192 |
initSchedule(); |
| 2573 | 1193 |
|
| 2574 | 1194 |
SPU_ReInit(); |
| 2575 | 1195 |
} |
| 2576 | 1196 |
|
| 2577 |
-/*static std::string MakeInputDisplayString(uint16_t pad, const std::string* Buttons, int count) {
|
|
| 2578 |
- std::string s; |
|
| 2579 |
- for (int x = 0; x < count; x++) {
|
|
| 2580 |
- if (pad & (1 << x)) |
|
| 2581 |
- s.append(Buttons[x].size(), ' '); |
|
| 2582 |
- else |
|
| 2583 |
- s += Buttons[x]; |
|
| 2584 |
- } |
|
| 2585 |
- return s; |
|
| 2586 |
-}*/ |
|
| 2587 |
- |
|
| 2588 |
-/*static std::string MakeInputDisplayString(uint16_t pad, uint16_t padExt) {
|
|
| 2589 |
- const std::string Buttons[] = {"A", "B", "Sl", "St", "R", "L", "U", "D", "Rs", "Ls"};
|
|
| 2590 |
- const std::string Ext[] = {"X", "Y"};
|
|
| 2591 |
- |
|
| 2592 |
- std::string s = MakeInputDisplayString(pad, Ext, ARRAY_SIZE(Ext)); |
|
| 2593 |
- s += MakeInputDisplayString(padExt, Buttons, ARRAY_SIZE(Buttons)); |
|
| 2594 |
- |
|
| 2595 |
- return s; |
|
| 2596 |
-}*/ |
|
| 2597 |
- |
|
| 2598 |
- |
|
| 2599 |
-//buttonstruct<bool> Turbo; |
|
| 2600 |
-buttonstruct<int> TurboTime; |
|
| 2601 |
-//buttonstruct<bool> AutoHold; |
|
| 2602 |
- |
|
| 2603 |
-/*void ClearAutoHold() {
|
|
| 2604 |
- |
|
| 2605 |
- for (uint32_t i=0; i < ARRAY_SIZE(AutoHold.array); i++) {
|
|
| 2606 |
- AutoHold.array[i]=false; |
|
| 2607 |
- } |
|
| 2608 |
-}*/ |
|
| 2609 |
- |
|
| 2610 |
- |
|
| 2611 |
-/*inline uint16_t NDS_getADCTouchPosX(uint16_t scrX) |
|
| 2612 |
-{
|
|
| 2613 |
- // this is a little iffy, |
|
| 2614 |
- // we're basically adjusting the ADC results to |
|
| 2615 |
- // compensate for how they will be interpreted. |
|
| 2616 |
- // the actual system doesn't do this transformation. |
|
| 2617 |
- int rv = (scrX - TSCal.scr.x1 + 1) * TSCal.adc.width / TSCal.scr.width + TSCal.adc.x1; |
|
| 2618 |
- rv = min(0xFFF, max(0, rv)); |
|
| 2619 |
- return (uint16_t)rv; |
|
| 2620 |
-}*/ |
|
| 2621 |
-/*inline uint16_t NDS_getADCTouchPosY(uint16_t scrY) |
|
| 2622 |
-{
|
|
| 2623 |
- int rv = (scrY - TSCal.scr.y1 + 1) * TSCal.adc.height / TSCal.scr.height + TSCal.adc.y1; |
|
| 2624 |
- rv = min(0xFFF, max(0, rv)); |
|
| 2625 |
- return (uint16_t)rv; |
|
| 2626 |
-}*/ |
|
| 2627 |
- |
|
| 2628 |
-//static UserInput rawUserInput = {}; // requested input, generally what the user is physically pressing
|
|
| 2629 |
-static UserInput intermediateUserInput; // intermediate buffer for modifications (seperated from finalUserInput for safety reasons) |
|
| 2630 |
-static UserInput finalUserInput; // what gets sent to the game and possibly recorded |
|
| 2631 |
-bool validToProcessInput = false; |
|
| 2632 |
- |
|
| 2633 |
-/*const UserInput& NDS_getRawUserInput() |
|
| 2634 |
-{
|
|
| 2635 |
- return rawUserInput; |
|
| 2636 |
-}*/ |
|
| 2637 |
-/*UserInput& NDS_getProcessingUserInput() |
|
| 2638 |
-{
|
|
| 2639 |
- assert(validToProcessInput); |
|
| 2640 |
- return intermediateUserInput; |
|
| 2641 |
-}*/ |
|
| 2642 |
-/*bool NDS_isProcessingUserInput() |
|
| 2643 |
-{
|
|
| 2644 |
- return validToProcessInput; |
|
| 2645 |
-}*/ |
|
| 2646 |
-/*const UserInput& NDS_getFinalUserInput() |
|
| 2647 |
-{
|
|
| 2648 |
- return finalUserInput; |
|
| 2649 |
-}*/ |
|
| 2650 |
- |
|
| 2651 |
- |
|
| 2652 |
-/*static void saveUserInput(EMUFILE* os, UserInput& input) |
|
| 2653 |
-{
|
|
| 2654 |
- os->fwrite((const char*)input.buttons.array, 14); |
|
| 2655 |
- writebool(input.touch.isTouch, os); |
|
| 2656 |
- write16le(input.touch.touchX, os); |
|
| 2657 |
- write16le(input.touch.touchY, os); |
|
| 2658 |
- write32le(input.mic.micButtonPressed, os); |
|
| 2659 |
-}*/ |
|
| 2660 |
-static bool loadUserInput(EMUFILE* is, UserInput& input, int) |
|
| 2661 |
-{
|
|
| 2662 |
- is->fread((char*)input.buttons.array, 14); |
|
| 2663 |
- readbool(&input.touch.isTouch, is); |
|
| 2664 |
- read16le(&input.touch.touchX, is); |
|
| 2665 |
- read16le(&input.touch.touchY, is); |
|
| 2666 |
- read32le(&input.mic.micButtonPressed, is); |
|
| 2667 |
- return true; |
|
| 2668 |
-} |
|
| 2669 |
-/*static void resetUserInput(UserInput& input) |
|
| 2670 |
-{
|
|
| 2671 |
- memset(&input, 0, sizeof(UserInput)); |
|
| 2672 |
-}*/ |
|
| 2673 |
-// (userinput is kind of a misnomer, e.g. finalUserInput has to mirror nds.pad, nds.touchX, etc.) |
|
| 2674 |
-/*static void saveUserInput(EMUFILE* os) |
|
| 2675 |
-{
|
|
| 2676 |
- saveUserInput(os, finalUserInput); |
|
| 2677 |
- saveUserInput(os, intermediateUserInput); // saved in case a savestate is made during input processing (which Lua could do if nothing else) |
|
| 2678 |
- writebool(validToProcessInput, os); |
|
| 2679 |
- for(int i = 0; i < 14; i++) |
|
| 2680 |
- write32le(TurboTime.array[i], os); // saved to make autofire more tolerable to use with re-recording |
|
| 2681 |
-}*/ |
|
| 2682 |
-static bool loadUserInput(EMUFILE* is, int version) |
|
| 2683 |
-{
|
|
| 2684 |
- bool rv = true; |
|
| 2685 |
- rv &= loadUserInput(is, finalUserInput, version); |
|
| 2686 |
- rv &= loadUserInput(is, intermediateUserInput, version); |
|
| 2687 |
- readbool(&validToProcessInput, is); |
|
| 2688 |
- for(int i = 0; i < 14; i++) |
|
| 2689 |
- read32le((uint32_t*)&TurboTime.array[i], is); |
|
| 2690 |
- return rv; |
|
| 2691 |
-} |
|
| 2692 |
-/*static void resetUserInput() |
|
| 2693 |
-{
|
|
| 2694 |
- resetUserInput(finalUserInput); |
|
| 2695 |
- resetUserInput(intermediateUserInput); |
|
| 2696 |
-}*/ |
|
| 2697 |
- |
|
| 2698 |
-/*static inline void gotInputRequest() |
|
| 2699 |
-{
|
|
| 2700 |
- // nobody should set the raw input while we're processing the input. |
|
| 2701 |
- // it might not screw anything up but it would be completely useless. |
|
| 2702 |
- assert(!validToProcessInput); |
|
| 2703 |
-}*/ |
|
| 2704 |
- |
|
| 2705 |
-/*void NDS_setPad(bool R,bool L,bool D,bool U,bool T,bool S,bool B,bool A,bool Y,bool X,bool W,bool E,bool G, bool F) |
|
| 2706 |
-{
|
|
| 2707 |
- gotInputRequest(); |
|
| 2708 |
- UserButtons& rawButtons = rawUserInput.buttons; |
|
| 2709 |
- rawButtons.R = R; |
|
| 2710 |
- rawButtons.L = L; |
|
| 2711 |
- rawButtons.D = D; |
|
| 2712 |
- rawButtons.U = U; |
|
| 2713 |
- rawButtons.T = T; |
|
| 2714 |
- rawButtons.S = S; |
|
| 2715 |
- rawButtons.B = B; |
|
| 2716 |
- rawButtons.A = A; |
|
| 2717 |
- rawButtons.Y = Y; |
|
| 2718 |
- rawButtons.X = X; |
|
| 2719 |
- rawButtons.W = W; |
|
| 2720 |
- rawButtons.E = E; |
|
| 2721 |
- rawButtons.G = G; |
|
| 2722 |
- rawButtons.F = F; |
|
| 2723 |
-}*/ |
|
| 2724 |
-/*void NDS_setTouchPos(uint16_t x, uint16_t y) |
|
| 2725 |
-{
|
|
| 2726 |
- gotInputRequest(); |
|
| 2727 |
- rawUserInput.touch.touchX = NDS_getADCTouchPosX(x); |
|
| 2728 |
- rawUserInput.touch.touchY = NDS_getADCTouchPosY(y); |
|
| 2729 |
- rawUserInput.touch.isTouch = true;*/ |
|
| 2730 |
- |
|
| 2731 |
- /*if(movieMode != MOVIEMODE_INACTIVE && movieMode != MOVIEMODE_FINISHED) |
|
| 2732 |
- {
|
|
| 2733 |
- // just in case, since the movie only stores 8 bits per touch coord |
|
| 2734 |
- rawUserInput.touch.touchX &= 0x0FF0; |
|
| 2735 |
- rawUserInput.touch.touchY &= 0x0FF0; |
|
| 2736 |
- }*/ |
|
| 2737 |
-/* |
|
| 2738 |
-#ifndef WIN32 |
|
| 2739 |
- // FIXME: this code should be deleted from here, |
|
| 2740 |
- // other platforms should call NDS_beginProcessingInput,NDS_endProcessingInput once per frame instead |
|
| 2741 |
- // (see the function called "StepRunLoop_Core" in src/windows/main.cpp), |
|
| 2742 |
- // but I'm leaving this here for now since I can't test those other platforms myself. |
|
| 2743 |
- nds.touchX = rawUserInput.touch.touchX; |
|
| 2744 |
- nds.touchY = rawUserInput.touch.touchY; |
|
| 2745 |
- nds.isTouch = 1; |
|
| 2746 |
- MMU.ARM7_REG[0x136] &= 0xBF; |
|
| 2747 |
-#endif |
|
| 2748 |
-}*/ |
|
| 2749 |
-/*void NDS_releaseTouch() |
|
| 2750 |
-{
|
|
| 2751 |
- gotInputRequest(); |
|
| 2752 |
- rawUserInput.touch.touchX = 0; |
|
| 2753 |
- rawUserInput.touch.touchY = 0; |
|
| 2754 |
- rawUserInput.touch.isTouch = false; |
|
| 2755 |
- |
|
| 2756 |
-#ifndef WIN32 |
|
| 2757 |
- // FIXME: this code should be deleted from here, |
|
| 2758 |
- // other platforms should call NDS_beginProcessingInput,NDS_endProcessingInput once per frame instead |
|
| 2759 |
- // (see the function called "StepRunLoop_Core" in src/windows/main.cpp), |
|
| 2760 |
- // but I'm leaving this here for now since I can't test those other platforms myself. |
|
| 2761 |
- nds.touchX = 0; |
|
| 2762 |
- nds.touchY = 0; |
|
| 2763 |
- nds.isTouch = 0; |
|
| 2764 |
- MMU.ARM7_REG[0x136] |= 0x40; |
|
| 2765 |
-#endif |
|
| 2766 |
-}*/ |
|
| 2767 |
-/*void NDS_setMic(bool pressed) |
|
| 2768 |
-{
|
|
| 2769 |
- gotInputRequest(); |
|
| 2770 |
- rawUserInput.mic.micButtonPressed = (pressed ? true : false); |
|
| 2771 |
-}*/ |
|
| 2772 |
- |
|
| 2773 |
- |
|
| 2774 |
-//static void NDS_applyFinalInput(); |
|
| 2775 |
- |
|
| 2776 |
- |
|
| 2777 |
-/*void NDS_beginProcessingInput() |
|
| 2778 |
-{
|
|
| 2779 |
- // start off from the raw input |
|
| 2780 |
- intermediateUserInput = rawUserInput; |
|
| 2781 |
- |
|
| 2782 |
- // processing is valid now |
|
| 2783 |
- validToProcessInput = true; |
|
| 2784 |
-}*/ |
|
| 2785 |
- |
|
| 2786 |
-/*void NDS_endProcessingInput() |
|
| 2787 |
-{
|
|
| 2788 |
- // transfer the processed input |
|
| 2789 |
- finalUserInput = intermediateUserInput; |
|
| 2790 |
- |
|
| 2791 |
- // processing is invalid now |
|
| 2792 |
- validToProcessInput = false; |
|
| 2793 |
- |
|
| 2794 |
- // use the final input for a few things right away |
|
| 2795 |
- NDS_applyFinalInput(); |
|
| 2796 |
-}*/ |
|
| 2797 |
- |
|
| 2798 |
- |
|
| 2799 |
- |
|
| 2800 |
- |
|
| 2801 |
- |
|
| 2802 |
- |
|
| 2803 |
- |
|
| 2804 |
- |
|
| 2805 |
-/*static void NDS_applyFinalInput() |
|
| 2806 |
-{
|
|
| 2807 |
- const UserInput& input = NDS_getFinalUserInput(); |
|
| 2808 |
- |
|
| 2809 |
- uint16_t pad = (0 | |
|
| 2810 |
- ((input.buttons.A ? 0 : 0x80) >> 7) | |
|
| 2811 |
- ((input.buttons.B ? 0 : 0x80) >> 6) | |
|
| 2812 |
- ((input.buttons.T ? 0 : 0x80) >> 5) | |
|
| 2813 |
- ((input.buttons.S ? 0 : 0x80) >> 4) | |
|
| 2814 |
- ((input.buttons.R ? 0 : 0x80) >> 3) | |
|
| 2815 |
- ((input.buttons.L ? 0 : 0x80) >> 2) | |
|
| 2816 |
- ((input.buttons.U ? 0 : 0x80) >> 1) | |
|
| 2817 |
- ((input.buttons.D ? 0 : 0x80) ) | |
|
| 2818 |
- ((input.buttons.E ? 0 : 0x80) << 1) | |
|
| 2819 |
- ((input.buttons.W ? 0 : 0x80) << 2)) ; |
|
| 2820 |
- |
|
| 2821 |
- ((uint16_t *)MMU.ARM9_REG)[0x130>>1] = (uint16_t)pad; |
|
| 2822 |
- ((uint16_t *)MMU.ARM7_REG)[0x130>>1] = (uint16_t)pad; |
|
| 2823 |
- |
|
| 2824 |
- uint16_t k_cnt = ((uint16_t *)MMU.ARM9_REG)[0x132>>1]; |
|
| 2825 |
- if ( k_cnt & (1<<14)) |
|
| 2826 |
- {
|
|
| 2827 |
- //INFO("ARM9: KeyPad IRQ (pad 0x%04X, cnt 0x%04X (condition %s))\n", pad, k_cnt, k_cnt&(1<<15)?"AND":"OR");
|
|
| 2828 |
- uint16_t k_cnt_selected = (k_cnt & 0x3F); |
|
| 2829 |
- if (k_cnt&(1<<15)) // AND |
|
| 2830 |
- {
|
|
| 2831 |
- if ((~pad & k_cnt_selected) == k_cnt_selected) NDS_makeIrq(ARMCPU_ARM9,IRQ_BIT_KEYPAD); |
|
| 2832 |
- } |
|
| 2833 |
- else // OR |
|
| 2834 |
- {
|
|
| 2835 |
- if (~pad & k_cnt_selected) NDS_makeIrq(ARMCPU_ARM9,IRQ_BIT_KEYPAD); |
|
| 2836 |
- } |
|
| 2837 |
- } |
|
| 2838 |
- |
|
| 2839 |
- k_cnt = ((uint16_t *)MMU.ARM7_REG)[0x132>>1]; |
|
| 2840 |
- if ( k_cnt & (1<<14)) |
|
| 2841 |
- {
|
|
| 2842 |
- //INFO("ARM7: KeyPad IRQ (pad 0x%04X, cnt 0x%04X (condition %s))\n", pad, k_cnt, k_cnt&(1<<15)?"AND":"OR");
|
|
| 2843 |
- uint16_t k_cnt_selected = (k_cnt & 0x3F); |
|
| 2844 |
- if (k_cnt&(1<<15)) // AND |
|
| 2845 |
- {
|
|
| 2846 |
- if ((~pad & k_cnt_selected) == k_cnt_selected) NDS_makeIrq(ARMCPU_ARM7,IRQ_BIT_KEYPAD); |
|
| 2847 |
- } |
|
| 2848 |
- else // OR |
|
| 2849 |
- {
|
|
| 2850 |
- if (~pad & k_cnt_selected) NDS_makeIrq(ARMCPU_ARM7,IRQ_BIT_KEYPAD); |
|
| 2851 |
- } |
|
| 2852 |
- } |
|
| 2853 |
- |
|
| 2854 |
- |
|
| 2855 |
- if(input.touch.isTouch) |
|
| 2856 |
- {
|
|
| 2857 |
- nds.touchX = input.touch.touchX; |
|
| 2858 |
- nds.touchY = input.touch.touchY; |
|
| 2859 |
- nds.isTouch = 1; |
|
| 2860 |
- |
|
| 2861 |
- MMU.ARM7_REG[0x136] &= 0xBF; |
|
| 2862 |
- } |
|
| 2863 |
- else |
|
| 2864 |
- {
|
|
| 2865 |
- |
|
| 2866 |
- nds.touchX = 0; |
|
| 2867 |
- nds.touchY = 0; |
|
| 2868 |
- nds.isTouch = 0; |
|
| 2869 |
- |
|
| 2870 |
- MMU.ARM7_REG[0x136] |= 0x40; |
|
| 2871 |
- } |
|
| 2872 |
- |
|
| 2873 |
- |
|
| 2874 |
- if (input.buttons.F && !countLid) |
|
| 2875 |
- {
|
|
| 2876 |
- LidClosed = (!LidClosed) & 0x01; |
|
| 2877 |
- if (!LidClosed) |
|
| 2878 |
- {
|
|
| 2879 |
- // SPU_Pause(false); |
|
| 2880 |
- NDS_makeIrq(ARMCPU_ARM7,IRQ_BIT_ARM7_FOLD); |
|
| 2881 |
- |
|
| 2882 |
- } |
|
| 2883 |
- //else |
|
| 2884 |
- //SPU_Pause(true); |
|
| 2885 |
- |
|
| 2886 |
- countLid = 30; |
|
| 2887 |
- } |
|
| 2888 |
- else |
|
| 2889 |
- {
|
|
| 2890 |
- if (countLid > 0) |
|
| 2891 |
- countLid--; |
|
| 2892 |
- } |
|
| 2893 |
- |
|
| 2894 |
- uint16_t padExt = (((uint16_t *)MMU.ARM7_REG)[0x136>>1] & 0x0070) | |
|
| 2895 |
- ((input.buttons.X ? 0 : 0x80) >> 7) | |
|
| 2896 |
- ((input.buttons.Y ? 0 : 0x80) >> 6) | |
|
| 2897 |
- ((input.buttons.G ? 0 : 0x80) >> 4) | |
|
| 2898 |
- ((LidClosed) << 7) | |
|
| 2899 |
- 0x0034; |
|
| 2900 |
- |
|
| 2901 |
- ((uint16_t *)MMU.ARM7_REG)[0x136>>1] = (uint16_t)padExt; |
|
| 2902 |
- |
|
| 2903 |
- InputDisplayString=MakeInputDisplayString(padExt, pad); |
|
| 2904 |
- |
|
| 2905 |
- //put into the format we want for the movie system |
|
| 2906 |
- //fRLDUTSBAYXWEg |
|
| 2907 |
- //we don't really need nds.pad anymore, but removing it would be a pain |
|
| 2908 |
- |
|
| 2909 |
- nds.pad = |
|
| 2910 |
- ((input.buttons.R ? 1 : 0) << 12)| |
|
| 2911 |
- ((input.buttons.L ? 1 : 0) << 11)| |
|
| 2912 |
- ((input.buttons.D ? 1 : 0) << 10)| |
|
| 2913 |
- ((input.buttons.U ? 1 : 0) << 9)| |
|
| 2914 |
- ((input.buttons.T ? 1 : 0) << 8)| |
|
| 2915 |
- ((input.buttons.S ? 1 : 0) << 7)| |
|
| 2916 |
- ((input.buttons.B ? 1 : 0) << 6)| |
|
| 2917 |
- ((input.buttons.A ? 1 : 0) << 5)| |
|
| 2918 |
- ((input.buttons.Y ? 1 : 0) << 4)| |
|
| 2919 |
- ((input.buttons.X ? 1 : 0) << 3)| |
|
| 2920 |
- ((input.buttons.W ? 1 : 0) << 2)| |
|
| 2921 |
- ((input.buttons.E ? 1 : 0) << 1); |
|
| 2922 |
- |
|
| 2923 |
- // TODO: low power IRQ |
|
| 2924 |
-}*/ |
|
| 2925 |
- |
|
| 2926 |
- |
|
| 2927 |
-/*void NDS_suspendProcessingInput(bool suspend) |
|
| 2928 |
-{
|
|
| 2929 |
- static int suspendCount = 0; |
|
| 2930 |
- if(suspend) |
|
| 2931 |
- {
|
|
| 2932 |
- // enter non-processing block |
|
| 2933 |
- assert(validToProcessInput); |
|
| 2934 |
- validToProcessInput = false; |
|
| 2935 |
- suspendCount++; |
|
| 2936 |
- } |
|
| 2937 |
- else if(suspendCount) |
|
| 2938 |
- {
|
|
| 2939 |
- // exit non-processing block |
|
| 2940 |
- validToProcessInput = true; |
|
| 2941 |
- suspendCount--; |
|
| 2942 |
- } |
|
| 2943 |
- else |
|
| 2944 |
- {
|
|
| 2945 |
- // unwound past first time -> not processing |
|
| 2946 |
- validToProcessInput = false; |
|
| 2947 |
- } |
|
| 2948 |
-}*/ |
|
| 2949 |
- |
|
| 2950 |
- |
|
| 2951 |
-/*void emu_halt() {
|
|
| 2952 |
- //printf("halting emu: ARM9 PC=%08X/%08X, ARM7 PC=%08X/%08X\n", NDS_ARM9.R[15], NDS_ARM9.instruct_adr, NDS_ARM7.R[15], NDS_ARM7.instruct_adr);
|
|
| 2953 |
- execute = false; |
|
| 2954 |
-#ifdef LOG_ARM9 |
|
| 2955 |
- if (fp_dis9) |
|
| 2956 |
- {
|
|
| 2957 |
- char buf[256] = { 0 };
|
|
| 2958 |
- sprintf(buf, "halting emu: ARM9 PC=%08X/%08X\n", NDS_ARM9.R[15], NDS_ARM9.instruct_adr); |
|
| 2959 |
- fwrite(buf, 1, strlen(buf), fp_dis9); |
|
| 2960 |
- INFO("ARM9 halted\n");
|
|
| 2961 |
- } |
|
| 2962 |
-#endif |
|
| 2963 |
- |
|
| 2964 |
-#ifdef LOG_ARM7 |
|
| 2965 |
- if (fp_dis7) |
|
| 2966 |
- {
|
|
| 2967 |
- char buf[256] = { 0 };
|
|
| 2968 |
- sprintf(buf, "halting emu: ARM7 PC=%08X/%08X\n", NDS_ARM7.R[15], NDS_ARM7.instruct_adr); |
|
| 2969 |
- fwrite(buf, 1, strlen(buf), fp_dis7); |
|
| 2970 |
- INFO("ARM7 halted\n");
|
|
| 2971 |
- } |
|
| 2972 |
-#endif |
|
| 2973 |
-}*/ |
|
| 2974 |
- |
|
| 2975 |
-//returns true if exmemcnt specifies satisfactory parameters for the device, which calls this function |
|
| 2976 |
-/*bool ValidateSlot2Access(uint32_t procnum, uint32_t demandSRAMSpeed, uint32_t demand1stROMSpeed, uint32_t demand2ndROMSpeed, int clockbits) |
|
| 2977 |
-{
|
|
| 2978 |
- static const uint32_t _sramSpeeds[] = {10,8,6,18};
|
|
| 2979 |
- static const uint32_t _rom1Speeds[] = {10,8,6,18};
|
|
| 2980 |
- static const uint32_t _rom2Speeds[] = {6,4};
|
|
| 2981 |
- uint16_t exmemcnt = T1ReadWord(MMU.MMU_MEM[procnum][0x40], 0x204); |
|
| 2982 |
- uint16_t exmemcnt9 = T1ReadWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x204); |
|
| 2983 |
- uint32_t arm7access = (exmemcnt9 & EXMEMCNT_MASK_SLOT2_ARM7); |
|
| 2984 |
- uint32_t sramSpeed = _sramSpeeds[(exmemcnt & EXMEMCNT_MASK_SLOT2_SRAM_TIME)]; |
|
| 2985 |
- uint32_t romSpeed1 = _rom1Speeds[(exmemcnt & EXMEMCNT_MASK_SLOT2_ROM_1ST_TIME)>>2]; |
|
| 2986 |
- uint32_t romSpeed2 = _rom2Speeds[(exmemcnt & EXMEMCNT_MASK_SLOT2_ROM_2ND_TIME)>>4]; |
|
| 2987 |
- uint32_t curclockbits = (exmemcnt & EXMEMCNT_MASK_SLOT2_CLOCKRATE)>>5; |
|
| 2988 |
- |
|
| 2989 |
- if(procnum==ARMCPU_ARM9 && arm7access) return false; |
|
| 2990 |
- if(procnum==ARMCPU_ARM7 && !arm7access) return false; |
|
| 2991 |
- |
|
| 2992 |
- //what we're interested in here is whether the rom/ram are too low -> too fast. then accesses won't have enough time to work. |
|
| 2993 |
- //i'm not sure if this gives us enough flexibility, but it is good enough for now. |
|
| 2994 |
- //should make the arguments to this function bitmasks later if we need better. |
|
| 2995 |
- if(sramSpeed < demandSRAMSpeed) return false; |
|
| 2996 |
- if(romSpeed1 < demand1stROMSpeed) return false; |
|
| 2997 |
- if(romSpeed2 < demand2ndROMSpeed) return false; |
|
| 2998 |
- |
|
| 2999 |
- if(clockbits != -1 && clockbits != (int)curclockbits) return false; |
|
| 3000 |
- |
|
| 3001 |
- return true; |
|
| 3002 |
-}*/ |
|
| 3003 |
- |
|
| 3004 |
-//these templates needed to be instantiated manually |
|
| 1197 |
+// these templates needed to be instantiated manually |
|
| 3005 | 1198 |
template void NDS_exec<false>(int32_t nb); |
| 3006 | 1199 |
template void NDS_exec<true>(int32_t nb); |
| 1 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,3006 @@ |
| 1 |
+/* |
|
| 2 |
+ Copyright (C) 2006 yopyop |
|
| 3 |
+ Copyright (C) 2008-2012 DeSmuME team |
|
| 4 |
+ |
|
| 5 |
+ This file is free software: you can redistribute it and/or modify |
|
| 6 |
+ it under the terms of the GNU General Public License as published by |
|
| 7 |
+ the Free Software Foundation, either version 2 of the License, or |
|
| 8 |
+ (at your option) any later version. |
|
| 9 |
+ |
|
| 10 |
+ This file is distributed in the hope that it will be useful, |
|
| 11 |
+ but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 12 |
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 13 |
+ GNU General Public License for more details. |
|
| 14 |
+ |
|
| 15 |
+ You should have received a copy of the GNU General Public License |
|
| 16 |
+ along with the this software. If not, see <http://www.gnu.org/licenses/>. |
|
| 17 |
+*/ |
|
| 18 |
+ |
|
| 19 |
+#include <algorithm> |
|
| 20 |
+#include <cstring> |
|
| 21 |
+#include <cstdlib> |
|
| 22 |
+#include <cmath> |
|
| 23 |
+#include <zlib.h> |
|
| 24 |
+ |
|
| 25 |
+#include "common.h" |
|
| 26 |
+#include "NDSSystem.h" |
|
| 27 |
+//#include "render3D.h" |
|
| 28 |
+#include "MMU.h" |
|
| 29 |
+//#include "ROMReader.h" |
|
| 30 |
+//#include "gfx3d.h" |
|
| 31 |
+//#include "utils/decrypt/decrypt.h" |
|
| 32 |
+//#include "utils/decrypt/crc.h" |
|
| 33 |
+#include "bios.h" |
|
| 34 |
+//#include "debug.h" |
|
| 35 |
+//#include "cheatSystem.h" |
|
| 36 |
+//#include "movie.h" |
|
| 37 |
+//#include "Disassembler.h" |
|
| 38 |
+#include "readwrite.h" |
|
| 39 |
+//#include "debug.h" |
|
| 40 |
+#include "firmware.h" |
|
| 41 |
+#include "version.h" |
|
| 42 |
+#include "slot1.h" |
|
| 43 |
+ |
|
| 44 |
+#include "path.h" |
|
| 45 |
+ |
|
| 46 |
+//#define LOG_ARM9 |
|
| 47 |
+//#define LOG_ARM7 |
|
| 48 |
+//bool dolog = false; |
|
| 49 |
+//#define LOG_TO_FILE |
|
| 50 |
+//#define LOG_TO_FILE_REGS |
|
| 51 |
+ |
|
| 52 |
+//=============================================================== |
|
| 53 |
+//FILE *fp_dis7 = NULL; |
|
| 54 |
+//FILE *fp_dis9 = NULL; |
|
| 55 |
+ |
|
| 56 |
+PathInfo path; |
|
| 57 |
+ |
|
| 58 |
+TCommonSettings CommonSettings; |
|
| 59 |
+//static BaseDriver _stub_driver; |
|
| 60 |
+//BaseDriver* driver = &_stub_driver; |
|
| 61 |
+//std::string InputDisplayString; |
|
| 62 |
+ |
|
| 63 |
+//static bool LidClosed = false; |
|
| 64 |
+//static uint8_t countLid = 0; |
|
| 65 |
+ |
|
| 66 |
+GameInfo gameInfo; |
|
| 67 |
+NDSSystem nds; |
|
| 68 |
+CFIRMWARE *firmware = NULL; |
|
| 69 |
+//ADVANsCEne advsc; |
|
| 70 |
+ |
|
| 71 |
+bool singleStep; |
|
| 72 |
+//bool nds_debug_continuing[2]; |
|
| 73 |
+//int lagframecounter; |
|
| 74 |
+//int LagFrameFlag; |
|
| 75 |
+//int lastLag; |
|
| 76 |
+//int TotalLagFrames; |
|
| 77 |
+ |
|
| 78 |
+//TSCalInfo TSCal; |
|
| 79 |
+ |
|
| 80 |
+namespace DLDI |
|
| 81 |
+{
|
|
| 82 |
+ bool tryPatch(void* data, size_t size); |
|
| 83 |
+} |
|
| 84 |
+ |
|
| 85 |
+/*void Desmume_InitOnce() |
|
| 86 |
+{
|
|
| 87 |
+ static bool initOnce = false; |
|
| 88 |
+ if(initOnce) return; |
|
| 89 |
+ initOnce = true;*/ |
|
| 90 |
+ |
|
| 91 |
+/*#ifdef HAVE_LIBAGG |
|
| 92 |
+ extern void Agg_init(); //no need to include just for this |
|
| 93 |
+ Agg_init(); |
|
| 94 |
+#endif*/ |
|
| 95 |
+//} |
|
| 96 |
+ |
|
| 97 |
+#ifdef GDB_STUB |
|
| 98 |
+int NDS_Init( struct armcpu_memory_iface *arm9_mem_if, |
|
| 99 |
+struct armcpu_ctrl_iface **arm9_ctrl_iface, |
|
| 100 |
+struct armcpu_memory_iface *arm7_mem_if, |
|
| 101 |
+struct armcpu_ctrl_iface **arm7_ctrl_iface) {
|
|
| 102 |
+#else |
|
| 103 |
+int NDS_Init() {
|
|
| 104 |
+#endif |
|
| 105 |
+ //nds.idleFrameCounter = 0; |
|
| 106 |
+ //memset(nds.runCycleCollector,0,sizeof(nds.runCycleCollector)); |
|
| 107 |
+ MMU_Init(); |
|
| 108 |
+ nds.VCount = 0; |
|
| 109 |
+ |
|
| 110 |
+ //got to print this somewhere.. |
|
| 111 |
+ printf("%s\n", EMU_DESMUME_NAME_AND_VERSION());
|
|
| 112 |
+ |
|
| 113 |
+ /*if (Screen_Init(GFXCORE_DUMMY) != 0) |
|
| 114 |
+ return -1;*/ |
|
| 115 |
+ |
|
| 116 |
+ //gfx3d_init(); |
|
| 117 |
+ |
|
| 118 |
+#ifdef GDB_STUB |
|
| 119 |
+ armcpu_new(&NDS_ARM7,1, arm7_mem_if, arm7_ctrl_iface); |
|
| 120 |
+ armcpu_new(&NDS_ARM9,0, arm9_mem_if, arm9_ctrl_iface); |
|
| 121 |
+#else |
|
| 122 |
+ armcpu_new(&NDS_ARM7,1); |
|
| 123 |
+ armcpu_new(&NDS_ARM9,0); |
|
| 124 |
+#endif |
|
| 125 |
+ |
|
| 126 |
+ if (SPU_Init(SNDCORE_DUMMY, 740) != 0) |
|
| 127 |
+ return -1; |
|
| 128 |
+ |
|
| 129 |
+ //WIFI_Init() ; |
|
| 130 |
+ |
|
| 131 |
+ // Init calibration info |
|
| 132 |
+ //TSCal.adc.x1 = 0x0200; |
|
| 133 |
+ //TSCal.adc.y1 = 0x0200; |
|
| 134 |
+ //TSCal.scr.x1 = 0x20 + 1; // calibration screen coords are 1-based, |
|
| 135 |
+ //TSCal.scr.y1 = 0x20 + 1; // either that or NDS_getADCTouchPosX/Y are wrong. |
|
| 136 |
+ //TSCal.adc.x2 = 0x0E00; |
|
| 137 |
+ //TSCal.adc.y2 = 0x0800; |
|
| 138 |
+ //TSCal.scr.x2 = 0xE0 + 1; |
|
| 139 |
+ //TSCal.scr.y2 = 0x80 + 1; |
|
| 140 |
+ //TSCal.adc.width = (TSCal.adc.x2 - TSCal.adc.x1); |
|
| 141 |
+ //TSCal.adc.height = (TSCal.adc.y2 - TSCal.adc.y1); |
|
| 142 |
+ //TSCal.scr.width = (TSCal.scr.x2 - TSCal.scr.x1); |
|
| 143 |
+ //TSCal.scr.height = (TSCal.scr.y2 - TSCal.scr.y1); |
|
| 144 |
+ |
|
| 145 |
+ //cheats = new CHEATS(); |
|
| 146 |
+ //cheatSearch = new CHEATSEARCH(); |
|
| 147 |
+ |
|
| 148 |
+ return 0; |
|
| 149 |
+} |
|
| 150 |
+ |
|
| 151 |
+void NDS_DeInit() {
|
|
| 152 |
+ if(MMU.CART_ROM != MMU.UNUSED_RAM) |
|
| 153 |
+ NDS_FreeROM(); |
|
| 154 |
+ |
|
| 155 |
+ SPU_DeInit(); |
|
| 156 |
+ //Screen_DeInit(); |
|
| 157 |
+ MMU_DeInit(); |
|
| 158 |
+ //gpu3D->NDS_3D_Close(); |
|
| 159 |
+ |
|
| 160 |
+ //WIFI_DeInit(); |
|
| 161 |
+ /*if (cheats) |
|
| 162 |
+ delete cheats;*/ |
|
| 163 |
+ /*if (cheatSearch) |
|
| 164 |
+ delete cheatSearch;*/ |
|
| 165 |
+ |
|
| 166 |
+#ifdef LOG_ARM7 |
|
| 167 |
+ if (fp_dis7 != NULL) |
|
| 168 |
+ {
|
|
| 169 |
+ fclose(fp_dis7); |
|
| 170 |
+ fp_dis7 = NULL; |
|
| 171 |
+ } |
|
| 172 |
+#endif |
|
| 173 |
+ |
|
| 174 |
+#ifdef LOG_ARM9 |
|
| 175 |
+ if (fp_dis9 != NULL) |
|
| 176 |
+ {
|
|
| 177 |
+ fclose(fp_dis9); |
|
| 178 |
+ fp_dis9 = NULL; |
|
| 179 |
+ } |
|
| 180 |
+#endif |
|
| 181 |
+} |
|
| 182 |
+ |
|
| 183 |
+bool NDS_SetROM(uint8_t * rom, uint32_t mask) |
|
| 184 |
+{
|
|
| 185 |
+ MMU_setRom(rom, mask); |
|
| 186 |
+ |
|
| 187 |
+ return true; |
|
| 188 |
+} |
|
| 189 |
+ |
|
| 190 |
+NDS_header * NDS_getROMHeader() |
|
| 191 |
+{
|
|
| 192 |
+ if(MMU.CART_ROM == MMU.UNUSED_RAM) return NULL; |
|
| 193 |
+ NDS_header * header = new NDS_header; |
|
| 194 |
+ |
|
| 195 |
+ memcpy(header->gameTile, MMU.CART_ROM, 12); |
|
| 196 |
+ memcpy(header->gameCode, MMU.CART_ROM + 12, 4); |
|
| 197 |
+ header->makerCode = T1ReadWord(MMU.CART_ROM, 16); |
|
| 198 |
+ header->unitCode = MMU.CART_ROM[18]; |
|
| 199 |
+ header->deviceCode = MMU.CART_ROM[19]; |
|
| 200 |
+ header->cardSize = MMU.CART_ROM[20]; |
|
| 201 |
+ memcpy(header->cardInfo, MMU.CART_ROM + 21, 8); |
|
| 202 |
+ header->flags = MMU.CART_ROM[29]; |
|
| 203 |
+ header->romversion = MMU.CART_ROM[30]; |
|
| 204 |
+ header->ARM9src = T1ReadLong(MMU.CART_ROM, 32); |
|
| 205 |
+ header->ARM9exe = T1ReadLong(MMU.CART_ROM, 36); |
|
| 206 |
+ header->ARM9cpy = T1ReadLong(MMU.CART_ROM, 40); |
|
| 207 |
+ header->ARM9binSize = T1ReadLong(MMU.CART_ROM, 44); |
|
| 208 |
+ header->ARM7src = T1ReadLong(MMU.CART_ROM, 48); |
|
| 209 |
+ header->ARM7exe = T1ReadLong(MMU.CART_ROM, 52); |
|
| 210 |
+ header->ARM7cpy = T1ReadLong(MMU.CART_ROM, 56); |
|
| 211 |
+ header->ARM7binSize = T1ReadLong(MMU.CART_ROM, 60); |
|
| 212 |
+ header->FNameTblOff = T1ReadLong(MMU.CART_ROM, 64); |
|
| 213 |
+ header->FNameTblSize = T1ReadLong(MMU.CART_ROM, 68); |
|
| 214 |
+ header->FATOff = T1ReadLong(MMU.CART_ROM, 72); |
|
| 215 |
+ header->FATSize = T1ReadLong(MMU.CART_ROM, 76); |
|
| 216 |
+ header->ARM9OverlayOff = T1ReadLong(MMU.CART_ROM, 80); |
|
| 217 |
+ header->ARM9OverlaySize = T1ReadLong(MMU.CART_ROM, 84); |
|
| 218 |
+ header->ARM7OverlayOff = T1ReadLong(MMU.CART_ROM, 88); |
|
| 219 |
+ header->ARM7OverlaySize = T1ReadLong(MMU.CART_ROM, 92); |
|
| 220 |
+ header->unknown2a = T1ReadLong(MMU.CART_ROM, 96); |
|
| 221 |
+ header->unknown2b = T1ReadLong(MMU.CART_ROM, 100); |
|
| 222 |
+ header->IconOff = T1ReadLong(MMU.CART_ROM, 104); |
|
| 223 |
+ header->CRC16 = T1ReadWord(MMU.CART_ROM, 108); |
|
| 224 |
+ header->ROMtimeout = T1ReadWord(MMU.CART_ROM, 110); |
|
| 225 |
+ header->ARM9unk = T1ReadLong(MMU.CART_ROM, 112); |
|
| 226 |
+ header->ARM7unk = T1ReadLong(MMU.CART_ROM, 116); |
|
| 227 |
+ memcpy(header->unknown3c, MMU.CART_ROM + 120, 8); |
|
| 228 |
+ header->ROMSize = T1ReadLong(MMU.CART_ROM, 128); |
|
| 229 |
+ header->HeaderSize = T1ReadLong(MMU.CART_ROM, 132); |
|
| 230 |
+ memcpy(header->unknown5, MMU.CART_ROM + 136, 56); |
|
| 231 |
+ memcpy(header->logo, MMU.CART_ROM + 192, 156); |
|
| 232 |
+ header->logoCRC16 = T1ReadWord(MMU.CART_ROM, 348); |
|
| 233 |
+ header->headerCRC16 = T1ReadWord(MMU.CART_ROM, 350); |
|
| 234 |
+ memcpy(header->reserved, MMU.CART_ROM + 352, std::min(160, (int)gameInfo.romsize - 352)); |
|
| 235 |
+ |
|
| 236 |
+ return header; |
|
| 237 |
+} |
|
| 238 |
+ |
|
| 239 |
+ |
|
| 240 |
+ |
|
| 241 |
+ |
|
| 242 |
+/*void debug() |
|
| 243 |
+{
|
|
| 244 |
+ //if(NDS_ARM9.R[15]==0x020520DC) emu_halt(); |
|
| 245 |
+ //DSLinux |
|
| 246 |
+ //if(NDS_ARM9.CPSR.bits.mode == 0) emu_halt(); |
|
| 247 |
+ //if((NDS_ARM9.R[15]&0xFFFFF000)==0) emu_halt(); |
|
| 248 |
+ //if((NDS_ARM9.R[15]==0x0201B4F4)&&(NDS_ARM9.R[1]==0x0)) emu_halt(); |
|
| 249 |
+ //AOE |
|
| 250 |
+ //if((NDS_ARM9.R[15]==0x01FFE194)&&(NDS_ARM9.R[0]==0)) emu_halt(); |
|
| 251 |
+ //if((NDS_ARM9.R[15]==0x01FFE134)&&(NDS_ARM9.R[0]==0)) emu_halt(); |
|
| 252 |
+ |
|
| 253 |
+ //BBMAN |
|
| 254 |
+ //if(NDS_ARM9.R[15]==0x02098B4C) emu_halt(); |
|
| 255 |
+ //if(NDS_ARM9.R[15]==0x02004924) emu_halt(); |
|
| 256 |
+ //if(NDS_ARM9.R[15]==0x02004890) emu_halt(); |
|
| 257 |
+ |
|
| 258 |
+ //if(NDS_ARM9.R[15]==0x0202B800) emu_halt(); |
|
| 259 |
+ //if(NDS_ARM9.R[15]==0x0202B3DC) emu_halt(); |
|
| 260 |
+ //if((NDS_ARM9.R[1]==0x9AC29AC1)&&(!fait)) {emu_halt();fait = true;}
|
|
| 261 |
+ //if(NDS_ARM9.R[1]==0x0400004A) {emu_halt();fait = true;}
|
|
| 262 |
+ if(NDS_ARM9.R[4]==0x2E33373C) emu_halt(); |
|
| 263 |
+ if(NDS_ARM9.R[15]==0x02036668) //emu_halt(); |
|
| 264 |
+ {
|
|
| 265 |
+ nds.logcount++; |
|
| 266 |
+ sprintf(logbuf, "%d %08X", nds.logcount, NDS_ARM9.R[13]); |
|
| 267 |
+ log::ajouter(logbuf); |
|
| 268 |
+ if(nds.logcount==89) execute=false; |
|
| 269 |
+ } |
|
| 270 |
+ //if(NDS_ARM9.instruction==0) emu_halt(); |
|
| 271 |
+ //if((NDS_ARM9.R[15]>>28)) emu_halt(); |
|
| 272 |
+}*/ |
|
| 273 |
+ |
|
| 274 |
+//#define DSGBA_LOADER_SIZE 512 |
|
| 275 |
+/*enum |
|
| 276 |
+{
|
|
| 277 |
+ ROM_NDS = 0, |
|
| 278 |
+ ROM_DSGBA |
|
| 279 |
+};*/ |
|
| 280 |
+ |
|
| 281 |
+#if 0 /* not used */ |
|
| 282 |
+//http://www.aggregate.org/MAGIC/#Population%20Count%20(Ones%20Count) |
|
| 283 |
+static uint32_t ones32(uint32_t x) |
|
| 284 |
+{
|
|
| 285 |
+ /* 32-bit recursive reduction using SWAR... |
|
| 286 |
+ but first step is mapping 2-bit values |
|
| 287 |
+ into sum of 2 1-bit values in sneaky way |
|
| 288 |
+ */ |
|
| 289 |
+ x -= ((x >> 1) & 0x55555555); |
|
| 290 |
+ x = (((x >> 2) & 0x33333333) + (x & 0x33333333)); |
|
| 291 |
+ x = (((x >> 4) + x) & 0x0f0f0f0f); |
|
| 292 |
+ x += (x >> 8); |
|
| 293 |
+ x += (x >> 16); |
|
| 294 |
+ return x & 0x0000003f; |
|
| 295 |
+} |
|
| 296 |
+#endif |
|
| 297 |
+ |
|
| 298 |
+RomBanner::RomBanner(bool defaultInit) |
|
| 299 |
+{
|
|
| 300 |
+ if(!defaultInit) return; |
|
| 301 |
+ version = 1; //Version (0001h) |
|
| 302 |
+ crc16 = 0; //CRC16 across entries 020h..83Fh |
|
| 303 |
+ memset(reserved,0,sizeof(reserved)); |
|
| 304 |
+ memset(bitmap,0,sizeof(bitmap)); |
|
| 305 |
+ memset(palette,0,sizeof(palette)); |
|
| 306 |
+ memset(titles,0,sizeof(titles)); |
|
| 307 |
+ memset(end0xFF,0,sizeof(end0xFF)); |
|
| 308 |
+} |
|
| 309 |
+ |
|
| 310 |
+/*bool GameInfo::hasRomBanner() |
|
| 311 |
+{
|
|
| 312 |
+ if(header.IconOff + sizeof(RomBanner) > romsize) |
|
| 313 |
+ return false; |
|
| 314 |
+ else return true; |
|
| 315 |
+}*/ |
|
| 316 |
+ |
|
| 317 |
+/*const RomBanner& GameInfo::getRomBanner() |
|
| 318 |
+{
|
|
| 319 |
+ //we may not have a valid banner. return a default one |
|
| 320 |
+ if(!hasRomBanner()) |
|
| 321 |
+ {
|
|
| 322 |
+ static RomBanner defaultBanner(true); |
|
| 323 |
+ return defaultBanner; |
|
| 324 |
+ } |
|
| 325 |
+ |
|
| 326 |
+ return *(RomBanner*)(romdata+header.IconOff); |
|
| 327 |
+}*/ |
|
| 328 |
+ |
|
| 329 |
+/*void GameInfo::populate() |
|
| 330 |
+{
|
|
| 331 |
+ const char *regions[] = { "JPFSEDIRKH",
|
|
| 332 |
+ "JPN", |
|
| 333 |
+ "EUR", |
|
| 334 |
+ "FRA", |
|
| 335 |
+ "ESP", |
|
| 336 |
+ "USA", |
|
| 337 |
+ "NOE", |
|
| 338 |
+ "ITA", |
|
| 339 |
+ "RUS", |
|
| 340 |
+ "KOR", |
|
| 341 |
+ "HOL", |
|
| 342 |
+ |
|
| 343 |
+ }; |
|
| 344 |
+ |
|
| 345 |
+ NDS_header * _header = NDS_getROMHeader(); |
|
| 346 |
+ header = *_header; |
|
| 347 |
+ delete _header; |
|
| 348 |
+ |
|
| 349 |
+ memset(ROMserial, 0, sizeof(ROMserial)); |
|
| 350 |
+ memset(ROMname, 0, sizeof(ROMname)); |
|
| 351 |
+ |
|
| 352 |
+ if ( |
|
| 353 |
+ //Option 1. - look for this instruction in the game title |
|
| 354 |
+ //(did this ever work?) |
|
| 355 |
+ //(header->gameTile[0] == 0x2E) && |
|
| 356 |
+ //(header->gameTile[1] == 0x00) && |
|
| 357 |
+ //(header->gameTile[2] == 0x00) && |
|
| 358 |
+ //(header->gameTile[3] == 0xEA) |
|
| 359 |
+ //) && |
|
| 360 |
+ //option 2. - look for gamecode #### (default for ndstool) |
|
| 361 |
+ //or an invalid gamecode |
|
| 362 |
+ ( |
|
| 363 |
+ ((header.gameCode[0] == 0x23) && |
|
| 364 |
+ (header.gameCode[1] == 0x23) && |
|
| 365 |
+ (header.gameCode[2] == 0x23) && |
|
| 366 |
+ (header.gameCode[3] == 0x23) |
|
| 367 |
+ ) || |
|
| 368 |
+ (header.gameCode[0] == 0x00) |
|
| 369 |
+ ) |
|
| 370 |
+ && |
|
| 371 |
+ header.makerCode == 0x0 |
|
| 372 |
+ ) |
|
| 373 |
+ {
|
|
| 374 |
+ //we can't really make a serial for a homebrew game that hasnt set a game code |
|
| 375 |
+ strcpy(ROMserial, "Homebrew"); |
|
| 376 |
+ } |
|
| 377 |
+ else |
|
| 378 |
+ {
|
|
| 379 |
+ strcpy(ROMserial,"NTR- -"); |
|
| 380 |
+ memcpy(ROMserial+4, header.gameCode, 4); |
|
| 381 |
+ |
|
| 382 |
+ uint32_t region = (uint32_t)(std::max<int32_t>(strchr(regions[0],header.gameCode[3]) - regions[0] + 1, 0)); |
|
| 383 |
+ if (region != 0) |
|
| 384 |
+ strcat(ROMserial, regions[region]); |
|
| 385 |
+ else |
|
| 386 |
+ strcat(ROMserial, "Unknown"); |
|
| 387 |
+ } |
|
| 388 |
+ |
|
| 389 |
+ //rom name is probably set even in homebrew |
|
| 390 |
+ memset(ROMname, 0, sizeof(ROMname)); |
|
| 391 |
+ memcpy(ROMname, header.gameTile, 12); |
|
| 392 |
+ trim(ROMname,20); |
|
| 393 |
+ |
|
| 394 |
+ if(header.IconOff < romsize) |
|
| 395 |
+ {
|
|
| 396 |
+ uint8_t num = (T1ReadByte((uint8_t*)romdata, header.IconOff) == 1)?6:7; |
|
| 397 |
+ for (int i = 0; i < num; i++) |
|
| 398 |
+ {
|
|
| 399 |
+ wcstombs(ROMfullName[i], (wchar_t *)(romdata+header.IconOff+0x240+(i*0x100)), 0x100); |
|
| 400 |
+ trim(ROMfullName[i]); |
|
| 401 |
+ } |
|
| 402 |
+ } |
|
| 403 |
+ |
|
| 404 |
+ //this may look like a poor heuristic for detecting homebrew, but it is actually pretty good. |
|
| 405 |
+ //setting your own game code is stupid, so homebrew should just leave it. |
|
| 406 |
+ //however, non-devkitARM-default makefiles may not have set this. |
|
| 407 |
+ isHomebrew = !memcmp(header.gameCode,"####",4); |
|
| 408 |
+}*/ |
|
| 409 |
+ |
|
| 410 |
+/*#ifdef _WINDOWS |
|
| 411 |
+ |
|
| 412 |
+//static std::vector<char> buffer; |
|
| 413 |
+//static std::vector<char> v; |
|
| 414 |
+ |
|
| 415 |
+static void loadrom(std::string fname) {
|
|
| 416 |
+ |
|
| 417 |
+ FILE* inf = fopen(fname.c_str(),"rb"); |
|
| 418 |
+ if(!inf) return; |
|
| 419 |
+ |
|
| 420 |
+ fseek(inf,0,SEEK_END); |
|
| 421 |
+ int size = ftell(inf); |
|
| 422 |
+ fseek(inf,0,SEEK_SET); |
|
| 423 |
+ |
|
| 424 |
+ gameInfo.resize(size); |
|
| 425 |
+ fread(gameInfo.romdata,1,size,inf); |
|
| 426 |
+ gameInfo.fillGap(); |
|
| 427 |
+ |
|
| 428 |
+ fclose(inf); |
|
| 429 |
+} |
|
| 430 |
+ |
|
| 431 |
+static int rom_init_path(const char *filename, const char *logicalFilename) |
|
| 432 |
+{
|
|
| 433 |
+ int type = ROM_NDS; |
|
| 434 |
+ |
|
| 435 |
+ path.init(logicalFilename); |
|
| 436 |
+ |
|
| 437 |
+ if ( path.isdsgba(path.path)) {
|
|
| 438 |
+ type = ROM_DSGBA; |
|
| 439 |
+ loadrom(path.path); |
|
| 440 |
+ } |
|
| 441 |
+ else if ( !strcasecmp(path.extension().c_str(), "nds")) {
|
|
| 442 |
+ type = ROM_NDS; |
|
| 443 |
+ loadrom(path.path); //n.b. this does nothing if the file can't be found (i.e. if it was an extracted tempfile)... |
|
| 444 |
+ //...but since the data was extracted to gameInfo then it is ok |
|
| 445 |
+ } |
|
| 446 |
+ //ds.gba in archives, it's already been loaded into memory at this point |
|
| 447 |
+ else if (path.isdsgba(std::string(logicalFilename))) {
|
|
| 448 |
+ type = ROM_DSGBA; |
|
| 449 |
+ } else {
|
|
| 450 |
+ //well, try to load it as an nds rom anyway |
|
| 451 |
+ type = ROM_NDS; |
|
| 452 |
+ loadrom(path.path); |
|
| 453 |
+ } |
|
| 454 |
+ |
|
| 455 |
+ if(type == ROM_DSGBA) |
|
| 456 |
+ {
|
|
| 457 |
+ std::vector<char> v(gameInfo.romdata + DSGBA_LOADER_SIZE, gameInfo.romdata + gameInfo.romsize); |
|
| 458 |
+ gameInfo.loadData(&v[0],gameInfo.romsize - DSGBA_LOADER_SIZE); |
|
| 459 |
+ } |
|
| 460 |
+ |
|
| 461 |
+ //check that size is at least the size of the header |
|
| 462 |
+ if (gameInfo.romsize < 352) {
|
|
| 463 |
+ return -1; |
|
| 464 |
+ } |
|
| 465 |
+ |
|
| 466 |
+ return 1; |
|
| 467 |
+} |
|
| 468 |
+#else |
|
| 469 |
+static int rom_init_path(const char *filename, const char *logicalFilename) |
|
| 470 |
+{
|
|
| 471 |
+ int ret; |
|
| 472 |
+ int type; |
|
| 473 |
+ ROMReader_struct *reader; |
|
| 474 |
+ void *file; |
|
| 475 |
+ uint32_t size; |
|
| 476 |
+ char *noext; |
|
| 477 |
+ |
|
| 478 |
+ noext = strdup(filename); |
|
| 479 |
+ reader = ROMReaderInit(&noext); |
|
| 480 |
+ free(noext); |
|
| 481 |
+ |
|
| 482 |
+ if (logicalFilename) |
|
| 483 |
+ path.init(logicalFilename); |
|
| 484 |
+ else |
|
| 485 |
+ path.init(filename); |
|
| 486 |
+ |
|
| 487 |
+ if (!strcasecmp(path.extension().c_str(), "zip")) |
|
| 488 |
+ type = ROM_NDS; |
|
| 489 |
+ else if (!strcasecmp(path.extension().c_str(), "nds")) |
|
| 490 |
+ type = ROM_NDS; |
|
| 491 |
+ else if (path.isdsgba(path.path)) |
|
| 492 |
+ type = ROM_DSGBA; |
|
| 493 |
+ else |
|
| 494 |
+ type = ROM_NDS; |
|
| 495 |
+ |
|
| 496 |
+ file = reader->Init(filename); |
|
| 497 |
+ if (!file) |
|
| 498 |
+ {
|
|
| 499 |
+ reader->DeInit(file); |
|
| 500 |
+ return -1; |
|
| 501 |
+ } |
|
| 502 |
+ |
|
| 503 |
+ size = reader->Size(file); |
|
| 504 |
+ |
|
| 505 |
+ if(type == ROM_DSGBA) |
|
| 506 |
+ {
|
|
| 507 |
+ reader->Seek(file, DSGBA_LOADER_SIZE, SEEK_SET); |
|
| 508 |
+ size -= DSGBA_LOADER_SIZE; |
|
| 509 |
+ } |
|
| 510 |
+ |
|
| 511 |
+ //check that size is at least the size of the header |
|
| 512 |
+ if (size < 352) {
|
|
| 513 |
+ reader->DeInit(file); |
|
| 514 |
+ return -1; |
|
| 515 |
+ } |
|
| 516 |
+ |
|
| 517 |
+ // Make sure old ROM is freed first(at least this way we won't be eating |
|
| 518 |
+ // up a ton of ram before the old ROM is freed) |
|
| 519 |
+ if(MMU.CART_ROM != MMU.UNUSED_RAM) |
|
| 520 |
+ NDS_FreeROM(); |
|
| 521 |
+ |
|
| 522 |
+ gameInfo.resize(size); |
|
| 523 |
+ ret = reader->Read(file, gameInfo.romdata, size); |
|
| 524 |
+ gameInfo.fillGap(); |
|
| 525 |
+ reader->DeInit(file); |
|
| 526 |
+ |
|
| 527 |
+ return ret; |
|
| 528 |
+} |
|
| 529 |
+#endif*/ |
|
| 530 |
+ |
|
| 531 |
+/*int NDS_LoadROM(const char *filename, const char *logicalFilename) |
|
| 532 |
+{
|
|
| 533 |
+ int ret; |
|
| 534 |
+ char buf[MAX_PATH]; |
|
| 535 |
+ |
|
| 536 |
+ if (filename == NULL) |
|
| 537 |
+ return -1; |
|
| 538 |
+ |
|
| 539 |
+ ret = rom_init_path(filename, logicalFilename); |
|
| 540 |
+ if (ret < 1) |
|
| 541 |
+ return ret; |
|
| 542 |
+ |
|
| 543 |
+ //decrypt if necessary.. |
|
| 544 |
+ //but this is untested and suspected to fail on big endian, so lets not support this on big endian |
|
| 545 |
+#ifndef WORDS_BIGENDIAN |
|
| 546 |
+ bool okRom = DecryptSecureArea((uint8_t*)gameInfo.romdata,gameInfo.romsize); |
|
| 547 |
+ |
|
| 548 |
+ if(!okRom) {
|
|
| 549 |
+ printf("Specified file is not a valid rom\n");
|
|
| 550 |
+ return -1; |
|
| 551 |
+ } |
|
| 552 |
+#endif |
|
| 553 |
+ |
|
| 554 |
+ if (cheatSearch) |
|
| 555 |
+ cheatSearch->close(); |
|
| 556 |
+ FCEUI_StopMovie(); |
|
| 557 |
+ |
|
| 558 |
+ MMU_unsetRom(); |
|
| 559 |
+ NDS_SetROM((uint8_t*)gameInfo.romdata, gameInfo.mask); |
|
| 560 |
+ |
|
| 561 |
+ gameInfo.populate(); |
|
| 562 |
+ gameInfo.crc = crc32(0,(uint8_t*)gameInfo.romdata,gameInfo.romsize); |
|
| 563 |
+ //INFO("\nROM game code: %c%c%c%c\n", gameInfo.header.gameCode[0], gameInfo.header.gameCode[1], gameInfo.header.gameCode[2], gameInfo.header.gameCode[3]);
|
|
| 564 |
+ //INFO("ROM crc: %08X\n", gameInfo.crc);
|
|
| 565 |
+ //INFO("ROM serial: %s\n", gameInfo.ROMserial);
|
|
| 566 |
+ //INFO("ROM internal name: %s\n", gameInfo.ROMname);
|
|
| 567 |
+ |
|
| 568 |
+ memset(buf, 0, MAX_PATH); |
|
| 569 |
+ strcpy(buf, path.pathToModule); |
|
| 570 |
+ strcat(buf, "desmume.ddb"); // DeSmuME database :) |
|
| 571 |
+ advsc.setDatabase(buf); |
|
| 572 |
+ buf[0] = gameInfo.header.gameCode[0]; |
|
| 573 |
+ buf[1] = gameInfo.header.gameCode[1]; |
|
| 574 |
+ buf[2] = gameInfo.header.gameCode[2]; |
|
| 575 |
+ buf[3] = gameInfo.header.gameCode[3]; |
|
| 576 |
+ buf[4] = 0; |
|
| 577 |
+ if (advsc.checkDB(buf)) |
|
| 578 |
+ {
|
|
| 579 |
+ u8 sv = advsc.getSaveType(); |
|
| 580 |
+ printf("ADVANsCEne database:\n");
|
|
| 581 |
+ printf("\t* ROM save type: ");
|
|
| 582 |
+ if (sv == 0xFF) |
|
| 583 |
+ printf("Unknown");
|
|
| 584 |
+ else |
|
| 585 |
+ if (sv == 0xFE) |
|
| 586 |
+ printf("None");
|
|
| 587 |
+ else |
|
| 588 |
+ {
|
|
| 589 |
+ printf("%s", save_names[sv]);
|
|
| 590 |
+ if (CommonSettings.autodetectBackupMethod == 1) |
|
| 591 |
+ backup_setManualBackupType(sv+1); |
|
| 592 |
+ } |
|
| 593 |
+ printf("\n\t* ROM crc: %08X\n", advsc.getCRC32());
|
|
| 594 |
+ } |
|
| 595 |
+ printf("\n");
|
|
| 596 |
+ |
|
| 597 |
+ //for homebrew, try auto-patching DLDI. should be benign if there is no DLDI or if it fails |
|
| 598 |
+ if(gameInfo.isHomebrew) |
|
| 599 |
+ DLDI::tryPatch((void*)gameInfo.romdata, gameInfo.romsize); |
|
| 600 |
+ |
|
| 601 |
+ memset(buf, 0, MAX_PATH); |
|
| 602 |
+ path.getpathnoext(path.BATTERY, buf); |
|
| 603 |
+ strcat(buf, ".dsv"); // DeSmuME memory card :) |
|
| 604 |
+ MMU_new.backupDevice.load_rom(buf); |
|
| 605 |
+ |
|
| 606 |
+ memset(buf, 0, MAX_PATH); |
|
| 607 |
+ path.getpathnoext(path.CHEATS, buf); |
|
| 608 |
+ strcat(buf, ".dct"); // DeSmuME cheat :) |
|
| 609 |
+ cheats->init(buf); |
|
| 610 |
+ |
|
| 611 |
+ NDS_Reset(); |
|
| 612 |
+ |
|
| 613 |
+ return ret; |
|
| 614 |
+}*/ |
|
| 615 |
+ |
|
| 616 |
+void NDS_FreeROM() |
|
| 617 |
+{
|
|
| 618 |
+ //FCEUI_StopMovie(); |
|
| 619 |
+ if ((uint8_t*)MMU.CART_ROM == (uint8_t*)gameInfo.romdata) |
|
| 620 |
+ gameInfo.romdata = NULL; |
|
| 621 |
+ if (MMU.CART_ROM != MMU.UNUSED_RAM) |
|
| 622 |
+ delete [] MMU.CART_ROM; |
|
| 623 |
+ MMU_unsetRom(); |
|
| 624 |
+} |
|
| 625 |
+ |
|
| 626 |
+ |
|
| 627 |
+ |
|
| 628 |
+/*int NDS_ImportSave(const char *filename) |
|
| 629 |
+{
|
|
| 630 |
+ if (strlen(filename) < 4) |
|
| 631 |
+ return 0; |
|
| 632 |
+ |
|
| 633 |
+ if (memcmp(filename+strlen(filename)-4, ".duc", 4) == 0) |
|
| 634 |
+ return MMU_new.backupDevice.load_duc(filename); |
|
| 635 |
+ else |
|
| 636 |
+ if (MMU_new.backupDevice.load_no_gba(filename)) |
|
| 637 |
+ return 1; |
|
| 638 |
+ else |
|
| 639 |
+ return MMU_new.backupDevice.load_raw(filename); |
|
| 640 |
+ |
|
| 641 |
+ //return 0; |
|
| 642 |
+}*/ |
|
| 643 |
+ |
|
| 644 |
+/*bool NDS_ExportSave(const char *filename) |
|
| 645 |
+{
|
|
| 646 |
+ if (strlen(filename) < 4) |
|
| 647 |
+ return false; |
|
| 648 |
+ |
|
| 649 |
+ if (memcmp(filename+strlen(filename)-5, ".sav*", 5) == 0) |
|
| 650 |
+ {
|
|
| 651 |
+ char tmp[MAX_PATH]; |
|
| 652 |
+ memset(tmp, 0, MAX_PATH); |
|
| 653 |
+ strcpy(tmp, filename); |
|
| 654 |
+ tmp[strlen(tmp)-1] = 0; |
|
| 655 |
+ return MMU_new.backupDevice.save_no_gba(tmp); |
|
| 656 |
+ } |
|
| 657 |
+ |
|
| 658 |
+ if (memcmp(filename+strlen(filename)-4, ".sav", 4) == 0) |
|
| 659 |
+ return MMU_new.backupDevice.save_raw(filename); |
|
| 660 |
+ |
|
| 661 |
+ return false; |
|
| 662 |
+}*/ |
|
| 663 |
+ |
|
| 664 |
+/*static int WritePNGChunk(FILE *fp, uint32 size, const char *type, const uint8 *data) |
|
| 665 |
+{
|
|
| 666 |
+ uint32 crc; |
|
| 667 |
+ |
|
| 668 |
+ uint8 tempo[4]; |
|
| 669 |
+ |
|
| 670 |
+ tempo[0]=size>>24; |
|
| 671 |
+ tempo[1]=size>>16; |
|
| 672 |
+ tempo[2]=size>>8; |
|
| 673 |
+ tempo[3]=size; |
|
| 674 |
+ |
|
| 675 |
+ if(fwrite(tempo,4,1,fp)!=1) |
|
| 676 |
+ return 0; |
|
| 677 |
+ if(fwrite(type,4,1,fp)!=1) |
|
| 678 |
+ return 0; |
|
| 679 |
+ |
|
| 680 |
+ if(size) |
|
| 681 |
+ if(fwrite(data,1,size,fp)!=size) |
|
| 682 |
+ return 0; |
|
| 683 |
+ |
|
| 684 |
+ crc = crc32(0,(uint8 *)type,4); |
|
| 685 |
+ if(size) |
|
| 686 |
+ crc = crc32(crc,data,size); |
|
| 687 |
+ |
|
| 688 |
+ tempo[0]=crc>>24; |
|
| 689 |
+ tempo[1]=crc>>16; |
|
| 690 |
+ tempo[2]=crc>>8; |
|
| 691 |
+ tempo[3]=crc; |
|
| 692 |
+ |
|
| 693 |
+ if(fwrite(tempo,4,1,fp)!=1) |
|
| 694 |
+ return 0; |
|
| 695 |
+ return 1; |
|
| 696 |
+}*/ |
|
| 697 |
+/*int NDS_WritePNG(const char *fname) |
|
| 698 |
+{
|
|
| 699 |
+ int x, y; |
|
| 700 |
+ int width=256; |
|
| 701 |
+ int height=192*2; |
|
| 702 |
+ uint16_t * bmp = (uint16_t *)GPU_screen; |
|
| 703 |
+ FILE *pp=NULL; |
|
| 704 |
+ uint8 *compmem = NULL; |
|
| 705 |
+ uLongf compmemsize = (uLongf)( (height * (width + 1) * 3 * 1.001 + 1) + 12 ); |
|
| 706 |
+ |
|
| 707 |
+ if(!(compmem=(uint8 *)malloc(compmemsize))) |
|
| 708 |
+ return 0; |
|
| 709 |
+ |
|
| 710 |
+ if(!(pp=fopen(fname, "wb"))) |
|
| 711 |
+ {
|
|
| 712 |
+ goto PNGerr; |
|
| 713 |
+ } |
|
| 714 |
+ {
|
|
| 715 |
+ const uint8 header[8]={137,80,78,71,13,10,26,10};
|
|
| 716 |
+ if(fwrite(header,8,1,pp)!=1) |
|
| 717 |
+ goto PNGerr; |
|
| 718 |
+ } |
|
| 719 |
+ |
|
| 720 |
+ {
|
|
| 721 |
+ uint8 chunko[13]; |
|
| 722 |
+ |
|
| 723 |
+ chunko[0] = width >> 24; // Width |
|
| 724 |
+ chunko[1] = width >> 16; |
|
| 725 |
+ chunko[2] = width >> 8; |
|
| 726 |
+ chunko[3] = width; |
|
| 727 |
+ |
|
| 728 |
+ chunko[4] = height >> 24; // Height |
|
| 729 |
+ chunko[5] = height >> 16; |
|
| 730 |
+ chunko[6] = height >> 8; |
|
| 731 |
+ chunko[7] = height; |
|
| 732 |
+ |
|
| 733 |
+ chunko[8]=8; // 8 bits per sample(24 bits per pixel) |
|
| 734 |
+ chunko[9]=2; // Color type; RGB triplet |
|
| 735 |
+ chunko[10]=0; // compression: deflate |
|
| 736 |
+ chunko[11]=0; // Basic adapative filter set(though none are used). |
|
| 737 |
+ chunko[12]=0; // No interlace. |
|
| 738 |
+ |
|
| 739 |
+ if(!WritePNGChunk(pp,13,"IHDR",chunko)) |
|
| 740 |
+ goto PNGerr; |
|
| 741 |
+ } |
|
| 742 |
+ |
|
| 743 |
+ {
|
|
| 744 |
+ uint8 *tmp_buffer; |
|
| 745 |
+ uint8 *tmp_inc; |
|
| 746 |
+ tmp_inc = tmp_buffer = (uint8 *)malloc((width * 3 + 1) * height); |
|
| 747 |
+ |
|
| 748 |
+ for(y=0;y<height;y++) |
|
| 749 |
+ {
|
|
| 750 |
+ *tmp_inc = 0; |
|
| 751 |
+ tmp_inc++; |
|
| 752 |
+ for(x=0;x<width;x++) |
|
| 753 |
+ {
|
|
| 754 |
+ int r,g,b; |
|
| 755 |
+ uint16_t pixel = bmp[y*256+x]; |
|
| 756 |
+ r = pixel>>10; |
|
| 757 |
+ pixel-=r<<10; |
|
| 758 |
+ g = pixel>>5; |
|
| 759 |
+ pixel-=g<<5; |
|
| 760 |
+ b = pixel; |
|
| 761 |
+ r*=255/31; |
|
| 762 |
+ g*=255/31; |
|
| 763 |
+ b*=255/31; |
|
| 764 |
+ tmp_inc[0] = b; |
|
| 765 |
+ tmp_inc[1] = g; |
|
| 766 |
+ tmp_inc[2] = r; |
|
| 767 |
+ tmp_inc += 3; |
|
| 768 |
+ } |
|
| 769 |
+ } |
|
| 770 |
+ |
|
| 771 |
+ if(compress(compmem, &compmemsize, tmp_buffer, height * (width * 3 + 1))!=Z_OK) |
|
| 772 |
+ {
|
|
| 773 |
+ if(tmp_buffer) free(tmp_buffer); |
|
| 774 |
+ goto PNGerr; |
|
| 775 |
+ } |
|
| 776 |
+ if(tmp_buffer) free(tmp_buffer); |
|
| 777 |
+ if(!WritePNGChunk(pp,compmemsize,"IDAT",compmem)) |
|
| 778 |
+ goto PNGerr; |
|
| 779 |
+ } |
|
| 780 |
+ if(!WritePNGChunk(pp,0,"IEND",0)) |
|
| 781 |
+ goto PNGerr; |
|
| 782 |
+ |
|
| 783 |
+ free(compmem); |
|
| 784 |
+ fclose(pp); |
|
| 785 |
+ |
|
| 786 |
+ return 1; |
|
| 787 |
+ |
|
| 788 |
+PNGerr: |
|
| 789 |
+ if(compmem) |
|
| 790 |
+ free(compmem); |
|
| 791 |
+ if(pp) |
|
| 792 |
+ fclose(pp); |
|
| 793 |
+ return 0; |
|
| 794 |
+}*/ |
|
| 795 |
+ |
|
| 796 |
+/*typedef struct |
|
| 797 |
+{
|
|
| 798 |
+ uint32_t size; |
|
| 799 |
+ int32_t width; |
|
| 800 |
+ int32_t height; |
|
| 801 |
+ uint16_t planes; |
|
| 802 |
+ uint16_t bpp; |
|
| 803 |
+ uint32_t cmptype; |
|
| 804 |
+ uint32_t imgsize; |
|
| 805 |
+ int32_t hppm; |
|
| 806 |
+ int32_t vppm; |
|
| 807 |
+ uint32_t numcol; |
|
| 808 |
+ uint32_t numimpcol; |
|
| 809 |
+} bmpimgheader_struct; |
|
| 810 |
+ |
|
| 811 |
+#include "PACKED.h" |
|
| 812 |
+typedef struct |
|
| 813 |
+{
|
|
| 814 |
+ uint16_t id __PACKED; |
|
| 815 |
+ uint32_t size __PACKED; |
|
| 816 |
+ uint16_t reserved1 __PACKED; |
|
| 817 |
+ uint16_t reserved2 __PACKED; |
|
| 818 |
+ uint32_t imgoffset __PACKED; |
|
| 819 |
+} bmpfileheader_struct; |
|
| 820 |
+#include "PACKED_END.h"*/ |
|
| 821 |
+ |
|
| 822 |
+/*int NDS_WriteBMP(const char *filename) |
|
| 823 |
+{
|
|
| 824 |
+ bmpfileheader_struct fileheader; |
|
| 825 |
+ bmpimgheader_struct imageheader; |
|
| 826 |
+ FILE *file; |
|
| 827 |
+ int i,j; |
|
| 828 |
+ uint16_t * bmp = (uint16_t *)GPU_screen; |
|
| 829 |
+ size_t elems_written = 0; |
|
| 830 |
+ |
|
| 831 |
+ memset(&fileheader, 0, sizeof(fileheader)); |
|
| 832 |
+ fileheader.size = sizeof(fileheader); |
|
| 833 |
+ fileheader.id = 'B' | ('M' << 8);
|
|
| 834 |
+ fileheader.imgoffset = sizeof(fileheader)+sizeof(imageheader); |
|
| 835 |
+ |
|
| 836 |
+ memset(&imageheader, 0, sizeof(imageheader)); |
|
| 837 |
+ imageheader.size = sizeof(imageheader); |
|
| 838 |
+ imageheader.width = 256; |
|
| 839 |
+ imageheader.height = 192*2; |
|
| 840 |
+ imageheader.planes = 1; |
|
| 841 |
+ imageheader.bpp = 24; |
|
| 842 |
+ imageheader.cmptype = 0; // None |
|
| 843 |
+ imageheader.imgsize = imageheader.width * imageheader.height * 3; |
|
| 844 |
+ |
|
| 845 |
+ if ((file = fopen(filename,"wb")) == NULL) |
|
| 846 |
+ return 0; |
|
| 847 |
+ |
|
| 848 |
+ elems_written += fwrite(&fileheader, 1, sizeof(fileheader), file); |
|
| 849 |
+ elems_written += fwrite(&imageheader, 1, sizeof(imageheader), file); |
|
| 850 |
+ |
|
| 851 |
+ for(j=0;j<192*2;j++) |
|
| 852 |
+ {
|
|
| 853 |
+ for(i=0;i<256;i++) |
|
| 854 |
+ {
|
|
| 855 |
+ uint8_t r,g,b; |
|
| 856 |
+ uint16_t pixel = bmp[(192*2-j-1)*256+i]; |
|
| 857 |
+ r = pixel>>10; |
|
| 858 |
+ pixel-=r<<10; |
|
| 859 |
+ g = pixel>>5; |
|
| 860 |
+ pixel-=g<<5; |
|
| 861 |
+ b = (uint8_t)pixel; |
|
| 862 |
+ r*=255/31; |
|
| 863 |
+ g*=255/31; |
|
| 864 |
+ b*=255/31; |
|
| 865 |
+ elems_written += fwrite(&r, 1, sizeof(uint8_t), file); |
|
| 866 |
+ elems_written += fwrite(&g, 1, sizeof(uint8_t), file); |
|
| 867 |
+ elems_written += fwrite(&b, 1, sizeof(uint8_t), file); |
|
| 868 |
+ } |
|
| 869 |
+ } |
|
| 870 |
+ fclose(file); |
|
| 871 |
+ |
|
| 872 |
+ return 1; |
|
| 873 |
+}*/ |
|
| 874 |
+ |
|
| 875 |
+/*int NDS_WriteBMP_32bppBuffer(int width, int height, const void* buf, const char *filename) |
|
| 876 |
+{
|
|
| 877 |
+ bmpfileheader_struct fileheader; |
|
| 878 |
+ bmpimgheader_struct imageheader; |
|
| 879 |
+ FILE *file; |
|
| 880 |
+ size_t elems_written = 0; |
|
| 881 |
+ memset(&fileheader, 0, sizeof(fileheader)); |
|
| 882 |
+ fileheader.size = sizeof(fileheader); |
|
| 883 |
+ fileheader.id = 'B' | ('M' << 8);
|
|
| 884 |
+ fileheader.imgoffset = sizeof(fileheader)+sizeof(imageheader); |
|
| 885 |
+ |
|
| 886 |
+ memset(&imageheader, 0, sizeof(imageheader)); |
|
| 887 |
+ imageheader.size = sizeof(imageheader); |
|
| 888 |
+ imageheader.width = width; |
|
| 889 |
+ imageheader.height = height; |
|
| 890 |
+ imageheader.planes = 1; |
|
| 891 |
+ imageheader.bpp = 32; |
|
| 892 |
+ imageheader.cmptype = 0; // None |
|
| 893 |
+ imageheader.imgsize = imageheader.width * imageheader.height * 4; |
|
| 894 |
+ |
|
| 895 |
+ if ((file = fopen(filename,"wb")) == NULL) |
|
| 896 |
+ return 0; |
|
| 897 |
+ |
|
| 898 |
+ elems_written += fwrite(&fileheader, 1, sizeof(fileheader), file); |
|
| 899 |
+ elems_written += fwrite(&imageheader, 1, sizeof(imageheader), file); |
|
| 900 |
+ |
|
| 901 |
+ for(int i=0;i<height;i++) |
|
| 902 |
+ for(int x=0;x<width;x++) |
|
| 903 |
+ {
|
|
| 904 |
+ uint8_t* pixel = (uint8_t*)buf + (height-i-1)*width*4; |
|
| 905 |
+ pixel += (x*4); |
|
| 906 |
+ elems_written += fwrite(pixel+2,1,1,file); |
|
| 907 |
+ elems_written += fwrite(pixel+1,1,1,file); |
|
| 908 |
+ elems_written += fwrite(pixel+0,1,1,file); |
|
| 909 |
+ elems_written += fwrite(pixel+3,1,1,file); |
|
| 910 |
+ } |
|
| 911 |
+ fclose(file); |
|
| 912 |
+ |
|
| 913 |
+ return 1; |
|
| 914 |
+}*/ |
|
| 915 |
+ |
|
| 916 |
+void NDS_Sleep() { nds.sleeping = true; }
|
|
| 917 |
+/*void NDS_ToggleCardEject() |
|
| 918 |
+{
|
|
| 919 |
+ if(!nds.cardEjected) |
|
| 920 |
+ {
|
|
| 921 |
+ //staff of kings will test this (it also uses the arm9 0xB8 poll) |
|
| 922 |
+ NDS_makeIrq(ARMCPU_ARM7, IRQ_BIT_GC_IREQ_MC); |
|
| 923 |
+ } |
|
| 924 |
+ nds.cardEjected ^= true; |
|
| 925 |
+}*/ |
|
| 926 |
+ |
|
| 927 |
+ |
|
| 928 |
+/*class FrameSkipper |
|
| 929 |
+{
|
|
| 930 |
+public: |
|
| 931 |
+ void RequestSkip() |
|
| 932 |
+ {
|
|
| 933 |
+ nextSkip = true; |
|
| 934 |
+ } |
|
| 935 |
+ void OmitSkip(bool force, bool forceEvenIfCapturing=false) |
|
| 936 |
+ {
|
|
| 937 |
+ nextSkip = false; |
|
| 938 |
+ if((force && consecutiveNonCaptures > 30) || forceEvenIfCapturing) |
|
| 939 |
+ {
|
|
| 940 |
+ SkipCur2DFrame = false; |
|
| 941 |
+ SkipCur3DFrame = false; |
|
| 942 |
+ SkipNext2DFrame = false; |
|
| 943 |
+ if(forceEvenIfCapturing) |
|
| 944 |
+ consecutiveNonCaptures = 0; |
|
| 945 |
+ } |
|
| 946 |
+ } |
|
| 947 |
+ void Advance() |
|
| 948 |
+ {
|
|
| 949 |
+ bool capturing = false*//*(MainScreen.gpu->dispCapCnt.enabled || (MainScreen.gpu->dispCapCnt.val & 0x80000000))*//*; |
|
| 950 |
+ |
|
| 951 |
+ if(capturing && consecutiveNonCaptures > 30) |
|
| 952 |
+ {
|
|
| 953 |
+ // the worst-looking graphics corruption problems from frameskip |
|
| 954 |
+ // are the result of skipping the capture on first frame it turns on. |
|
| 955 |
+ // so we do this to handle the capture immediately, |
|
| 956 |
+ // despite the risk of 1 frame of 2d/3d mismatch or wrong screen display. |
|
| 957 |
+ SkipNext2DFrame = false; |
|
| 958 |
+ nextSkip = false; |
|
| 959 |
+ } |
|
| 960 |
+ else if(*//*lastOffset != MainScreen.offset && *//*lastSkip && !skipped) |
|
| 961 |
+ {
|
|
| 962 |
+ // if we're switching from not skipping to skipping |
|
| 963 |
+ // and the screens are also switching around this frame, |
|
| 964 |
+ // go for 1 extra frame without skipping. |
|
| 965 |
+ // this avoids the scenario where we only draw one of the two screens |
|
| 966 |
+ // when a game is switching screens every frame. |
|
| 967 |
+ nextSkip = false; |
|
| 968 |
+ } |
|
| 969 |
+ |
|
| 970 |
+ if(capturing) |
|
| 971 |
+ consecutiveNonCaptures = 0; |
|
| 972 |
+ else if(!(consecutiveNonCaptures > 9000)) // arbitrary cap to avoid eventual wrap |
|
| 973 |
+ consecutiveNonCaptures++; |
|
| 974 |
+ lastLastOffset = lastOffset; |
|
| 975 |
+ //lastOffset = MainScreen.offset; |
|
| 976 |
+ lastSkip = skipped; |
|
| 977 |
+ skipped = nextSkip; |
|
| 978 |
+ nextSkip = false; |
|
| 979 |
+ |
|
| 980 |
+ SkipCur2DFrame = SkipNext2DFrame; |
|
| 981 |
+ SkipCur3DFrame = skipped; |
|
| 982 |
+ SkipNext2DFrame = skipped; |
|
| 983 |
+ } |
|
| 984 |
+ inline bool ShouldSkip2D() |
|
| 985 |
+ {
|
|
| 986 |
+ return SkipCur2DFrame; |
|
| 987 |
+ } |
|
| 988 |
+ inline bool ShouldSkip3D() |
|
| 989 |
+ {
|
|
| 990 |
+ return SkipCur3DFrame; |
|
| 991 |
+ } |
|
| 992 |
+ FrameSkipper() |
|
| 993 |
+ {
|
|
| 994 |
+ nextSkip = false; |
|
| 995 |
+ skipped = false; |
|
| 996 |
+ lastSkip = false; |
|
| 997 |
+ lastOffset = 0; |
|
| 998 |
+ SkipCur2DFrame = false; |
|
| 999 |
+ SkipCur3DFrame = false; |
|
| 1000 |
+ SkipNext2DFrame = false; |
|
| 1001 |
+ consecutiveNonCaptures = 0; |
|
| 1002 |
+ } |
|
| 1003 |
+private: |
|
| 1004 |
+ bool nextSkip; |
|
| 1005 |
+ bool skipped; |
|
| 1006 |
+ bool lastSkip; |
|
| 1007 |
+ int lastOffset; |
|
| 1008 |
+ int lastLastOffset; |
|
| 1009 |
+ int consecutiveNonCaptures; |
|
| 1010 |
+ bool SkipCur2DFrame; |
|
| 1011 |
+ bool SkipCur3DFrame; |
|
| 1012 |
+ bool SkipNext2DFrame; |
|
| 1013 |
+};*/ |
|
| 1014 |
+//static FrameSkipper frameSkipper; |
|
| 1015 |
+ |
|
| 1016 |
+ |
|
| 1017 |
+/*void NDS_SkipNextFrame() {
|
|
| 1018 |
+ //if (!driver->AVI_IsRecording()) {
|
|
| 1019 |
+ //frameSkipper.RequestSkip(); |
|
| 1020 |
+ //} |
|
| 1021 |
+}*/ |
|
| 1022 |
+/*void NDS_OmitFrameSkip(int force) {
|
|
| 1023 |
+ //frameSkipper.OmitSkip(force > 0, force > 1); |
|
| 1024 |
+}*/ |
|
| 1025 |
+ |
|
| 1026 |
+//#define INDEX(i) ((((i)>>16)&0xFF0)|(((i)>>4)&0xF)) |
|
| 1027 |
+ |
|
| 1028 |
+ |
|
| 1029 |
+enum ESI_DISPCNT |
|
| 1030 |
+{
|
|
| 1031 |
+ ESI_DISPCNT_HStart, ESI_DISPCNT_HStartIRQ, ESI_DISPCNT_HDraw, ESI_DISPCNT_HBlank |
|
| 1032 |
+}; |
|
| 1033 |
+ |
|
| 1034 |
+uint64_t nds_timer; |
|
| 1035 |
+uint64_t nds_arm9_timer, nds_arm7_timer; |
|
| 1036 |
+ |
|
| 1037 |
+static const uint64_t kNever = 0xFFFFFFFFFFFFFFFFULL; |
|
| 1038 |
+ |
|
| 1039 |
+struct TSequenceItem |
|
| 1040 |
+{
|
|
| 1041 |
+ uint64_t timestamp; |
|
| 1042 |
+ uint32_t param; |
|
| 1043 |
+ bool enabled; |
|
| 1044 |
+ |
|
| 1045 |
+ /*virtual void save(EMUFILE* os) |
|
| 1046 |
+ {
|
|
| 1047 |
+ write64le(timestamp,os); |
|
| 1048 |
+ write32le(param,os); |
|
| 1049 |
+ writebool(enabled,os); |
|
| 1050 |
+ }*/ |
|
| 1051 |
+ |
|
| 1052 |
+ virtual bool load(EMUFILE* is) |
|
| 1053 |
+ {
|
|
| 1054 |
+ if(read64le(×tamp,is) != 1) return false; |
|
| 1055 |
+ if(read32le(¶m,is) != 1) return false; |
|
| 1056 |
+ if(readbool(&enabled,is) != 1) return false; |
|
| 1057 |
+ return true; |
|
| 1058 |
+ } |
|
| 1059 |
+ |
|
| 1060 |
+ inline bool isTriggered() |
|
| 1061 |
+ {
|
|
| 1062 |
+ return enabled && nds_timer >= timestamp; |
|
| 1063 |
+ } |
|
| 1064 |
+ |
|
| 1065 |
+ inline uint64_t next() |
|
| 1066 |
+ {
|
|
| 1067 |
+ return timestamp; |
|
| 1068 |
+ } |
|
| 1069 |
+}; |
|
| 1070 |
+ |
|
| 1071 |
+/*struct TSequenceItem_GXFIFO : public TSequenceItem |
|
| 1072 |
+{
|
|
| 1073 |
+ inline bool isTriggered() |
|
| 1074 |
+ {
|
|
| 1075 |
+ return enabled && nds_timer >= MMU.gfx3dCycles; |
|
| 1076 |
+ } |
|
| 1077 |
+ |
|
| 1078 |
+ inline void exec() |
|
| 1079 |
+ {
|
|
| 1080 |
+ IF_DEVELOPER(DEBUG_statistics.sequencerExecutionCounters[4]++); |
|
| 1081 |
+ while(isTriggered()) {
|
|
| 1082 |
+ enabled = false; |
|
| 1083 |
+ //gfx3d_execute3D(); |
|
| 1084 |
+ } |
|
| 1085 |
+ } |
|
| 1086 |
+ |
|
| 1087 |
+ inline uint64_t next() |
|
| 1088 |
+ {
|
|
| 1089 |
+ if(enabled) return MMU.gfx3dCycles; |
|
| 1090 |
+ else return kNever; |
|
| 1091 |
+ } |
|
| 1092 |
+};*/ |
|
| 1093 |
+ |
|
| 1094 |
+template<int procnum, int num> struct TSequenceItem_Timer : public TSequenceItem |
|
| 1095 |
+{
|
|
| 1096 |
+ inline bool isTriggered() |
|
| 1097 |
+ {
|
|
| 1098 |
+ return enabled && nds_timer >= nds.timerCycle[procnum][num]; |
|
| 1099 |
+ } |
|
| 1100 |
+ |
|
| 1101 |
+ inline void schedule() |
|
| 1102 |
+ {
|
|
| 1103 |
+ enabled = MMU.timerON[procnum][num] && MMU.timerMODE[procnum][num] != 0xFFFF; |
|
| 1104 |
+ } |
|
| 1105 |
+ |
|
| 1106 |
+ inline uint64_t next() |
|
| 1107 |
+ {
|
|
| 1108 |
+ return nds.timerCycle[procnum][num]; |
|
| 1109 |
+ } |
|
| 1110 |
+ |
|
| 1111 |
+ inline void exec() |
|
| 1112 |
+ {
|
|
| 1113 |
+ IF_DEVELOPER(DEBUG_statistics.sequencerExecutionCounters[13+procnum*4+num]++); |
|
| 1114 |
+ uint8_t* regs = procnum==0?MMU.ARM9_REG:MMU.ARM7_REG; |
|
| 1115 |
+ bool first = true, over; |
|
| 1116 |
+ //we'll need to check chained timers.. |
|
| 1117 |
+ for(int i=num;i<4;i++) |
|
| 1118 |
+ {
|
|
| 1119 |
+ //maybe too many checks if this is here, but we need it here for now |
|
| 1120 |
+ if(!MMU.timerON[procnum][i]) return; |
|
| 1121 |
+ |
|
| 1122 |
+ if(MMU.timerMODE[procnum][i] == 0xFFFF) |
|
| 1123 |
+ {
|
|
| 1124 |
+ ++(MMU.timer[procnum][i]); |
|
| 1125 |
+ over = !MMU.timer[procnum][i]; |
|
| 1126 |
+ } |
|
| 1127 |
+ else |
|
| 1128 |
+ {
|
|
| 1129 |
+ if(!first) break; //this timer isn't chained. break the chain |
|
| 1130 |
+ first = false; |
|
| 1131 |
+ |
|
| 1132 |
+ over = true; |
|
| 1133 |
+ int remain = 65536 - MMU.timerReload[procnum][i]; |
|
| 1134 |
+ int ctr=0; |
|
| 1135 |
+ while(nds.timerCycle[procnum][i] <= nds_timer) {
|
|
| 1136 |
+ nds.timerCycle[procnum][i] += (remain << MMU.timerMODE[procnum][i]); |
|
| 1137 |
+ ctr++; |
|
| 1138 |
+ } |
|
| 1139 |
+#ifndef NDEBUG |
|
| 1140 |
+ if(ctr>1) {
|
|
| 1141 |
+ printf("yikes!!!!! please report!\n");
|
|
| 1142 |
+ } |
|
| 1143 |
+#endif |
|
| 1144 |
+ } |
|
| 1145 |
+ |
|
| 1146 |
+ if(over) |
|
| 1147 |
+ {
|
|
| 1148 |
+ MMU.timer[procnum][i] = MMU.timerReload[procnum][i]; |
|
| 1149 |
+ if(T1ReadWord(regs, 0x102 + i*4) & 0x40) |
|
| 1150 |
+ {
|
|
| 1151 |
+ NDS_makeIrq(procnum, IRQ_BIT_TIMER_0 + i); |
|
| 1152 |
+ } |
|
| 1153 |
+ } |
|
| 1154 |
+ else |
|
| 1155 |
+ break; //no more chained timers to trigger. we're done here |
|
| 1156 |
+ } |
|
| 1157 |
+ } |
|
| 1158 |
+}; |
|
| 1159 |
+ |
|
| 1160 |
+template<int procnum, int chan> struct TSequenceItem_DMA : public TSequenceItem |
|
| 1161 |
+{
|
|
| 1162 |
+ DmaController* controller; |
|
| 1163 |
+ |
|
| 1164 |
+ inline bool isTriggered() |
|
| 1165 |
+ {
|
|
| 1166 |
+ return controller->dmaCheck && nds_timer>= controller->nextEvent; |
|
| 1167 |
+ } |
|
| 1168 |
+ |
|
| 1169 |
+ inline bool isEnabled() {
|
|
| 1170 |
+ return controller->dmaCheck?true:false; |
|
| 1171 |
+ } |
|
| 1172 |
+ |
|
| 1173 |
+ inline uint64_t next() |
|
| 1174 |
+ {
|
|
| 1175 |
+ return controller->nextEvent; |
|
| 1176 |
+ } |
|
| 1177 |
+ |
|
| 1178 |
+ inline void exec() |
|
| 1179 |
+ {
|
|
| 1180 |
+ IF_DEVELOPER(DEBUG_statistics.sequencerExecutionCounters[5+procnum*4+chan]++); |
|
| 1181 |
+ |
|
| 1182 |
+ //if (nds.freezeBus) return; |
|
| 1183 |
+ |
|
| 1184 |
+ //printf("exec from TSequenceItem_DMA: %d %d\n",procnum,chan);
|
|
| 1185 |
+ controller->exec(); |
|
| 1186 |
+// //give gxfifo dmas a chance to re-trigger |
|
| 1187 |
+// if(MMU.DMAStartTime[procnum][chan] == EDMAMode_GXFifo) {
|
|
| 1188 |
+// MMU.DMAing[procnum][chan] = false; |
|
| 1189 |
+// if (gxFIFO.size <= 127) |
|
| 1190 |
+// {
|
|
| 1191 |
+// execHardware_doDma(procnum,chan,EDMAMode_GXFifo); |
|
| 1192 |
+// if (MMU.DMACompleted[procnum][chan]) |
|
| 1193 |
+// goto docomplete; |
|
| 1194 |
+// else return; |
|
| 1195 |
+// } |
|
| 1196 |
+// } |
|
| 1197 |
+// |
|
| 1198 |
+//docomplete: |
|
| 1199 |
+// if (MMU.DMACompleted[procnum][chan]) |
|
| 1200 |
+// {
|
|
| 1201 |
+// uint8_t* regs = procnum==0?MMU.ARM9_REG:MMU.ARM7_REG; |
|
| 1202 |
+// |
|
| 1203 |
+// //disable the channel |
|
| 1204 |
+// if(MMU.DMAStartTime[procnum][chan] != EDMAMode_GXFifo) {
|
|
| 1205 |
+// T1WriteLong(regs, 0xB8 + (0xC*chan), T1ReadLong(regs, 0xB8 + (0xC*chan)) & 0x7FFFFFFF); |
|
| 1206 |
+// MMU.DMACrt[procnum][chan] &= 0x7FFFFFFF; //blehhh i hate this shit being mirrored in memory |
|
| 1207 |
+// } |
|
| 1208 |
+// |
|
| 1209 |
+// if((MMU.DMACrt[procnum][chan])&(1<<30)) {
|
|
| 1210 |
+// if(procnum==0) NDS_makeARM9Int(8+chan); |
|
| 1211 |
+// else NDS_makeARM7Int(8+chan); |
|
| 1212 |
+// } |
|
| 1213 |
+// |
|
| 1214 |
+// MMU.DMAing[procnum][chan] = false; |
|
| 1215 |
+// } |
|
| 1216 |
+ |
|
| 1217 |
+ } |
|
| 1218 |
+}; |
|
| 1219 |
+ |
|
| 1220 |
+struct TSequenceItem_divider : public TSequenceItem |
|
| 1221 |
+{
|
|
| 1222 |
+ inline bool isTriggered() |
|
| 1223 |
+ {
|
|
| 1224 |
+ return MMU.divRunning && nds_timer >= MMU.divCycles; |
|
| 1225 |
+ } |
|
| 1226 |
+ |
|
| 1227 |
+ bool isEnabled() { return MMU.divRunning!=0; }
|
|
| 1228 |
+ |
|
| 1229 |
+ inline uint64_t next() |
|
| 1230 |
+ {
|
|
| 1231 |
+ return MMU.divCycles; |
|
| 1232 |
+ } |
|
| 1233 |
+ |
|
| 1234 |
+ void exec() |
|
| 1235 |
+ {
|
|
| 1236 |
+ IF_DEVELOPER(DEBUG_statistics.sequencerExecutionCounters[2]++); |
|
| 1237 |
+ MMU_new.div.busy = 0; |
|
| 1238 |
+#ifdef _WIN64 |
|
| 1239 |
+ T1WriteQuad(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A0, MMU.divResult); |
|
| 1240 |
+ T1WriteQuad(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A8, MMU.divMod); |
|
| 1241 |
+#else |
|
| 1242 |
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A0, (uint32_t)MMU.divResult); |
|
| 1243 |
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A4, (uint32_t)(MMU.divResult >> 32)); |
|
| 1244 |
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A8, (uint32_t)MMU.divMod); |
|
| 1245 |
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2AC, (uint32_t)(MMU.divMod >> 32)); |
|
| 1246 |
+#endif |
|
| 1247 |
+ MMU.divRunning = false; |
|
| 1248 |
+ } |
|
| 1249 |
+ |
|
| 1250 |
+}; |
|
| 1251 |
+ |
|
| 1252 |
+struct TSequenceItem_sqrtunit : public TSequenceItem |
|
| 1253 |
+{
|
|
| 1254 |
+ inline bool isTriggered() |
|
| 1255 |
+ {
|
|
| 1256 |
+ return MMU.sqrtRunning && nds_timer >= MMU.sqrtCycles; |
|
| 1257 |
+ } |
|
| 1258 |
+ |
|
| 1259 |
+ bool isEnabled() { return MMU.sqrtRunning!=0; }
|
|
| 1260 |
+ |
|
| 1261 |
+ inline uint64_t next() |
|
| 1262 |
+ {
|
|
| 1263 |
+ return MMU.sqrtCycles; |
|
| 1264 |
+ } |
|
| 1265 |
+ |
|
| 1266 |
+ inline void exec() |
|
| 1267 |
+ {
|
|
| 1268 |
+ IF_DEVELOPER(DEBUG_statistics.sequencerExecutionCounters[3]++); |
|
| 1269 |
+ MMU_new.sqrt.busy = 0; |
|
| 1270 |
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2B4, MMU.sqrtResult); |
|
| 1271 |
+ MMU.sqrtRunning = false; |
|
| 1272 |
+ } |
|
| 1273 |
+ |
|
| 1274 |
+}; |
|
| 1275 |
+ |
|
| 1276 |
+struct Sequencer |
|
| 1277 |
+{
|
|
| 1278 |
+ bool nds_vblankEnded; |
|
| 1279 |
+ bool reschedule; |
|
| 1280 |
+ TSequenceItem dispcnt; |
|
| 1281 |
+ TSequenceItem wifi; |
|
| 1282 |
+ TSequenceItem_divider divider; |
|
| 1283 |
+ TSequenceItem_sqrtunit sqrtunit; |
|
| 1284 |
+ TSequenceItem/*_GXFIFO*/ gxfifo; |
|
| 1285 |
+ TSequenceItem_DMA<0,0> dma_0_0; TSequenceItem_DMA<0,1> dma_0_1; |
|
| 1286 |
+ TSequenceItem_DMA<0,2> dma_0_2; TSequenceItem_DMA<0,3> dma_0_3; |
|
| 1287 |
+ TSequenceItem_DMA<1,0> dma_1_0; TSequenceItem_DMA<1,1> dma_1_1; |
|
| 1288 |
+ TSequenceItem_DMA<1,2> dma_1_2; TSequenceItem_DMA<1,3> dma_1_3; |
|
| 1289 |
+ TSequenceItem_Timer<0,0> timer_0_0; TSequenceItem_Timer<0,1> timer_0_1; |
|
| 1290 |
+ TSequenceItem_Timer<0,2> timer_0_2; TSequenceItem_Timer<0,3> timer_0_3; |
|
| 1291 |
+ TSequenceItem_Timer<1,0> timer_1_0; TSequenceItem_Timer<1,1> timer_1_1; |
|
| 1292 |
+ TSequenceItem_Timer<1,2> timer_1_2; TSequenceItem_Timer<1,3> timer_1_3; |
|
| 1293 |
+ |
|
| 1294 |
+ void init(); |
|
| 1295 |
+ |
|
| 1296 |
+ void execHardware(); |
|
| 1297 |
+ uint64_t findNext(); |
|
| 1298 |
+ |
|
| 1299 |
+ /*void save(EMUFILE* os) |
|
| 1300 |
+ {
|
|
| 1301 |
+ write64le(nds_timer,os); |
|
| 1302 |
+ write64le(nds_arm9_timer,os); |
|
| 1303 |
+ write64le(nds_arm7_timer,os); |
|
| 1304 |
+ dispcnt.save(os); |
|
| 1305 |
+ divider.save(os); |
|
| 1306 |
+ sqrtunit.save(os); |
|
| 1307 |
+ gxfifo.save(os); |
|
| 1308 |
+ wifi.save(os); |
|
| 1309 |
+#define SAVE(I,X,Y) I##_##X##_##Y .save(os); |
|
| 1310 |
+ SAVE(timer,0,0); SAVE(timer,0,1); SAVE(timer,0,2); SAVE(timer,0,3); |
|
| 1311 |
+ SAVE(timer,1,0); SAVE(timer,1,1); SAVE(timer,1,2); SAVE(timer,1,3); |
|
| 1312 |
+ SAVE(dma,0,0); SAVE(dma,0,1); SAVE(dma,0,2); SAVE(dma,0,3); |
|
| 1313 |
+ SAVE(dma,1,0); SAVE(dma,1,1); SAVE(dma,1,2); SAVE(dma,1,3); |
|
| 1314 |
+#undef SAVE |
|
| 1315 |
+ }*/ |
|
| 1316 |
+ |
|
| 1317 |
+ bool load(EMUFILE* is, int version) |
|
| 1318 |
+ {
|
|
| 1319 |
+ if(read64le(&nds_timer,is) != 1) return false; |
|
| 1320 |
+ if(read64le(&nds_arm9_timer,is) != 1) return false; |
|
| 1321 |
+ if(read64le(&nds_arm7_timer,is) != 1) return false; |
|
| 1322 |
+ if(!dispcnt.load(is)) return false; |
|
| 1323 |
+ if(!divider.load(is)) return false; |
|
| 1324 |
+ if(!sqrtunit.load(is)) return false; |
|
| 1325 |
+ if(!gxfifo.load(is)) return false; |
|
| 1326 |
+ if(version >= 1) if(!wifi.load(is)) return false; |
|
| 1327 |
+#define LOAD(I,X,Y) if(!I##_##X##_##Y .load(is)) return false; |
|
| 1328 |
+ LOAD(timer,0,0); LOAD(timer,0,1); LOAD(timer,0,2); LOAD(timer,0,3); |
|
| 1329 |
+ LOAD(timer,1,0); LOAD(timer,1,1); LOAD(timer,1,2); LOAD(timer,1,3); |
|
| 1330 |
+ LOAD(dma,0,0); LOAD(dma,0,1); LOAD(dma,0,2); LOAD(dma,0,3); |
|
| 1331 |
+ LOAD(dma,1,0); LOAD(dma,1,1); LOAD(dma,1,2); LOAD(dma,1,3); |
|
| 1332 |
+#undef LOAD |
|
| 1333 |
+ |
|
| 1334 |
+ return true; |
|
| 1335 |
+ } |
|
| 1336 |
+ |
|
| 1337 |
+} sequencer; |
|
| 1338 |
+ |
|
| 1339 |
+/*void NDS_RescheduleGXFIFO(uint32_t cost) |
|
| 1340 |
+{
|
|
| 1341 |
+ //if(!sequencer.gxfifo.enabled) {
|
|
| 1342 |
+ //MMU.gfx3dCycles = nds_timer; |
|
| 1343 |
+ //sequencer.gxfifo.enabled = true; |
|
| 1344 |
+ //} |
|
| 1345 |
+ //MMU.gfx3dCycles += cost; |
|
| 1346 |
+ NDS_Reschedule(); |
|
| 1347 |
+}*/ |
|
| 1348 |
+ |
|
| 1349 |
+void NDS_RescheduleTimers() |
|
| 1350 |
+{
|
|
| 1351 |
+#define check(X,Y) sequencer.timer_##X##_##Y .schedule(); |
|
| 1352 |
+ check(0,0); check(0,1); check(0,2); check(0,3); |
|
| 1353 |
+ check(1,0); check(1,1); check(1,2); check(1,3); |
|
| 1354 |
+#undef check |
|
| 1355 |
+ |
|
| 1356 |
+ NDS_Reschedule(); |
|
| 1357 |
+} |
|
| 1358 |
+ |
|
| 1359 |
+void NDS_RescheduleDMA() |
|
| 1360 |
+{
|
|
| 1361 |
+ //TBD |
|
| 1362 |
+ NDS_Reschedule(); |
|
| 1363 |
+ |
|
| 1364 |
+} |
|
| 1365 |
+ |
|
| 1366 |
+static void initSchedule() |
|
| 1367 |
+{
|
|
| 1368 |
+ sequencer.init(); |
|
| 1369 |
+ |
|
| 1370 |
+ //begin at the very end of the last scanline |
|
| 1371 |
+ //so that at t=0 we can increment to scanline=0 |
|
| 1372 |
+ nds.VCount = 262; |
|
| 1373 |
+ |
|
| 1374 |
+ sequencer.nds_vblankEnded = false; |
|
| 1375 |
+} |
|
| 1376 |
+ |
|
| 1377 |
+ |
|
| 1378 |
+// 2196372 ~= (ARM7_CLOCK << 16) / 1000000 |
|
| 1379 |
+// This value makes more sense to me, because: |
|
| 1380 |
+// ARM7_CLOCK = 33.51 mhz |
|
| 1381 |
+// = 33513982 cycles per second |
|
| 1382 |
+// = 33.513982 cycles per microsecond |
|
| 1383 |
+//const uint64_t kWifiCycles = 34*2; |
|
| 1384 |
+//(this isn't very precise. I don't think it needs to be) |
|
| 1385 |
+ |
|
| 1386 |
+void Sequencer::init() |
|
| 1387 |
+{
|
|
| 1388 |
+ NDS_RescheduleTimers(); |
|
| 1389 |
+ NDS_RescheduleDMA(); |
|
| 1390 |
+ |
|
| 1391 |
+ reschedule = false; |
|
| 1392 |
+ nds_timer = 0; |
|
| 1393 |
+ nds_arm9_timer = 0; |
|
| 1394 |
+ nds_arm7_timer = 0; |
|
| 1395 |
+ |
|
| 1396 |
+ dispcnt.enabled = true; |
|
| 1397 |
+ dispcnt.param = ESI_DISPCNT_HStart; |
|
| 1398 |
+ dispcnt.timestamp = 0; |
|
| 1399 |
+ |
|
| 1400 |
+ //gxfifo.enabled = false; |
|
| 1401 |
+ |
|
| 1402 |
+ dma_0_0.controller = &MMU_new.dma[0][0]; |
|
| 1403 |
+ dma_0_1.controller = &MMU_new.dma[0][1]; |
|
| 1404 |
+ dma_0_2.controller = &MMU_new.dma[0][2]; |
|
| 1405 |
+ dma_0_3.controller = &MMU_new.dma[0][3]; |
|
| 1406 |
+ dma_1_0.controller = &MMU_new.dma[1][0]; |
|
| 1407 |
+ dma_1_1.controller = &MMU_new.dma[1][1]; |
|
| 1408 |
+ dma_1_2.controller = &MMU_new.dma[1][2]; |
|
| 1409 |
+ dma_1_3.controller = &MMU_new.dma[1][3]; |
|
| 1410 |
+ |
|
| 1411 |
+ |
|
| 1412 |
+ /*#ifdef EXPERIMENTAL_WIFI_COMM |
|
| 1413 |
+ wifi.enabled = true; |
|
| 1414 |
+ wifi.timestamp = kWifiCycles; |
|
| 1415 |
+ #else |
|
| 1416 |
+ wifi.enabled = false; |
|
| 1417 |
+ #endif*/ |
|
| 1418 |
+} |
|
| 1419 |
+ |
|
| 1420 |
+//this isnt helping much right now. work on it later |
|
| 1421 |
+//#include "utils/task.h" |
|
| 1422 |
+//Task taskSubGpu(true); |
|
| 1423 |
+//void* renderSubScreen(void*) |
|
| 1424 |
+//{
|
|
| 1425 |
+// GPU_RenderLine(&SubScreen, nds.VCount, SkipCur2DFrame); |
|
| 1426 |
+// return NULL; |
|
| 1427 |
+//} |
|
| 1428 |
+ |
|
| 1429 |
+static void execHardware_hblank() |
|
| 1430 |
+{
|
|
| 1431 |
+ //this logic keeps moving around. |
|
| 1432 |
+ //now, we try and give the game as much time as possible to finish doing its work for the scanline, |
|
| 1433 |
+ //by drawing scanline N at the end of drawing time (but before subsequent interrupt or hdma-driven events happen) |
|
| 1434 |
+ //don't try to do this at the end of the scanline, because some games (sonic classics) may use hblank IRQ to set |
|
| 1435 |
+ //scroll regs for the next scanline |
|
| 1436 |
+ if(nds.VCount<192) |
|
| 1437 |
+ {
|
|
| 1438 |
+ //taskSubGpu.execute(renderSubScreen,NULL); |
|
| 1439 |
+ //GPU_RenderLine(&MainScreen, nds.VCount, frameSkipper.ShouldSkip2D()); |
|
| 1440 |
+ //GPU_RenderLine(&SubScreen, nds.VCount, frameSkipper.ShouldSkip2D()); |
|
| 1441 |
+ //taskSubGpu.finish(); |
|
| 1442 |
+ |
|
| 1443 |
+ //trigger hblank dmas |
|
| 1444 |
+ //but notice, we do that just after we finished drawing the line |
|
| 1445 |
+ //(values copied by this hdma should not be used until the next scanline) |
|
| 1446 |
+ triggerDma(EDMAMode_HBlank); |
|
| 1447 |
+ } |
|
| 1448 |
+ |
|
| 1449 |
+ if(nds.VCount==262) |
|
| 1450 |
+ {
|
|
| 1451 |
+ //we need to trigger one last hblank dma since |
|
| 1452 |
+ //a. we're sort of lagged behind by one scanline |
|
| 1453 |
+ //b. i think that 193 hblanks actually fire (one for the hblank in scanline 262) |
|
| 1454 |
+ //this is demonstrated by NSMB splot-parallaxing clouds |
|
| 1455 |
+ //for some reason the game will setup two hdma scroll register buffers |
|
| 1456 |
+ //to be run consecutively, and unless we do this, the second buffer will be offset by one scanline |
|
| 1457 |
+ //causing a glitch in the 0th scanline |
|
| 1458 |
+ //triggerDma(EDMAMode_HBlank); |
|
| 1459 |
+ |
|
| 1460 |
+ //BUT! this was removed in order to make glitches in megaman zero collection (mmz 4 1st level) work. |
|
| 1461 |
+ //and, it seems that it is no longer necessary in nsmb. perhaps something else fixed it |
|
| 1462 |
+ } |
|
| 1463 |
+ |
|
| 1464 |
+ |
|
| 1465 |
+ //turn on hblank status bit |
|
| 1466 |
+ T1WriteWord(MMU.ARM9_REG, 4, T1ReadWord(MMU.ARM9_REG, 4) | 2); |
|
| 1467 |
+ T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) | 2); |
|
| 1468 |
+ |
|
| 1469 |
+ //fire hblank interrupts if necessary |
|
| 1470 |
+ if(T1ReadWord(MMU.ARM9_REG, 4) & 0x10) NDS_makeIrq(ARMCPU_ARM9,IRQ_BIT_LCD_HBLANK); |
|
| 1471 |
+ if(T1ReadWord(MMU.ARM7_REG, 4) & 0x10) NDS_makeIrq(ARMCPU_ARM7,IRQ_BIT_LCD_HBLANK); |
|
| 1472 |
+ |
|
| 1473 |
+ //emulation housekeeping. for some reason we always do this at hblank, |
|
| 1474 |
+ //even though it sounds more reasonable to do it at hstart |
|
| 1475 |
+ SPU_Emulate_core(); |
|
| 1476 |
+ //driver->AVI_SoundUpdate(SPU_core->outbuf,spu_core_samples); |
|
| 1477 |
+ //WAV_WavSoundUpdate(SPU_core->outbuf,spu_core_samples); |
|
| 1478 |
+} |
|
| 1479 |
+ |
|
| 1480 |
+static void execHardware_hstart_vblankEnd() |
|
| 1481 |
+{
|
|
| 1482 |
+ sequencer.nds_vblankEnded = true; |
|
| 1483 |
+ sequencer.reschedule = true; |
|
| 1484 |
+ |
|
| 1485 |
+ //turn off vblank status bit |
|
| 1486 |
+ T1WriteWord(MMU.ARM9_REG, 4, T1ReadWord(MMU.ARM9_REG, 4) & ~1); |
|
| 1487 |
+ T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) & ~1); |
|
| 1488 |
+ |
|
| 1489 |
+ //some emulation housekeeping |
|
| 1490 |
+ //frameSkipper.Advance(); |
|
| 1491 |
+} |
|
| 1492 |
+ |
|
| 1493 |
+static void execHardware_hstart_vblankStart() |
|
| 1494 |
+{
|
|
| 1495 |
+ //printf("--------VBLANK!!!--------\n");
|
|
| 1496 |
+ |
|
| 1497 |
+ //fire vblank interrupts if necessary |
|
| 1498 |
+ for(int i=0;i<2;i++) |
|
| 1499 |
+ if(MMU.reg_IF_pending[i] & (1<<IRQ_BIT_LCD_VBLANK)) |
|
| 1500 |
+ {
|
|
| 1501 |
+ MMU.reg_IF_pending[i] &= ~(1<<IRQ_BIT_LCD_VBLANK); |
|
| 1502 |
+ NDS_makeIrq(i,IRQ_BIT_LCD_VBLANK); |
|
| 1503 |
+ } |
|
| 1504 |
+ |
|
| 1505 |
+ //trigger vblank dmas |
|
| 1506 |
+ triggerDma(EDMAMode_VBlank); |
|
| 1507 |
+ |
|
| 1508 |
+ //tracking for arm9 load average |
|
| 1509 |
+ //nds.runCycleCollector[0][nds.idleFrameCounter] = 1120380-nds.idleCycles[0]; |
|
| 1510 |
+ //nds.runCycleCollector[1][nds.idleFrameCounter] = 1120380-nds.idleCycles[1]; |
|
| 1511 |
+ //nds.idleFrameCounter++; |
|
| 1512 |
+ //nds.idleFrameCounter &= 15; |
|
| 1513 |
+ //nds.idleCycles[0] = 0; |
|
| 1514 |
+ //nds.idleCycles[1] = 0; |
|
| 1515 |
+} |
|
| 1516 |
+ |
|
| 1517 |
+static uint16_t execHardware_gen_vmatch_goal() |
|
| 1518 |
+{
|
|
| 1519 |
+ uint16_t vmatch = T1ReadWord(MMU.ARM9_REG, 4); |
|
| 1520 |
+ vmatch = ((vmatch>>8)|((vmatch<<1)&(1<<8))); |
|
| 1521 |
+ return vmatch; |
|
| 1522 |
+} |
|
| 1523 |
+ |
|
| 1524 |
+static void execHardware_hstart_vcount_irq() |
|
| 1525 |
+{
|
|
| 1526 |
+ //trigger pending VMATCH irqs |
|
| 1527 |
+ if(MMU.reg_IF_pending[ARMCPU_ARM9] & (1<<IRQ_BIT_LCD_VMATCH)) |
|
| 1528 |
+ {
|
|
| 1529 |
+ MMU.reg_IF_pending[ARMCPU_ARM9] &= ~(1<<IRQ_BIT_LCD_VMATCH); |
|
| 1530 |
+ NDS_makeIrq(ARMCPU_ARM9,IRQ_BIT_LCD_VMATCH); |
|
| 1531 |
+ } |
|
| 1532 |
+ if(MMU.reg_IF_pending[ARMCPU_ARM7] & (1<<IRQ_BIT_LCD_VMATCH)) |
|
| 1533 |
+ {
|
|
| 1534 |
+ MMU.reg_IF_pending[ARMCPU_ARM7] &= ~(1<<IRQ_BIT_LCD_VMATCH); |
|
| 1535 |
+ NDS_makeIrq(ARMCPU_ARM7,IRQ_BIT_LCD_VMATCH); |
|
| 1536 |
+ } |
|
| 1537 |
+} |
|
| 1538 |
+ |
|
| 1539 |
+static void execHardware_hstart_vcount() |
|
| 1540 |
+{
|
|
| 1541 |
+ uint16_t vmatch = execHardware_gen_vmatch_goal(); |
|
| 1542 |
+ if(nds.VCount==vmatch) |
|
| 1543 |
+ {
|
|
| 1544 |
+ //arm9 vmatch |
|
| 1545 |
+ T1WriteWord(MMU.ARM9_REG, 4, T1ReadWord(MMU.ARM9_REG, 4) | 4); |
|
| 1546 |
+ if(T1ReadWord(MMU.ARM9_REG, 4) & 32) {
|
|
| 1547 |
+ MMU.reg_IF_pending[ARMCPU_ARM9] |= (1<<IRQ_BIT_LCD_VMATCH); |
|
| 1548 |
+ } |
|
| 1549 |
+ } |
|
| 1550 |
+ else |
|
| 1551 |
+ T1WriteWord(MMU.ARM9_REG, 4, T1ReadWord(MMU.ARM9_REG, 4) & 0xFFFB); |
|
| 1552 |
+ |
|
| 1553 |
+ vmatch = T1ReadWord(MMU.ARM7_REG, 4); |
|
| 1554 |
+ vmatch = ((vmatch>>8)|((vmatch<<1)&(1<<8))); |
|
| 1555 |
+ if(nds.VCount==vmatch) |
|
| 1556 |
+ {
|
|
| 1557 |
+ //arm7 vmatch |
|
| 1558 |
+ T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) | 4); |
|
| 1559 |
+ if(T1ReadWord(MMU.ARM7_REG, 4) & 32) |
|
| 1560 |
+ MMU.reg_IF_pending[ARMCPU_ARM7] |= (1<<IRQ_BIT_LCD_VMATCH); |
|
| 1561 |
+ } |
|
| 1562 |
+ else |
|
| 1563 |
+ T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) & 0xFFFB); |
|
| 1564 |
+} |
|
| 1565 |
+ |
|
| 1566 |
+static void execHardware_hdraw() |
|
| 1567 |
+{
|
|
| 1568 |
+ //due to hacks in our selection of rendering time, we do not actually render here as intended. |
|
| 1569 |
+ //consider changing this if there is some problem with raster fx timing but check the documentation near the gpu rendering calls |
|
| 1570 |
+ //to make sure you check for regressions (nsmb, sonic classics, et al) |
|
| 1571 |
+} |
|
| 1572 |
+ |
|
| 1573 |
+static void execHardware_hstart_irq() |
|
| 1574 |
+{
|
|
| 1575 |
+ //this function very soon after the registers get updated to trigger IRQs |
|
| 1576 |
+ //this is necessary to fix "egokoro kyoushitsu" which idles waiting for vcount=192, which never happens due to a long vblank irq |
|
| 1577 |
+ //100% accurate emulation would require the read of VCOUNT to be in the pipeline already with the irq coming in behind it, thus |
|
| 1578 |
+ //allowing the vcount to register as 192 occasionally (maybe about 1 out of 28 frames) |
|
| 1579 |
+ //the actual length of the delay is in execHardware() where the events are scheduled |
|
| 1580 |
+ sequencer.reschedule = true; |
|
| 1581 |
+ if(nds.VCount==192) |
|
| 1582 |
+ {
|
|
| 1583 |
+ //when the vcount hits 192, vblank begins |
|
| 1584 |
+ execHardware_hstart_vblankStart(); |
|
| 1585 |
+ } |
|
| 1586 |
+ |
|
| 1587 |
+ execHardware_hstart_vcount_irq(); |
|
| 1588 |
+} |
|
| 1589 |
+ |
|
| 1590 |
+static void execHardware_hstart() |
|
| 1591 |
+{
|
|
| 1592 |
+ nds.VCount++; |
|
| 1593 |
+ |
|
| 1594 |
+ //end of 3d vblank |
|
| 1595 |
+ //this should be 214, but we are going to be generous for games with tight timing |
|
| 1596 |
+ //they shouldnt be changing any textures at 262 but they might accidentally still be at 214 |
|
| 1597 |
+ //so.. |
|
| 1598 |
+ /*if((CommonSettings.rigorous_timing && nds.VCount==214) || (!CommonSettings.rigorous_timing && nds.VCount==262)) |
|
| 1599 |
+ {
|
|
| 1600 |
+ gfx3d_VBlankEndSignal(frameSkipper.ShouldSkip3D()); |
|
| 1601 |
+ }*/ |
|
| 1602 |
+ |
|
| 1603 |
+ if(nds.VCount==263) |
|
| 1604 |
+ {
|
|
| 1605 |
+ //when the vcount hits 263 it rolls over to 0 |
|
| 1606 |
+ nds.VCount=0; |
|
| 1607 |
+ } |
|
| 1608 |
+ if(nds.VCount==262) |
|
| 1609 |
+ {
|
|
| 1610 |
+ //when the vcount hits 262, vblank ends (oam pre-renders by one scanline) |
|
| 1611 |
+ execHardware_hstart_vblankEnd(); |
|
| 1612 |
+ } |
|
| 1613 |
+ /*else if(nds.VCount==191) |
|
| 1614 |
+ {
|
|
| 1615 |
+ //when the vcount hits 191, the 3d vblank occurs (maybe because OAM doesnt need to run anymore, so we can power it down, and give the 3d as much time as possible?) |
|
| 1616 |
+ gfx3d_VBlankSignal(); |
|
| 1617 |
+ }*/ |
|
| 1618 |
+ else if(nds.VCount==192) |
|
| 1619 |
+ {
|
|
| 1620 |
+ //turn on vblank status bit |
|
| 1621 |
+ T1WriteWord(MMU.ARM9_REG, 4, T1ReadWord(MMU.ARM9_REG, 4) | 1); |
|
| 1622 |
+ T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) | 1); |
|
| 1623 |
+ |
|
| 1624 |
+ //check whether we'll need to fire vblank irqs |
|
| 1625 |
+ if(T1ReadWord(MMU.ARM9_REG, 4) & 0x8) MMU.reg_IF_pending[ARMCPU_ARM9] |= (1<<IRQ_BIT_LCD_VBLANK); |
|
| 1626 |
+ if(T1ReadWord(MMU.ARM7_REG, 4) & 0x8) MMU.reg_IF_pending[ARMCPU_ARM7] |= (1<<IRQ_BIT_LCD_VBLANK); |
|
| 1627 |
+ } |
|
| 1628 |
+ |
|
| 1629 |
+ //write the new vcount |
|
| 1630 |
+ T1WriteWord(MMU.ARM9_REG, 6, static_cast<uint16_t>(nds.VCount)); |
|
| 1631 |
+ T1WriteWord(MMU.ARM9_REG, 0x1006, static_cast<uint16_t>(nds.VCount)); |
|
| 1632 |
+ T1WriteWord(MMU.ARM7_REG, 6, static_cast<uint16_t>(nds.VCount)); |
|
| 1633 |
+ T1WriteWord(MMU.ARM7_REG, 0x1006, static_cast<uint16_t>(nds.VCount)); |
|
| 1634 |
+ |
|
| 1635 |
+ //turn off hblank status bit |
|
| 1636 |
+ T1WriteWord(MMU.ARM9_REG, 4, T1ReadWord(MMU.ARM9_REG, 4) & 0xFFFD); |
|
| 1637 |
+ T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) & 0xFFFD); |
|
| 1638 |
+ |
|
| 1639 |
+ //handle vcount status |
|
| 1640 |
+ execHardware_hstart_vcount(); |
|
| 1641 |
+ |
|
| 1642 |
+ //trigger hstart dmas |
|
| 1643 |
+ triggerDma(EDMAMode_HStart); |
|
| 1644 |
+ |
|
| 1645 |
+ if(nds.VCount<192) |
|
| 1646 |
+ {
|
|
| 1647 |
+ //this is hacky. |
|
| 1648 |
+ //there is a corresponding hack in doDMA. |
|
| 1649 |
+ //it should be driven by a fifo (and generate just in time as the scanline is displayed) |
|
| 1650 |
+ //but that isnt even possible until we have some sort of sub-scanline timing. |
|
| 1651 |
+ //it may not be necessary. |
|
| 1652 |
+ triggerDma(EDMAMode_MemDisplay); |
|
| 1653 |
+ } |
|
| 1654 |
+} |
|
| 1655 |
+ |
|
| 1656 |
+void NDS_Reschedule() |
|
| 1657 |
+{
|
|
| 1658 |
+ IF_DEVELOPER(if(!sequencer.reschedule) DEBUG_statistics.sequencerExecutionCounters[0]++;); |
|
| 1659 |
+ sequencer.reschedule = true; |
|
| 1660 |
+} |
|
| 1661 |
+ |
|
| 1662 |
+/*inline uint32_t _fast_min32(uint32_t a, uint32_t b, uint32_t c, uint32_t d) |
|
| 1663 |
+{
|
|
| 1664 |
+ return (( ((int32_t)(a-b)) >> (32-1)) & (c^d)) ^ d; |
|
| 1665 |
+}*/ |
|
| 1666 |
+ |
|
| 1667 |
+inline uint64_t _fast_min(uint64_t a, uint64_t b) |
|
| 1668 |
+{
|
|
| 1669 |
+ //you might find that this is faster on a 64bit system; someone should try it |
|
| 1670 |
+ //http://aggregate.org/MAGIC/#Integer%20Selection |
|
| 1671 |
+ //uint64_t ret = (((((s64)(a-b)) >> (64-1)) & (a^b)) ^ b); |
|
| 1672 |
+ //assert(ret==min(a,b)); |
|
| 1673 |
+ //return ret; |
|
| 1674 |
+ |
|
| 1675 |
+ //but this ends up being the fastest on 32bits |
|
| 1676 |
+ return a<b?a:b; |
|
| 1677 |
+ |
|
| 1678 |
+ //just for the record, I tried to do the 64bit math on a 32bit proc |
|
| 1679 |
+ //using sse2 and it was really slow |
|
| 1680 |
+ //__m128i __a; __a.m128i_u64[0] = a; |
|
| 1681 |
+ //__m128i __b; __b.m128i_u64[0] = b; |
|
| 1682 |
+ //__m128i xorval = _mm_xor_si128(__a,__b); |
|
| 1683 |
+ //__m128i temp = _mm_sub_epi64(__a,__b); |
|
| 1684 |
+ //temp.m128i_i64[0] >>= 63; //no 64bit shra in sse2, what a disappointment |
|
| 1685 |
+ //temp = _mm_and_si128(temp,xorval); |
|
| 1686 |
+ //temp = _mm_xor_si128(temp,__b); |
|
| 1687 |
+ //return temp.m128i_u64[0]; |
|
| 1688 |
+} |
|
| 1689 |
+ |
|
| 1690 |
+ |
|
| 1691 |
+ |
|
| 1692 |
+uint64_t Sequencer::findNext() |
|
| 1693 |
+{
|
|
| 1694 |
+ //this one is always enabled so dont bother to check it |
|
| 1695 |
+ uint64_t next = dispcnt.next(); |
|
| 1696 |
+ |
|
| 1697 |
+ if(divider.isEnabled()) next = _fast_min(next,divider.next()); |
|
| 1698 |
+ if(sqrtunit.isEnabled()) next = _fast_min(next,sqrtunit.next()); |
|
| 1699 |
+ //if(gxfifo.enabled) next = _fast_min(next,gxfifo.next()); |
|
| 1700 |
+ |
|
| 1701 |
+#ifdef EXPERIMENTAL_WIFI_COMM |
|
| 1702 |
+ next = _fast_min(next,wifi.next()); |
|
| 1703 |
+#endif |
|
| 1704 |
+ |
|
| 1705 |
+#define test(X,Y) if(dma_##X##_##Y .isEnabled()) next = _fast_min(next,dma_##X##_##Y .next()); |
|
| 1706 |
+ test(0,0); test(0,1); test(0,2); test(0,3); |
|
| 1707 |
+ test(1,0); test(1,1); test(1,2); test(1,3); |
|
| 1708 |
+#undef test |
|
| 1709 |
+#define test(X,Y) if(timer_##X##_##Y .enabled) next = _fast_min(next,timer_##X##_##Y .next()); |
|
| 1710 |
+ test(0,0); test(0,1); test(0,2); test(0,3); |
|
| 1711 |
+ test(1,0); test(1,1); test(1,2); test(1,3); |
|
| 1712 |
+#undef test |
|
| 1713 |
+ |
|
| 1714 |
+ return next; |
|
| 1715 |
+} |
|
| 1716 |
+ |
|
| 1717 |
+void Sequencer::execHardware() |
|
| 1718 |
+{
|
|
| 1719 |
+ if(dispcnt.isTriggered()) |
|
| 1720 |
+ {
|
|
| 1721 |
+ |
|
| 1722 |
+ IF_DEVELOPER(DEBUG_statistics.sequencerExecutionCounters[1]++); |
|
| 1723 |
+ |
|
| 1724 |
+ switch(dispcnt.param) |
|
| 1725 |
+ {
|
|
| 1726 |
+ case ESI_DISPCNT_HStart: |
|
| 1727 |
+ execHardware_hstart(); |
|
| 1728 |
+ //(used to be 3168) |
|
| 1729 |
+ //hstart is actually 8 dots before the visible drawing begins |
|
| 1730 |
+ //we're going to run 1 here and then run 7 in the next case |
|
| 1731 |
+ dispcnt.timestamp += 1*6*2; |
|
| 1732 |
+ dispcnt.param = ESI_DISPCNT_HStartIRQ; |
|
| 1733 |
+ break; |
|
| 1734 |
+ case ESI_DISPCNT_HStartIRQ: |
|
| 1735 |
+ execHardware_hstart_irq(); |
|
| 1736 |
+ dispcnt.timestamp += 7*6*2; |
|
| 1737 |
+ dispcnt.param = ESI_DISPCNT_HDraw; |
|
| 1738 |
+ break; |
|
| 1739 |
+ |
|
| 1740 |
+ case ESI_DISPCNT_HDraw: |
|
| 1741 |
+ execHardware_hdraw(); |
|
| 1742 |
+ //duration of non-blanking period is ~1606 clocks (gbatek agrees) [but says its different on arm7] |
|
| 1743 |
+ //im gonna call this 267 dots = 267*6=1602 |
|
| 1744 |
+ //so, this event lasts 267 dots minus the 8 dot preroll |
|
| 1745 |
+ dispcnt.timestamp += (267-8)*6*2; |
|
| 1746 |
+ dispcnt.param = ESI_DISPCNT_HBlank; |
|
| 1747 |
+ break; |
|
| 1748 |
+ |
|
| 1749 |
+ case ESI_DISPCNT_HBlank: |
|
| 1750 |
+ execHardware_hblank(); |
|
| 1751 |
+ //(once this was 1092 or 1092/12=91 dots.) |
|
| 1752 |
+ //there are surely 355 dots per scanline, less 267 for non-blanking period. the rest is hblank and then after that is hstart |
|
| 1753 |
+ dispcnt.timestamp += (355-267)*6*2; |
|
| 1754 |
+ dispcnt.param = ESI_DISPCNT_HStart; |
|
| 1755 |
+ break; |
|
| 1756 |
+ } |
|
| 1757 |
+ } |
|
| 1758 |
+ |
|
| 1759 |
+#ifdef EXPERIMENTAL_WIFI_COMM |
|
| 1760 |
+ if(wifi.isTriggered()) |
|
| 1761 |
+ {
|
|
| 1762 |
+ WIFI_usTrigger(); |
|
| 1763 |
+ wifi.timestamp += kWifiCycles; |
|
| 1764 |
+ } |
|
| 1765 |
+#endif |
|
| 1766 |
+ |
|
| 1767 |
+ if(divider.isTriggered()) divider.exec(); |
|
| 1768 |
+ if(sqrtunit.isTriggered()) sqrtunit.exec(); |
|
| 1769 |
+ //if(gxfifo.isTriggered()) gxfifo.exec(); |
|
| 1770 |
+ |
|
| 1771 |
+ |
|
| 1772 |
+#define test(X,Y) if(dma_##X##_##Y .isTriggered()) dma_##X##_##Y .exec(); |
|
| 1773 |
+ test(0,0); test(0,1); test(0,2); test(0,3); |
|
| 1774 |
+ test(1,0); test(1,1); test(1,2); test(1,3); |
|
| 1775 |
+#undef test |
|
| 1776 |
+#define test(X,Y) if(timer_##X##_##Y .enabled) if(timer_##X##_##Y .isTriggered()) timer_##X##_##Y .exec(); |
|
| 1777 |
+ test(0,0); test(0,1); test(0,2); test(0,3); |
|
| 1778 |
+ test(1,0); test(1,1); test(1,2); test(1,3); |
|
| 1779 |
+#undef test |
|
| 1780 |
+} |
|
| 1781 |
+ |
|
| 1782 |
+void execHardware_interrupts(); |
|
| 1783 |
+ |
|
| 1784 |
+//static void saveUserInput(EMUFILE* os); |
|
| 1785 |
+static bool loadUserInput(EMUFILE* is, int version); |
|
| 1786 |
+ |
|
| 1787 |
+/*void nds_savestate(EMUFILE* os) |
|
| 1788 |
+{
|
|
| 1789 |
+ //version |
|
| 1790 |
+ write32le(3,os); |
|
| 1791 |
+ |
|
| 1792 |
+ //sequencer.save(os); |
|
| 1793 |
+ |
|
| 1794 |
+ saveUserInput(os); |
|
| 1795 |
+ |
|
| 1796 |
+ write32le(LidClosed,os); |
|
| 1797 |
+ write8le(countLid,os); |
|
| 1798 |
+}*/ |
|
| 1799 |
+ |
|
| 1800 |
+bool nds_loadstate(EMUFILE* is, int) |
|
| 1801 |
+{
|
|
| 1802 |
+ // this isn't part of the savestate loading logic, but |
|
| 1803 |
+ // don't skip the next frame after loading a savestate |
|
| 1804 |
+ //frameSkipper.OmitSkip(true, true); |
|
| 1805 |
+ |
|
| 1806 |
+ //read version |
|
| 1807 |
+ uint32_t version; |
|
| 1808 |
+ if(read32le(&version,is) != 1) return false; |
|
| 1809 |
+ |
|
| 1810 |
+ if(version > 3) return false; |
|
| 1811 |
+ |
|
| 1812 |
+ bool temp = true; |
|
| 1813 |
+ temp &= sequencer.load(is, version); |
|
| 1814 |
+ if(version <= 1 || !temp) return temp; |
|
| 1815 |
+ temp &= loadUserInput(is, version); |
|
| 1816 |
+ |
|
| 1817 |
+ if(version < 3) return temp; |
|
| 1818 |
+ |
|
| 1819 |
+ uint32_t tmpu32; |
|
| 1820 |
+ read32le(&tmpu32,is); |
|
| 1821 |
+ uint8_t tmpu8; |
|
| 1822 |
+ read8le(&tmpu8,is); |
|
| 1823 |
+ |
|
| 1824 |
+ return temp; |
|
| 1825 |
+} |
|
| 1826 |
+ |
|
| 1827 |
+/*inline void arm9log() |
|
| 1828 |
+{
|
|
| 1829 |
+#ifdef LOG_ARM9 |
|
| 1830 |
+ if(dolog) |
|
| 1831 |
+ {
|
|
| 1832 |
+ char dasmbuf[4096]; |
|
| 1833 |
+ if(NDS_ARM9.CPSR.bits.T) |
|
| 1834 |
+ des_thumb_instructions_set[((NDS_ARM9.instruction)>>6)&1023](NDS_ARM9.instruct_adr, NDS_ARM9.instruction, dasmbuf); |
|
| 1835 |
+ else |
|
| 1836 |
+ des_arm_instructions_set[INDEX(NDS_ARM9.instruction)](NDS_ARM9.instruct_adr, NDS_ARM9.instruction, dasmbuf); |
|
| 1837 |
+ |
|
| 1838 |
+#ifdef LOG_TO_FILE |
|
| 1839 |
+ if (!fp_dis9) return; |
|
| 1840 |
+#ifdef LOG_TO_FILE_REGS |
|
| 1841 |
+ fprintf(fp_dis9, "\t\t;R0:%08X R1:%08X R2:%08X R3:%08X R4:%08X R5:%08X R6:%08X R7:%08X R8:%08X R9:%08X\n\t\t;R10:%08X R11:%08X R12:%08X R13:%08X R14:%08X R15:%08X| next %08X, N:%i Z:%i C:%i V:%i\n", |
|
| 1842 |
+ NDS_ARM9.R[0], NDS_ARM9.R[1], NDS_ARM9.R[2], NDS_ARM9.R[3], NDS_ARM9.R[4], NDS_ARM9.R[5], NDS_ARM9.R[6], NDS_ARM9.R[7], |
|
| 1843 |
+ NDS_ARM9.R[8], NDS_ARM9.R[9], NDS_ARM9.R[10], NDS_ARM9.R[11], NDS_ARM9.R[12], NDS_ARM9.R[13], NDS_ARM9.R[14], NDS_ARM9.R[15], |
|
| 1844 |
+ NDS_ARM9.next_instruction, NDS_ARM9.CPSR.bits.N, NDS_ARM9.CPSR.bits.Z, NDS_ARM9.CPSR.bits.C, NDS_ARM9.CPSR.bits.V); |
|
| 1845 |
+#endif |
|
| 1846 |
+ fprintf(fp_dis9, "%s %08X\t%08X \t%s\n", NDS_ARM9.CPSR.bits.T?"THUMB":"ARM", NDS_ARM9.instruct_adr, NDS_ARM9.instruction, dasmbuf);*/ |
|
| 1847 |
+ /*if (NDS_ARM9.instruction == 0) |
|
| 1848 |
+ {
|
|
| 1849 |
+ dolog = false; |
|
| 1850 |
+ INFO("Disassembler is stopped\n");
|
|
| 1851 |
+ }*/ |
|
| 1852 |
+/*#else |
|
| 1853 |
+ printf("%05d:%03d %12lld 9:%08X %08X %-30s R00:%08X R01:%08X R02:%08X R03:%08X R04:%08X R05:%08X R06:%08X R07:%08X R08:%08X R09:%08X R10:%08X R11:%08X R12:%08X R13:%08X R14:%08X R15:%08X\n",
|
|
| 1854 |
+ currFrameCounter, nds.VCount, nds_timer, |
|
| 1855 |
+ NDS_ARM9.instruct_adr,NDS_ARM9.instruction, dasmbuf, |
|
| 1856 |
+ NDS_ARM9.R[0], NDS_ARM9.R[1], NDS_ARM9.R[2], NDS_ARM9.R[3], NDS_ARM9.R[4], NDS_ARM9.R[5], NDS_ARM9.R[6], NDS_ARM9.R[7], |
|
| 1857 |
+ NDS_ARM9.R[8], NDS_ARM9.R[9], NDS_ARM9.R[10], NDS_ARM9.R[11], NDS_ARM9.R[12], NDS_ARM9.R[13], NDS_ARM9.R[14], NDS_ARM9.R[15]); |
|
| 1858 |
+#endif |
|
| 1859 |
+ } |
|
| 1860 |
+#endif |
|
| 1861 |
+}*/ |
|
| 1862 |
+ |
|
| 1863 |
+/*inline void arm7log() |
|
| 1864 |
+{
|
|
| 1865 |
+#ifdef LOG_ARM7 |
|
| 1866 |
+ if(dolog) |
|
| 1867 |
+ {
|
|
| 1868 |
+ char dasmbuf[4096]; |
|
| 1869 |
+ if(NDS_ARM7.CPSR.bits.T) |
|
| 1870 |
+ des_thumb_instructions_set[((NDS_ARM7.instruction)>>6)&1023](NDS_ARM7.instruct_adr, NDS_ARM7.instruction, dasmbuf); |
|
| 1871 |
+ else |
|
| 1872 |
+ des_arm_instructions_set[INDEX(NDS_ARM7.instruction)](NDS_ARM7.instruct_adr, NDS_ARM7.instruction, dasmbuf); |
|
| 1873 |
+#ifdef LOG_TO_FILE |
|
| 1874 |
+ if (!fp_dis7) return; |
|
| 1875 |
+#ifdef LOG_TO_FILE_REGS |
|
| 1876 |
+ fprintf(fp_dis7, "\t\t;R0:%08X R1:%08X R2:%08X R3:%08X R4:%08X R5:%08X R6:%08X R7:%08X R8:%08X R9:%08X\n\t\t;R10:%08X R11:%08X R12:%08X R13:%08X R14:%08X R15:%08X| next %08X, N:%i Z:%i C:%i V:%i\n", |
|
| 1877 |
+ NDS_ARM7.R[0], NDS_ARM7.R[1], NDS_ARM7.R[2], NDS_ARM7.R[3], NDS_ARM7.R[4], NDS_ARM7.R[5], NDS_ARM7.R[6], NDS_ARM7.R[7], |
|
| 1878 |
+ NDS_ARM7.R[8], NDS_ARM7.R[9], NDS_ARM7.R[10], NDS_ARM7.R[11], NDS_ARM7.R[12], NDS_ARM7.R[13], NDS_ARM7.R[14], NDS_ARM7.R[15], |
|
| 1879 |
+ NDS_ARM7.next_instruction, NDS_ARM7.CPSR.bits.N, NDS_ARM7.CPSR.bits.Z, NDS_ARM7.CPSR.bits.C, NDS_ARM7.CPSR.bits.V); |
|
| 1880 |
+#endif |
|
| 1881 |
+ fprintf(fp_dis7, "%s %08X\t%08X \t%s\n", NDS_ARM7.CPSR.bits.T?"THUMB":"ARM", NDS_ARM7.instruct_adr, NDS_ARM7.instruction, dasmbuf);*/ |
|
| 1882 |
+ /*if (NDS_ARM7.instruction == 0) |
|
| 1883 |
+ {
|
|
| 1884 |
+ dolog = false; |
|
| 1885 |
+ INFO("Disassembler is stopped\n");
|
|
| 1886 |
+ }*/ |
|
| 1887 |
+/*#else |
|
| 1888 |
+ printf("%05d:%03d %12lld 7:%08X %08X %-30s R00:%08X R01:%08X R02:%08X R03:%08X R04:%08X R05:%08X R06:%08X R07:%08X R08:%08X R09:%08X R10:%08X R11:%08X R12:%08X R13:%08X R14:%08X R15:%08X\n",
|
|
| 1889 |
+ currFrameCounter, nds.VCount, nds_timer, |
|
| 1890 |
+ NDS_ARM7.instruct_adr,NDS_ARM7.instruction, dasmbuf, |
|
| 1891 |
+ NDS_ARM7.R[0], NDS_ARM7.R[1], NDS_ARM7.R[2], NDS_ARM7.R[3], NDS_ARM7.R[4], NDS_ARM7.R[5], NDS_ARM7.R[6], NDS_ARM7.R[7], |
|
| 1892 |
+ NDS_ARM7.R[8], NDS_ARM7.R[9], NDS_ARM7.R[10], NDS_ARM7.R[11], NDS_ARM7.R[12], NDS_ARM7.R[13], NDS_ARM7.R[14], NDS_ARM7.R[15]); |
|
| 1893 |
+#endif |
|
| 1894 |
+ } |
|
| 1895 |
+#endif |
|
| 1896 |
+}*/ |
|
| 1897 |
+ |
|
| 1898 |
+//these have not been tuned very well yet. |
|
| 1899 |
+static const int kMaxWork = 4000; |
|
| 1900 |
+static const int kIrqWait = 4000; |
|
| 1901 |
+ |
|
| 1902 |
+ |
|
| 1903 |
+template<bool doarm9, bool doarm7> |
|
| 1904 |
+static inline int32_t minarmtime(int32_t arm9, int32_t arm7) |
|
| 1905 |
+{
|
|
| 1906 |
+ if(doarm9) |
|
| 1907 |
+ {
|
|
| 1908 |
+ if(doarm7) |
|
| 1909 |
+ return std::min(arm9,arm7); |
|
| 1910 |
+ else |
|
| 1911 |
+ return arm9; |
|
| 1912 |
+ } |
|
| 1913 |
+ else |
|
| 1914 |
+ return arm7; |
|
| 1915 |
+} |
|
| 1916 |
+ |
|
| 1917 |
+template<bool doarm9, bool doarm7> |
|
| 1918 |
+static /*donotinline*/ std::pair<int32_t,int32_t> armInnerLoop( |
|
| 1919 |
+ const uint64_t nds_timer_base, const int32_t s32next, int32_t arm9, int32_t arm7) |
|
| 1920 |
+{
|
|
| 1921 |
+ int32_t timer = minarmtime<doarm9,doarm7>(arm9,arm7); |
|
| 1922 |
+ while(timer < s32next && !sequencer.reschedule && execute) |
|
| 1923 |
+ {
|
|
| 1924 |
+ if(doarm9 && (!doarm7 || arm9 <= timer)) |
|
| 1925 |
+ {
|
|
| 1926 |
+ if(!NDS_ARM9.waitIRQ&&!nds.freezeBus) |
|
| 1927 |
+ {
|
|
| 1928 |
+ //arm9log(); |
|
| 1929 |
+ arm9 += armcpu_exec<ARMCPU_ARM9>(); |
|
| 1930 |
+ #ifdef DEVELOPER |
|
| 1931 |
+ nds_debug_continuing[0] = false; |
|
| 1932 |
+ #endif |
|
| 1933 |
+ } |
|
| 1934 |
+ else |
|
| 1935 |
+ {
|
|
| 1936 |
+ //int32_t temp = arm9; |
|
| 1937 |
+ arm9 = std::min(s32next, arm9 + kIrqWait); |
|
| 1938 |
+ //nds.idleCycles[0] += arm9-temp; |
|
| 1939 |
+ //if (gxFIFO.size < 255) nds.freezeBus = false; |
|
| 1940 |
+ } |
|
| 1941 |
+ } |
|
| 1942 |
+ if(doarm7 && (!doarm9 || arm7 <= timer)) |
|
| 1943 |
+ {
|
|
| 1944 |
+ if(!NDS_ARM7.waitIRQ&&!nds.freezeBus) |
|
| 1945 |
+ {
|
|
| 1946 |
+ //arm7log(); |
|
| 1947 |
+ arm7 += (armcpu_exec<ARMCPU_ARM7>()<<1); |
|
| 1948 |
+ #ifdef DEVELOPER |
|
| 1949 |
+ nds_debug_continuing[1] = false; |
|
| 1950 |
+ #endif |
|
| 1951 |
+ } |
|
| 1952 |
+ else |
|
| 1953 |
+ {
|
|
| 1954 |
+ //int32_t temp = arm7; |
|
| 1955 |
+ arm7 = std::min(s32next, arm7 + kIrqWait); |
|
| 1956 |
+ //nds.idleCycles[1] += arm7-temp; |
|
| 1957 |
+ if(arm7 == s32next) |
|
| 1958 |
+ {
|
|
| 1959 |
+ nds_timer = nds_timer_base + minarmtime<doarm9,false>(arm9,arm7); |
|
| 1960 |
+ return armInnerLoop<doarm9,false>(nds_timer_base, s32next, arm9, arm7); |
|
| 1961 |
+ } |
|
| 1962 |
+ } |
|
| 1963 |
+ } |
|
| 1964 |
+ |
|
| 1965 |
+ timer = minarmtime<doarm9,doarm7>(arm9,arm7); |
|
| 1966 |
+ nds_timer = nds_timer_base + timer; |
|
| 1967 |
+ } |
|
| 1968 |
+ |
|
| 1969 |
+ return std::make_pair(arm9, arm7); |
|
| 1970 |
+} |
|
| 1971 |
+ |
|
| 1972 |
+/*void NDS_debug_break() |
|
| 1973 |
+{
|
|
| 1974 |
+ NDS_ARM9.stalled = NDS_ARM7.stalled = 1; |
|
| 1975 |
+ |
|
| 1976 |
+ //triggers an immediate exit from the cpu loop |
|
| 1977 |
+ NDS_Reschedule(); |
|
| 1978 |
+}*/ |
|
| 1979 |
+ |
|
| 1980 |
+/*void NDS_debug_continue() |
|
| 1981 |
+{
|
|
| 1982 |
+ NDS_ARM9.stalled = NDS_ARM7.stalled = 0; |
|
| 1983 |
+}*/ |
|
| 1984 |
+ |
|
| 1985 |
+/*void NDS_debug_step() |
|
| 1986 |
+{
|
|
| 1987 |
+ NDS_debug_continue(); |
|
| 1988 |
+ singleStep = true; |
|
| 1989 |
+}*/ |
|
| 1990 |
+ |
|
| 1991 |
+template<bool FORCE> |
|
| 1992 |
+void NDS_exec(int32_t) |
|
| 1993 |
+{
|
|
| 1994 |
+ //LagFrameFlag=1; |
|
| 1995 |
+ |
|
| 1996 |
+ /*if((currFrameCounter&63) == 0) |
|
| 1997 |
+ MMU_new.backupDevice.lazy_flush();*/ |
|
| 1998 |
+ |
|
| 1999 |
+ sequencer.nds_vblankEnded = false; |
|
| 2000 |
+ |
|
| 2001 |
+ //nds.cpuloopIterationCount = 0; |
|
| 2002 |
+ |
|
| 2003 |
+ IF_DEVELOPER(for(int i=0;i<32;i++) DEBUG_statistics.sequencerExecutionCounters[i] = 0); |
|
| 2004 |
+ |
|
| 2005 |
+ if(nds.sleeping) |
|
| 2006 |
+ {
|
|
| 2007 |
+ //speculative code: if ANY irq happens, wake up the arm7. |
|
| 2008 |
+ //I think the arm7 program analyzes the system and may decide not to wake up |
|
| 2009 |
+ //if it is dissatisfied with the conditions |
|
| 2010 |
+ if((MMU.reg_IE[1] & MMU.gen_IF<1>())) |
|
| 2011 |
+ {
|
|
| 2012 |
+ nds.sleeping = false; |
|
| 2013 |
+ } |
|
| 2014 |
+ } |
|
| 2015 |
+ else |
|
| 2016 |
+ {
|
|
| 2017 |
+ for(;;) |
|
| 2018 |
+ {
|
|
| 2019 |
+ //trap the debug-stalled condition |
|
| 2020 |
+ #ifdef DEVELOPER |
|
| 2021 |
+ singleStep = false; |
|
| 2022 |
+ //(gdb stub doesnt yet know how to trigger these immediately by calling reschedule) |
|
| 2023 |
+ while((NDS_ARM9.stalled || NDS_ARM7.stalled) && execute) |
|
| 2024 |
+ {
|
|
| 2025 |
+ driver->EMU_DebugIdleUpdate(); |
|
| 2026 |
+ nds_debug_continuing[0] = nds_debug_continuing[1] = true; |
|
| 2027 |
+ } |
|
| 2028 |
+ #endif |
|
| 2029 |
+ |
|
| 2030 |
+ //nds.cpuloopIterationCount++; |
|
| 2031 |
+ sequencer.execHardware(); |
|
| 2032 |
+ |
|
| 2033 |
+ //break out once per frame |
|
| 2034 |
+ if(sequencer.nds_vblankEnded) break; |
|
| 2035 |
+ //it should be benign to execute execHardware in the next frame, |
|
| 2036 |
+ //since there won't be anything for it to do (everything should be scheduled in the future) |
|
| 2037 |
+ |
|
| 2038 |
+ //bail in case the system halted |
|
| 2039 |
+ if(!execute) break; |
|
| 2040 |
+ |
|
| 2041 |
+ execHardware_interrupts(); |
|
| 2042 |
+ |
|
| 2043 |
+ //find next work unit: |
|
| 2044 |
+ uint64_t next = sequencer.findNext(); |
|
| 2045 |
+ next = std::min(next,nds_timer+kMaxWork); //lets set an upper limit for now |
|
| 2046 |
+ |
|
| 2047 |
+ //printf("%d\n",(next-nds_timer));
|
|
| 2048 |
+ |
|
| 2049 |
+ sequencer.reschedule = false; |
|
| 2050 |
+ |
|
| 2051 |
+ //cast these down to 32bits so that things run faster on 32bit procs |
|
| 2052 |
+ uint64_t nds_timer_base = nds_timer; |
|
| 2053 |
+ int32_t arm9 = (int32_t)(nds_arm9_timer-nds_timer); |
|
| 2054 |
+ int32_t arm7 = (int32_t)(nds_arm7_timer-nds_timer); |
|
| 2055 |
+ int32_t s32next = (int32_t)(next-nds_timer); |
|
| 2056 |
+ |
|
| 2057 |
+ #ifdef DEVELOPER |
|
| 2058 |
+ if(singleStep) |
|
| 2059 |
+ {
|
|
| 2060 |
+ s32next = 1; |
|
| 2061 |
+ } |
|
| 2062 |
+ #endif |
|
| 2063 |
+ |
|
| 2064 |
+ std::pair<int32_t,int32_t> arm9arm7 = armInnerLoop<true,true>(nds_timer_base,s32next,arm9,arm7); |
|
| 2065 |
+ |
|
| 2066 |
+ #ifdef DEVELOPER |
|
| 2067 |
+ if(singleStep) |
|
| 2068 |
+ {
|
|
| 2069 |
+ NDS_ARM9.stalled = NDS_ARM7.stalled = 1; |
|
| 2070 |
+ } |
|
| 2071 |
+ #endif |
|
| 2072 |
+ |
|
| 2073 |
+ arm9 = arm9arm7.first; |
|
| 2074 |
+ arm7 = arm9arm7.second; |
|
| 2075 |
+ nds_arm7_timer = nds_timer_base+arm7; |
|
| 2076 |
+ nds_arm9_timer = nds_timer_base+arm9; |
|
| 2077 |
+ |
|
| 2078 |
+#ifndef NDEBUG |
|
| 2079 |
+ //what we find here is dependent on the timing constants above |
|
| 2080 |
+ //if(nds_timer>next && (nds_timer-next)>22) |
|
| 2081 |
+ // printf("curious. please report: over by %d\n",(int)(nds_timer-next));
|
|
| 2082 |
+#endif |
|
| 2083 |
+ |
|
| 2084 |
+ //if we were waiting for an irq, don't wait too long: |
|
| 2085 |
+ //let's re-analyze it after this hardware event (this rolls back a big burst of irq waiting which may have been interrupted by a resynch) |
|
| 2086 |
+ if(NDS_ARM9.waitIRQ) |
|
| 2087 |
+ {
|
|
| 2088 |
+ //nds.idleCycles[0] -= (int32_t)(nds_arm9_timer-nds_timer); |
|
| 2089 |
+ nds_arm9_timer = nds_timer; |
|
| 2090 |
+ } |
|
| 2091 |
+ if(NDS_ARM7.waitIRQ) |
|
| 2092 |
+ {
|
|
| 2093 |
+ //nds.idleCycles[1] -= (int32_t)(nds_arm7_timer-nds_timer); |
|
| 2094 |
+ nds_arm7_timer = nds_timer; |
|
| 2095 |
+ } |
|
| 2096 |
+ } |
|
| 2097 |
+ } |
|
| 2098 |
+ |
|
| 2099 |
+ //DEBUG_statistics.printSequencerExecutionCounters(); |
|
| 2100 |
+ //DEBUG_statistics.print(); |
|
| 2101 |
+ |
|
| 2102 |
+ //end of frame emulation housekeeping |
|
| 2103 |
+ /*if(LagFrameFlag) |
|
| 2104 |
+ {
|
|
| 2105 |
+ lagframecounter++; |
|
| 2106 |
+ TotalLagFrames++; |
|
| 2107 |
+ } |
|
| 2108 |
+ else |
|
| 2109 |
+ {
|
|
| 2110 |
+ lastLag = lagframecounter; |
|
| 2111 |
+ lagframecounter = 0; |
|
| 2112 |
+ }*/ |
|
| 2113 |
+ //currFrameCounter++; |
|
| 2114 |
+ //DEBUG_Notify.NextFrame(); |
|
| 2115 |
+ /*if (cheats) |
|
| 2116 |
+ cheats->process();*/ |
|
| 2117 |
+} |
|
| 2118 |
+ |
|
| 2119 |
+template<int PROCNUM> static void execHardware_interrupts_core() |
|
| 2120 |
+{
|
|
| 2121 |
+ uint32_t IF = MMU.gen_IF<PROCNUM>(); |
|
| 2122 |
+ uint32_t IE = MMU.reg_IE[PROCNUM]; |
|
| 2123 |
+ uint32_t masked = IF & IE; |
|
| 2124 |
+ if(ARMPROC.halt_IE_and_IF && masked) |
|
| 2125 |
+ {
|
|
| 2126 |
+ ARMPROC.halt_IE_and_IF = false; |
|
| 2127 |
+ ARMPROC.waitIRQ = false; |
|
| 2128 |
+ } |
|
| 2129 |
+ |
|
| 2130 |
+ if(masked && MMU.reg_IME[PROCNUM] && !ARMPROC.CPSR.bits.I) |
|
| 2131 |
+ {
|
|
| 2132 |
+ //printf("Executing IRQ on procnum %d with IF = %08X and IE = %08X\n",PROCNUM,IF,IE);
|
|
| 2133 |
+ armcpu_irqException(&ARMPROC); |
|
| 2134 |
+ } |
|
| 2135 |
+} |
|
| 2136 |
+ |
|
| 2137 |
+void execHardware_interrupts() |
|
| 2138 |
+{
|
|
| 2139 |
+ execHardware_interrupts_core<ARMCPU_ARM9>(); |
|
| 2140 |
+ execHardware_interrupts_core<ARMCPU_ARM7>(); |
|
| 2141 |
+} |
|
| 2142 |
+ |
|
| 2143 |
+//static void resetUserInput(); |
|
| 2144 |
+ |
|
| 2145 |
+//bool _HACK_DONT_STOPMOVIE = false; |
|
| 2146 |
+void NDS_Reset() |
|
| 2147 |
+{
|
|
| 2148 |
+ singleStep = false; |
|
| 2149 |
+ //nds_debug_continuing[0] = nds_debug_continuing[1] = false; |
|
| 2150 |
+ uint32_t src = 0; |
|
| 2151 |
+ uint32_t dst = 0; |
|
| 2152 |
+ bool fw_success = false; |
|
| 2153 |
+ FILE* inf = NULL; |
|
| 2154 |
+ NDS_header * header = NDS_getROMHeader(); |
|
| 2155 |
+ |
|
| 2156 |
+ //DEBUG_reset(); |
|
| 2157 |
+ |
|
| 2158 |
+ if (!header) return ; |
|
| 2159 |
+ |
|
| 2160 |
+ nds.sleeping = false; |
|
| 2161 |
+ nds.cardEjected = false; |
|
| 2162 |
+ nds.freezeBus = 0; |
|
| 2163 |
+ //nds.power1.lcd = nds.power1.gpuMain = nds.power1.gfx3d_render = nds.power1.gfx3d_geometry = nds.power1.gpuSub = nds.power1.dispswap = 1; |
|
| 2164 |
+ //nds.power2.speakers = 1; |
|
| 2165 |
+ //nds.power2.wifi = 0; |
|
| 2166 |
+ |
|
| 2167 |
+ nds_timer = 0; |
|
| 2168 |
+ nds_arm9_timer = 0; |
|
| 2169 |
+ nds_arm7_timer = 0; |
|
| 2170 |
+ |
|
| 2171 |
+ /*if(movieMode != MOVIEMODE_INACTIVE && !_HACK_DONT_STOPMOVIE) |
|
| 2172 |
+ movie_reset_command = true;*/ |
|
| 2173 |
+ |
|
| 2174 |
+ /*if(movieMode == MOVIEMODE_INACTIVE) {
|
|
| 2175 |
+ //currFrameCounter = 0; |
|
| 2176 |
+ lagframecounter = 0; |
|
| 2177 |
+ LagFrameFlag = 0; |
|
| 2178 |
+ lastLag = 0; |
|
| 2179 |
+ TotalLagFrames = 0; |
|
| 2180 |
+ }*/ |
|
| 2181 |
+ |
|
| 2182 |
+ SPU_DeInit(); |
|
| 2183 |
+ |
|
| 2184 |
+ MMU_Reset(); |
|
| 2185 |
+ |
|
| 2186 |
+ //put random garbage in vram for homebrew games, to help mimic the situation where libnds does not clear out junk |
|
| 2187 |
+ //which the card's launcher may or may not have left behind |
|
| 2188 |
+ //1. retail games dont clear TCM, so why should we jumble it and expect homebrew to clear it? |
|
| 2189 |
+ //2. some retail games _dont boot_ if main memory is jumbled. wha...? |
|
| 2190 |
+ //3. clearing this is not as useful as tracking uninitialized reads in dev+ builds |
|
| 2191 |
+ //4. the vram clearing causes lots of graphical corruptions in badly coded homebrews. this reduces compatibility substantially |
|
| 2192 |
+ //conclusion: disable it for now and bring it back as an option |
|
| 2193 |
+ //if(gameInfo.isHomebrew) |
|
| 2194 |
+ //{
|
|
| 2195 |
+ // uint32_t w=100000,x=99,y=117,z=19382173; |
|
| 2196 |
+ // CTASSERT(sizeof(MMU.ARM9_LCD) < sizeof(MMU.MAIN_MEM)); |
|
| 2197 |
+ // CTASSERT(sizeof(MMU.ARM9_VMEM) < sizeof(MMU.MAIN_MEM)); |
|
| 2198 |
+ // CTASSERT(sizeof(MMU.ARM9_ITCM) < sizeof(MMU.MAIN_MEM)); |
|
| 2199 |
+ // CTASSERT(sizeof(MMU.ARM9_DTCM) < sizeof(MMU.MAIN_MEM)); |
|
| 2200 |
+ // for(int i=0;i<sizeof(MMU.MAIN_MEM);i++) |
|
| 2201 |
+ // {
|
|
| 2202 |
+ // uint32_t t= (x^(x<<11)); |
|
| 2203 |
+ // x=y; |
|
| 2204 |
+ // y=z; |
|
| 2205 |
+ // z=w; |
|
| 2206 |
+ // t = (w= (w^(w>>19))^(t^(t>>8))); |
|
| 2207 |
+ // //MMU.MAIN_MEM[i] = t; |
|
| 2208 |
+ // if (i<sizeof(MMU.ARM9_LCD)) MMU.ARM9_LCD[i] = t; |
|
| 2209 |
+ // if (i<sizeof(MMU.ARM9_VMEM)) MMU.ARM9_VMEM[i] = t; |
|
| 2210 |
+ // //if (i<sizeof(MMU.ARM9_ITCM)) MMU.ARM9_ITCM[i] = t; |
|
| 2211 |
+ // //if (i<sizeof(MMU.ARM9_DTCM)) MMU.ARM9_DTCM[i] = t; |
|
| 2212 |
+ // } |
|
| 2213 |
+ //} |
|
| 2214 |
+ |
|
| 2215 |
+ NDS_ARM7.BIOS_loaded = false; |
|
| 2216 |
+ NDS_ARM9.BIOS_loaded = false; |
|
| 2217 |
+ memset(MMU.ARM7_BIOS, 0, sizeof(MMU.ARM7_BIOS)); |
|
| 2218 |
+ memset(MMU.ARM9_BIOS, 0, sizeof(MMU.ARM9_BIOS)); |
|
| 2219 |
+ |
|
| 2220 |
+ //ARM7 BIOS IRQ HANDLER |
|
| 2221 |
+ if(CommonSettings.UseExtBIOS == true) |
|
| 2222 |
+ inf = fopen(CommonSettings.ARM7BIOS,"rb"); |
|
| 2223 |
+ else |
|
| 2224 |
+ inf = NULL; |
|
| 2225 |
+ |
|
| 2226 |
+ if(inf) |
|
| 2227 |
+ {
|
|
| 2228 |
+ if (fread(MMU.ARM7_BIOS,1,16384,inf) == 16384) NDS_ARM7.BIOS_loaded = true; |
|
| 2229 |
+ fclose(inf); |
|
| 2230 |
+ |
|
| 2231 |
+ if((CommonSettings.SWIFromBIOS) && (NDS_ARM7.BIOS_loaded)) NDS_ARM7.swi_tab = 0; |
|
| 2232 |
+ else NDS_ARM7.swi_tab = ARM7_swi_tab; |
|
| 2233 |
+ |
|
| 2234 |
+ if (CommonSettings.PatchSWI3) |
|
| 2235 |
+ _MMU_write16<ARMCPU_ARM7>(0x00002F08, 0x4770); |
|
| 2236 |
+ |
|
| 2237 |
+ //INFO("ARM7 BIOS is %s.\n", NDS_ARM7.BIOS_loaded?"loaded":"failed");
|
|
| 2238 |
+ } |
|
| 2239 |
+ else |
|
| 2240 |
+ {
|
|
| 2241 |
+ NDS_ARM7.swi_tab = ARM7_swi_tab; |
|
| 2242 |
+ |
|
| 2243 |
+#if 0 |
|
| 2244 |
+ // TODO |
|
| 2245 |
+ T1WriteLong(MMU.ARM7_BIOS, 0x0000, 0xEAFFFFFE); // loop for Reset !!! |
|
| 2246 |
+ T1WriteLong(MMU.ARM7_BIOS, 0x0004, 0xEAFFFFFE); // loop for Undef instr expection |
|
| 2247 |
+ T1WriteLong(MMU.ARM7_BIOS, 0x0008, 0xEA00009C); // SWI |
|
| 2248 |
+ T1WriteLong(MMU.ARM7_BIOS, 0x000C, 0xEAFFFFFE); // loop for Prefetch Abort |
|
| 2249 |
+ T1WriteLong(MMU.ARM7_BIOS, 0x0010, 0xEAFFFFFE); // loop for Data Abort |
|
| 2250 |
+ T1WriteLong(MMU.ARM7_BIOS, 0x0014, 0x00000000); // Reserved |
|
| 2251 |
+ T1WriteLong(MMU.ARM7_BIOS, 0x001C, 0x00000000); // Fast IRQ |
|
| 2252 |
+#endif |
|
| 2253 |
+ T1WriteLong(MMU.ARM7_BIOS, 0x0000, 0xE25EF002); |
|
| 2254 |
+ T1WriteLong(MMU.ARM7_BIOS, 0x0018, 0xEA000000); |
|
| 2255 |
+ T1WriteLong(MMU.ARM7_BIOS, 0x0020, 0xE92D500F); |
|
| 2256 |
+ T1WriteLong(MMU.ARM7_BIOS, 0x0024, 0xE3A00301); |
|
| 2257 |
+ T1WriteLong(MMU.ARM7_BIOS, 0x0028, 0xE28FE000); |
|
| 2258 |
+ T1WriteLong(MMU.ARM7_BIOS, 0x002C, 0xE510F004); |
|
| 2259 |
+ T1WriteLong(MMU.ARM7_BIOS, 0x0030, 0xE8BD500F); |
|
| 2260 |
+ T1WriteLong(MMU.ARM7_BIOS, 0x0034, 0xE25EF004); |
|
| 2261 |
+ } |
|
| 2262 |
+ |
|
| 2263 |
+ //ARM9 BIOS IRQ HANDLER |
|
| 2264 |
+ if(CommonSettings.UseExtBIOS == true) |
|
| 2265 |
+ inf = fopen(CommonSettings.ARM9BIOS,"rb"); |
|
| 2266 |
+ else |
|
| 2267 |
+ inf = NULL; |
|
| 2268 |
+ |
|
| 2269 |
+ if(inf) |
|
| 2270 |
+ {
|
|
| 2271 |
+ if (fread(MMU.ARM9_BIOS,1,4096,inf) == 4096) NDS_ARM9.BIOS_loaded = true; |
|
| 2272 |
+ fclose(inf); |
|
| 2273 |
+ |
|
| 2274 |
+ if((CommonSettings.SWIFromBIOS) && (NDS_ARM9.BIOS_loaded)) NDS_ARM9.swi_tab = 0; |
|
| 2275 |
+ else NDS_ARM9.swi_tab = ARM9_swi_tab; |
|
| 2276 |
+ |
|
| 2277 |
+ if (CommonSettings.PatchSWI3) |
|
| 2278 |
+ _MMU_write16<ARMCPU_ARM9>(0xFFFF07CC, 0x4770); |
|
| 2279 |
+ |
|
| 2280 |
+ //INFO("ARM9 BIOS is %s.\n", NDS_ARM9.BIOS_loaded?"loaded":"failed");
|
|
| 2281 |
+ } |
|
| 2282 |
+ else |
|
| 2283 |
+ {
|
|
| 2284 |
+ NDS_ARM9.swi_tab = ARM9_swi_tab; |
|
| 2285 |
+ |
|
| 2286 |
+ //bios chains data abort to fast irq |
|
| 2287 |
+ |
|
| 2288 |
+ //exception vectors: |
|
| 2289 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x0000, 0xEAFFFFFE); // (infinite loop for) Reset !!! |
|
| 2290 |
+ //T1WriteLong(MMU.ARM9_BIOS, 0x0004, 0xEAFFFFFE); // (infinite loop for) Undefined instruction |
|
| 2291 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x0004, 0xEA000004); // Undefined instruction -> Fast IRQ (just guessing) |
|
| 2292 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x0008, 0xEA00009C); // SWI -> ????? |
|
| 2293 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x000C, 0xEAFFFFFE); // (infinite loop for) Prefetch Abort |
|
| 2294 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x0010, 0xEA000001); // Data Abort -> Fast IRQ |
|
| 2295 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x0014, 0x00000000); // Reserved |
|
| 2296 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x0018, 0xEA000095); // Normal IRQ -> 0x0274 |
|
| 2297 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x001C, 0xEA00009D); // Fast IRQ -> 0x0298 |
|
| 2298 |
+ |
|
| 2299 |
+ // logo (do some games fail to boot without this? example?) |
|
| 2300 |
+ for (int t = 0; t < 0x9C; t++) |
|
| 2301 |
+ MMU.ARM9_BIOS[t + 0x20] = logo_data[t]; |
|
| 2302 |
+ |
|
| 2303 |
+ //...0xBC: |
|
| 2304 |
+ |
|
| 2305 |
+ //(now what goes in this gap??) |
|
| 2306 |
+ |
|
| 2307 |
+ //IRQ handler: get dtcm address and jump to a vector in it |
|
| 2308 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x0274, 0xE92D500F); //STMDB SP!, {R0-R3,R12,LR}
|
|
| 2309 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x0278, 0xEE190F11); //MRC CP15, 0, R0, CR9, CR1, 0 |
|
| 2310 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x027C, 0xE1A00620); //MOV R0, R0, LSR #C |
|
| 2311 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x0280, 0xE1A00600); //MOV R0, R0, LSL #C |
|
| 2312 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x0284, 0xE2800C40); //ADD R0, R0, #4000 |
|
| 2313 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x0288, 0xE28FE000); //ADD LR, PC, #0 |
|
| 2314 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x028C, 0xE510F004); //LDR PC, [R0, -#4] |
|
| 2315 |
+ |
|
| 2316 |
+ //???? |
|
| 2317 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x0290, 0xE8BD500F); //LDMIA SP!, {R0-R3,R12,LR}
|
|
| 2318 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x0294, 0xE25EF004); //SUBS PC, LR, #4 |
|
| 2319 |
+ |
|
| 2320 |
+ //------- |
|
| 2321 |
+ //FIQ and abort exception handler |
|
| 2322 |
+ //TODO - this code is copied from the bios. refactor it |
|
| 2323 |
+ //friendly reminder: to calculate an immediate offset: encoded = (desired_address-cur_address-8) |
|
| 2324 |
+ |
|
| 2325 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x0298, 0xE10FD000); //MRS SP, CPSR |
|
| 2326 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x029C, 0xE38DD0C0); //ORR SP, SP, #C0 |
|
| 2327 |
+ |
|
| 2328 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x02A0, 0xE12FF00D); //MSR CPSR_fsxc, SP |
|
| 2329 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x02A4, 0xE59FD000 | (0x2D4-0x2A4-8)); //LDR SP, [FFFF02D4] |
|
| 2330 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x02A8, 0xE28DD001); //ADD SP, SP, #1 |
|
| 2331 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x02AC, 0xE92D5000); //STMDB SP!, {R12,LR}
|
|
| 2332 |
+ |
|
| 2333 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x02B0, 0xE14FE000); //MRS LR, SPSR |
|
| 2334 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x02B4, 0xEE11CF10); //MRC CP15, 0, R12, CR1, CR0, 0 |
|
| 2335 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x02B8, 0xE92D5000); //STMDB SP!, {R12,LR}
|
|
| 2336 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x02BC, 0xE3CCC001); //BIC R12, R12, #1 |
|
| 2337 |
+ |
|
| 2338 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x02C0, 0xEE01CF10); //MCR CP15, 0, R12, CR1, CR0, 0 |
|
| 2339 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x02C4, 0xE3CDC001); //BIC R12, SP, #1 |
|
| 2340 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x02C8, 0xE59CC010); //LDR R12, [R12, #10] |
|
| 2341 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x02CC, 0xE35C0000); //CMP R12, #0 |
|
| 2342 |
+ |
|
| 2343 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x02D0, 0x112FFF3C); //BLXNE R12 |
|
| 2344 |
+ T1WriteLong(MMU.ARM9_BIOS, 0x02D4, 0x027FFD9C); //0x027FFD9C |
|
| 2345 |
+ //--------- |
|
| 2346 |
+ |
|
| 2347 |
+ } |
|
| 2348 |
+ |
|
| 2349 |
+#ifdef LOG_ARM7 |
|
| 2350 |
+ if (fp_dis7 != NULL) |
|
| 2351 |
+ {
|
|
| 2352 |
+ fclose(fp_dis7); |
|
| 2353 |
+ fp_dis7 = NULL; |
|
| 2354 |
+ } |
|
| 2355 |
+ fp_dis7 = fopen("D:\\desmume_dis7.asm", "w");
|
|
| 2356 |
+#endif |
|
| 2357 |
+ |
|
| 2358 |
+#ifdef LOG_ARM9 |
|
| 2359 |
+ if (fp_dis9 != NULL) |
|
| 2360 |
+ {
|
|
| 2361 |
+ fclose(fp_dis9); |
|
| 2362 |
+ fp_dis9 = NULL; |
|
| 2363 |
+ } |
|
| 2364 |
+ fp_dis9 = fopen("D:\\desmume_dis9.asm", "w");
|
|
| 2365 |
+#endif |
|
| 2366 |
+ |
|
| 2367 |
+ if (firmware) |
|
| 2368 |
+ {
|
|
| 2369 |
+ delete firmware; |
|
| 2370 |
+ firmware = NULL; |
|
| 2371 |
+ } |
|
| 2372 |
+ firmware = new CFIRMWARE(); |
|
| 2373 |
+ fw_success = firmware->load(); |
|
| 2374 |
+ if (NDS_ARM7.BIOS_loaded && NDS_ARM9.BIOS_loaded && CommonSettings.BootFromFirmware && fw_success) |
|
| 2375 |
+ {
|
|
| 2376 |
+ // Copy secure area to memory if needed |
|
| 2377 |
+ if ((header->ARM9src >= 0x4000) && (header->ARM9src < 0x8000)) |
|
| 2378 |
+ {
|
|
| 2379 |
+ src = header->ARM9src; |
|
| 2380 |
+ dst = header->ARM9cpy; |
|
| 2381 |
+ |
|
| 2382 |
+ uint32_t size = (0x8000 - src) >> 2; |
|
| 2383 |
+ //INFO("Copy secure area from 0x%08X to 0x%08X (size %i/0x%08X)\n", src, dst, size, size);
|
|
| 2384 |
+ for (uint32_t i = 0; i < size; i++) |
|
| 2385 |
+ {
|
|
| 2386 |
+ _MMU_write32<ARMCPU_ARM9>(dst, T1ReadLong(MMU.CART_ROM, src)); |
|
| 2387 |
+ src += 4; dst += 4; |
|
| 2388 |
+ } |
|
| 2389 |
+ } |
|
| 2390 |
+ |
|
| 2391 |
+ if (firmware->patched) |
|
| 2392 |
+ {
|
|
| 2393 |
+ armcpu_init(&NDS_ARM7, 0x00000008); |
|
| 2394 |
+ armcpu_init(&NDS_ARM9, 0xFFFF0008); |
|
| 2395 |
+ } |
|
| 2396 |
+ else |
|
| 2397 |
+ {
|
|
| 2398 |
+ //INFO("Booting at ARM9: 0x%08X, ARM7: 0x%08X\n", firmware->ARM9bootAddr, firmware->ARM7bootAddr);
|
|
| 2399 |
+ // need for firmware |
|
| 2400 |
+ //armcpu_init(&NDS_ARM7, 0x00000008); |
|
| 2401 |
+ //armcpu_init(&NDS_ARM9, 0xFFFF0008); |
|
| 2402 |
+ armcpu_init(&NDS_ARM7, firmware->ARM7bootAddr); |
|
| 2403 |
+ armcpu_init(&NDS_ARM9, firmware->ARM9bootAddr); |
|
| 2404 |
+ } |
|
| 2405 |
+ |
|
| 2406 |
+ _MMU_write08<ARMCPU_ARM9>(0x04000300, 0); |
|
| 2407 |
+ _MMU_write08<ARMCPU_ARM7>(0x04000300, 0); |
|
| 2408 |
+ } |
|
| 2409 |
+ else |
|
| 2410 |
+ {
|
|
| 2411 |
+ src = header->ARM9src; |
|
| 2412 |
+ dst = header->ARM9cpy; |
|
| 2413 |
+ |
|
| 2414 |
+ for(uint32_t i = 0; i < (header->ARM9binSize>>2); ++i) |
|
| 2415 |
+ {
|
|
| 2416 |
+ _MMU_write32<ARMCPU_ARM9>(dst, T1ReadLong(MMU.CART_ROM, src)); |
|
| 2417 |
+ dst += 4; |
|
| 2418 |
+ src += 4; |
|
| 2419 |
+ } |
|
| 2420 |
+ |
|
| 2421 |
+ src = header->ARM7src; |
|
| 2422 |
+ dst = header->ARM7cpy; |
|
| 2423 |
+ |
|
| 2424 |
+ for(uint32_t i = 0; i < (header->ARM7binSize>>2); ++i) |
|
| 2425 |
+ {
|
|
| 2426 |
+ _MMU_write32<ARMCPU_ARM7>(dst, T1ReadLong(MMU.CART_ROM, src)); |
|
| 2427 |
+ dst += 4; |
|
| 2428 |
+ src += 4; |
|
| 2429 |
+ } |
|
| 2430 |
+ |
|
| 2431 |
+ armcpu_init(&NDS_ARM7, header->ARM7exe); |
|
| 2432 |
+ armcpu_init(&NDS_ARM9, header->ARM9exe); |
|
| 2433 |
+ |
|
| 2434 |
+ _MMU_write08<ARMCPU_ARM9>(REG_POSTFLG, 1); |
|
| 2435 |
+ _MMU_write08<ARMCPU_ARM7>(REG_POSTFLG, 1); |
|
| 2436 |
+ } |
|
| 2437 |
+ //bitbox 4k demo is so stripped down it relies on default stack values |
|
| 2438 |
+ //otherwise the arm7 will crash before making a sound |
|
| 2439 |
+ //(these according to gbatek softreset bios docs) |
|
| 2440 |
+ NDS_ARM7.R13_svc = 0x0380FFDC; |
|
| 2441 |
+ NDS_ARM7.R13_irq = 0x0380FFB0; |
|
| 2442 |
+ NDS_ARM7.R13_usr = 0x0380FF00; |
|
| 2443 |
+ NDS_ARM7.R[13] = NDS_ARM7.R13_usr; |
|
| 2444 |
+ //and let's set these for the arm9 while we're at it, though we have no proof |
|
| 2445 |
+ NDS_ARM9.R13_svc = 0x00803FC0; |
|
| 2446 |
+ NDS_ARM9.R13_irq = 0x00803FA0; |
|
| 2447 |
+ NDS_ARM9.R13_usr = 0x00803EC0; |
|
| 2448 |
+ NDS_ARM9.R13_abt = NDS_ARM9.R13_usr; //????? |
|
| 2449 |
+ //I think it is wrong to take gbatek's "SYS" and put it in USR--maybe USR doesnt matter. |
|
| 2450 |
+ //i think SYS is all the misc modes. please verify by setting nonsensical stack values for USR here |
|
| 2451 |
+ NDS_ARM9.R[13] = NDS_ARM9.R13_usr; |
|
| 2452 |
+ //n.b.: im not sure about all these, I dont know enough about arm9 svc/irq/etc modes |
|
| 2453 |
+ //and how theyre named in desmume to match them up correctly. i just guessed. |
|
| 2454 |
+ |
|
| 2455 |
+ //nds.wifiCycle = 0; |
|
| 2456 |
+ memset(nds.timerCycle, 0, sizeof(uint64_t) * 2 * 4); |
|
| 2457 |
+ nds.old = 0; |
|
| 2458 |
+ //nds.touchX = nds.touchY = 0; |
|
| 2459 |
+ //nds.isTouch = 0; |
|
| 2460 |
+ //nds.debugConsole = CommonSettings.DebugConsole; |
|
| 2461 |
+ //nds.ensataEmulation = CommonSettings.EnsataEmulation; |
|
| 2462 |
+ //nds.ensataHandshake = ENSATA_HANDSHAKE_none; |
|
| 2463 |
+ //nds.ensataIpcSyncCounter = 0; |
|
| 2464 |
+ SetupMMU(/*nds.Is_DebugConsole()*/false,nds.Is_DSI()); |
|
| 2465 |
+ |
|
| 2466 |
+ _MMU_write16<ARMCPU_ARM9>(REG_KEYINPUT, 0x3FF); |
|
| 2467 |
+ _MMU_write16<ARMCPU_ARM7>(REG_KEYINPUT, 0x3FF); |
|
| 2468 |
+ _MMU_write08<ARMCPU_ARM7>(REG_EXTKEYIN, 0x43); |
|
| 2469 |
+ |
|
| 2470 |
+ //LidClosed = false; |
|
| 2471 |
+ //countLid = 0; |
|
| 2472 |
+ |
|
| 2473 |
+ //resetUserInput(); |
|
| 2474 |
+ |
|
| 2475 |
+ //Setup a copy of the firmware user settings in memory. |
|
| 2476 |
+ //(this is what the DS firmware would do). |
|
| 2477 |
+ {
|
|
| 2478 |
+ uint8_t temp_buffer[NDS_FW_USER_SETTINGS_MEM_BYTE_COUNT]; |
|
| 2479 |
+ int fw_index; |
|
| 2480 |
+ |
|
| 2481 |
+ if ( copy_firmware_user_data( temp_buffer, &MMU.fw.data[0])) {
|
|
| 2482 |
+ for ( fw_index = 0; fw_index < NDS_FW_USER_SETTINGS_MEM_BYTE_COUNT; fw_index++) |
|
| 2483 |
+ _MMU_write08<ARMCPU_ARM9>(0x027FFC80 + fw_index, temp_buffer[fw_index]); |
|
| 2484 |
+ } |
|
| 2485 |
+ } |
|
| 2486 |
+ |
|
| 2487 |
+ // Copy the whole header to Main RAM 0x27FFE00 on startup. (http://nocash.emubase.de/gbatek.htm#dscartridgeheader) |
|
| 2488 |
+ //once upon a time this copied 0x90 more. this was thought to be wrong, and changed. |
|
| 2489 |
+ if(nds.Is_DSI()) |
|
| 2490 |
+ {
|
|
| 2491 |
+ //dsi needs this copied later in memory. there are probably a number of things that get copied to a later location in memory.. thats where the NDS consoles tend to stash stuff. |
|
| 2492 |
+ for (int i = 0; i < ((0x170)/4); i++) |
|
| 2493 |
+ _MMU_write32<ARMCPU_ARM9>(0x02FFFE00+i*4, LE_TO_LOCAL_32(((uint32_t*)MMU.CART_ROM)[i])); |
|
| 2494 |
+ } |
|
| 2495 |
+ else |
|
| 2496 |
+ {
|
|
| 2497 |
+ for (int i = 0; i < ((0x170)/4); i++) |
|
| 2498 |
+ _MMU_write32<ARMCPU_ARM9>(0x027FFE00+i*4, LE_TO_LOCAL_32(((uint32_t*)MMU.CART_ROM)[i])); |
|
| 2499 |
+ } |
|
| 2500 |
+ |
|
| 2501 |
+ // Write the header checksum to memory (the firmware needs it to see the cart) |
|
| 2502 |
+ _MMU_write16<ARMCPU_ARM9>(0x027FF808, T1ReadWord(MMU.CART_ROM, 0x15E)); |
|
| 2503 |
+ |
|
| 2504 |
+ //-------------------------------- |
|
| 2505 |
+ //setup the homebrew argv |
|
| 2506 |
+ //this is useful for nitrofs apps which are emulating themselves via cflash |
|
| 2507 |
+ //struct __argv {
|
|
| 2508 |
+ // int argvMagic; //!< argv magic number, set to 0x5f617267 ('_arg') if valid
|
|
| 2509 |
+ // char *commandLine; //!< base address of command line, set of null terminated strings |
|
| 2510 |
+ // int length; //!< total length of command line |
|
| 2511 |
+ // int argc; //!< internal use, number of arguments |
|
| 2512 |
+ // char **argv; //!< internal use, argv pointer |
|
| 2513 |
+ //}; |
|
| 2514 |
+ std::string rompath = "fat:/" + path.RomName; |
|
| 2515 |
+ const uint32_t kCommandline = 0x027E0000; |
|
| 2516 |
+ //const uint32_t kCommandline = 0x027FFF84; |
|
| 2517 |
+ |
|
| 2518 |
+ // |
|
| 2519 |
+ _MMU_write32<ARMCPU_ARM9>(0x02FFFE70, 0x5f617267); |
|
| 2520 |
+ _MMU_write32<ARMCPU_ARM9>(0x02FFFE74, kCommandline); //(commandline starts here) |
|
| 2521 |
+ _MMU_write32<ARMCPU_ARM9>(0x02FFFE78, rompath.size()+1); |
|
| 2522 |
+ //0x027FFF7C (argc) |
|
| 2523 |
+ //0x027FFF80 (argv) |
|
| 2524 |
+ for(size_t i=0;i<rompath.size();i++) |
|
| 2525 |
+ _MMU_write08<ARMCPU_ARM9>(kCommandline+i, rompath[i]); |
|
| 2526 |
+ _MMU_write08<ARMCPU_ARM9>(kCommandline+rompath.size(), 0); |
|
| 2527 |
+ //-------------------------------- |
|
| 2528 |
+ |
|
| 2529 |
+ if ((firmware->patched) && (CommonSettings.UseExtBIOS == true) && (CommonSettings.BootFromFirmware == true) && (fw_success == true)) |
|
| 2530 |
+ {
|
|
| 2531 |
+ // HACK! for flashme |
|
| 2532 |
+ _MMU_write32<ARMCPU_ARM9>(0x27FFE24, firmware->ARM9bootAddr); |
|
| 2533 |
+ _MMU_write32<ARMCPU_ARM7>(0x27FFE34, firmware->ARM7bootAddr); |
|
| 2534 |
+ } |
|
| 2535 |
+ |
|
| 2536 |
+ // make system think it's booted from card -- EXTREMELY IMPORTANT!!! Thanks to cReDiAr |
|
| 2537 |
+ _MMU_write08<ARMCPU_ARM9>(0x02FFFC40,0x1); |
|
| 2538 |
+ _MMU_write08<ARMCPU_ARM7>(0x02FFFC40,0x1); |
|
| 2539 |
+ |
|
| 2540 |
+ // Save touchscreen calibration info in a structure |
|
| 2541 |
+ // so we can easily access it at any time |
|
| 2542 |
+ //TSCal.adc.x1 = _MMU_read16<ARMCPU_ARM7>(0x027FFC80 + 0x58); |
|
| 2543 |
+ //TSCal.adc.y1 = _MMU_read16<ARMCPU_ARM7>(0x027FFC80 + 0x5A); |
|
| 2544 |
+ //TSCal.scr.x1 = _MMU_read08<ARMCPU_ARM7>(0x027FFC80 + 0x5C); |
|
| 2545 |
+ //TSCal.scr.y1 = _MMU_read08<ARMCPU_ARM7>(0x027FFC80 + 0x5D); |
|
| 2546 |
+ //TSCal.adc.x2 = _MMU_read16<ARMCPU_ARM7>(0x027FFC80 + 0x5E); |
|
| 2547 |
+ //TSCal.adc.y2 = _MMU_read16<ARMCPU_ARM7>(0x027FFC80 + 0x60); |
|
| 2548 |
+ //TSCal.scr.x2 = _MMU_read08<ARMCPU_ARM7>(0x027FFC80 + 0x62); |
|
| 2549 |
+ //TSCal.scr.y2 = _MMU_read08<ARMCPU_ARM7>(0x027FFC80 + 0x63); |
|
| 2550 |
+ |
|
| 2551 |
+ //TSCal.adc.width = (TSCal.adc.x2 - TSCal.adc.x1); |
|
| 2552 |
+ //TSCal.adc.height = (TSCal.adc.y2 - TSCal.adc.y1); |
|
| 2553 |
+ //TSCal.scr.width = (TSCal.scr.x2 - TSCal.scr.x1); |
|
| 2554 |
+ //TSCal.scr.height = (TSCal.scr.y2 - TSCal.scr.y1); |
|
| 2555 |
+ |
|
| 2556 |
+ //MainScreen.offset = 0; |
|
| 2557 |
+ //SubScreen.offset = 192; |
|
| 2558 |
+ |
|
| 2559 |
+ //_MMU_write32[ARMCPU_ARM9](0x02007FFC, 0xE92D4030); |
|
| 2560 |
+ |
|
| 2561 |
+ delete header; |
|
| 2562 |
+ |
|
| 2563 |
+ //Screen_Reset(); |
|
| 2564 |
+ //gfx3d_reset(); |
|
| 2565 |
+ //gpu3D->NDS_3D_Reset(); |
|
| 2566 |
+ //slot1Reset(); |
|
| 2567 |
+ |
|
| 2568 |
+ //WIFI_Reset(); |
|
| 2569 |
+ |
|
| 2570 |
+ //memcpy(FW_Mac, (MMU.fw.data + 0x36), 6); |
|
| 2571 |
+ |
|
| 2572 |
+ initSchedule(); |
|
| 2573 |
+ |
|
| 2574 |
+ SPU_ReInit(); |
|
| 2575 |
+} |
|
| 2576 |
+ |
|
| 2577 |
+/*static std::string MakeInputDisplayString(uint16_t pad, const std::string* Buttons, int count) {
|
|
| 2578 |
+ std::string s; |
|
| 2579 |
+ for (int x = 0; x < count; x++) {
|
|
| 2580 |
+ if (pad & (1 << x)) |
|
| 2581 |
+ s.append(Buttons[x].size(), ' '); |
|
| 2582 |
+ else |
|
| 2583 |
+ s += Buttons[x]; |
|
| 2584 |
+ } |
|
| 2585 |
+ return s; |
|
| 2586 |
+}*/ |
|
| 2587 |
+ |
|
| 2588 |
+/*static std::string MakeInputDisplayString(uint16_t pad, uint16_t padExt) {
|
|
| 2589 |
+ const std::string Buttons[] = {"A", "B", "Sl", "St", "R", "L", "U", "D", "Rs", "Ls"};
|
|
| 2590 |
+ const std::string Ext[] = {"X", "Y"};
|
|
| 2591 |
+ |
|
| 2592 |
+ std::string s = MakeInputDisplayString(pad, Ext, ARRAY_SIZE(Ext)); |
|
| 2593 |
+ s += MakeInputDisplayString(padExt, Buttons, ARRAY_SIZE(Buttons)); |
|
| 2594 |
+ |
|
| 2595 |
+ return s; |
|
| 2596 |
+}*/ |
|
| 2597 |
+ |
|
| 2598 |
+ |
|
| 2599 |
+//buttonstruct<bool> Turbo; |
|
| 2600 |
+buttonstruct<int> TurboTime; |
|
| 2601 |
+//buttonstruct<bool> AutoHold; |
|
| 2602 |
+ |
|
| 2603 |
+/*void ClearAutoHold() {
|
|
| 2604 |
+ |
|
| 2605 |
+ for (uint32_t i=0; i < ARRAY_SIZE(AutoHold.array); i++) {
|
|
| 2606 |
+ AutoHold.array[i]=false; |
|
| 2607 |
+ } |
|
| 2608 |
+}*/ |
|
| 2609 |
+ |
|
| 2610 |
+ |
|
| 2611 |
+/*inline uint16_t NDS_getADCTouchPosX(uint16_t scrX) |
|
| 2612 |
+{
|
|
| 2613 |
+ // this is a little iffy, |
|
| 2614 |
+ // we're basically adjusting the ADC results to |
|
| 2615 |
+ // compensate for how they will be interpreted. |
|
| 2616 |
+ // the actual system doesn't do this transformation. |
|
| 2617 |
+ int rv = (scrX - TSCal.scr.x1 + 1) * TSCal.adc.width / TSCal.scr.width + TSCal.adc.x1; |
|
| 2618 |
+ rv = min(0xFFF, max(0, rv)); |
|
| 2619 |
+ return (uint16_t)rv; |
|
| 2620 |
+}*/ |
|
| 2621 |
+/*inline uint16_t NDS_getADCTouchPosY(uint16_t scrY) |
|
| 2622 |
+{
|
|
| 2623 |
+ int rv = (scrY - TSCal.scr.y1 + 1) * TSCal.adc.height / TSCal.scr.height + TSCal.adc.y1; |
|
| 2624 |
+ rv = min(0xFFF, max(0, rv)); |
|
| 2625 |
+ return (uint16_t)rv; |
|
| 2626 |
+}*/ |
|
| 2627 |
+ |
|
| 2628 |
+//static UserInput rawUserInput = {}; // requested input, generally what the user is physically pressing
|
|
| 2629 |
+static UserInput intermediateUserInput; // intermediate buffer for modifications (seperated from finalUserInput for safety reasons) |
|
| 2630 |
+static UserInput finalUserInput; // what gets sent to the game and possibly recorded |
|
| 2631 |
+bool validToProcessInput = false; |
|
| 2632 |
+ |
|
| 2633 |
+/*const UserInput& NDS_getRawUserInput() |
|
| 2634 |
+{
|
|
| 2635 |
+ return rawUserInput; |
|
| 2636 |
+}*/ |
|
| 2637 |
+/*UserInput& NDS_getProcessingUserInput() |
|
| 2638 |
+{
|
|
| 2639 |
+ assert(validToProcessInput); |
|
| 2640 |
+ return intermediateUserInput; |
|
| 2641 |
+}*/ |
|
| 2642 |
+/*bool NDS_isProcessingUserInput() |
|
| 2643 |
+{
|
|
| 2644 |
+ return validToProcessInput; |
|
| 2645 |
+}*/ |
|
| 2646 |
+/*const UserInput& NDS_getFinalUserInput() |
|
| 2647 |
+{
|
|
| 2648 |
+ return finalUserInput; |
|
| 2649 |
+}*/ |
|
| 2650 |
+ |
|
| 2651 |
+ |
|
| 2652 |
+/*static void saveUserInput(EMUFILE* os, UserInput& input) |
|
| 2653 |
+{
|
|
| 2654 |
+ os->fwrite((const char*)input.buttons.array, 14); |
|
| 2655 |
+ writebool(input.touch.isTouch, os); |
|
| 2656 |
+ write16le(input.touch.touchX, os); |
|
| 2657 |
+ write16le(input.touch.touchY, os); |
|
| 2658 |
+ write32le(input.mic.micButtonPressed, os); |
|
| 2659 |
+}*/ |
|
| 2660 |
+static bool loadUserInput(EMUFILE* is, UserInput& input, int) |
|
| 2661 |
+{
|
|
| 2662 |
+ is->fread((char*)input.buttons.array, 14); |
|
| 2663 |
+ readbool(&input.touch.isTouch, is); |
|
| 2664 |
+ read16le(&input.touch.touchX, is); |
|
| 2665 |
+ read16le(&input.touch.touchY, is); |
|
| 2666 |
+ read32le(&input.mic.micButtonPressed, is); |
|
| 2667 |
+ return true; |
|
| 2668 |
+} |
|
| 2669 |
+/*static void resetUserInput(UserInput& input) |
|
| 2670 |
+{
|
|
| 2671 |
+ memset(&input, 0, sizeof(UserInput)); |
|
| 2672 |
+}*/ |
|
| 2673 |
+// (userinput is kind of a misnomer, e.g. finalUserInput has to mirror nds.pad, nds.touchX, etc.) |
|
| 2674 |
+/*static void saveUserInput(EMUFILE* os) |
|
| 2675 |
+{
|
|
| 2676 |
+ saveUserInput(os, finalUserInput); |
|
| 2677 |
+ saveUserInput(os, intermediateUserInput); // saved in case a savestate is made during input processing (which Lua could do if nothing else) |
|
| 2678 |
+ writebool(validToProcessInput, os); |
|
| 2679 |
+ for(int i = 0; i < 14; i++) |
|
| 2680 |
+ write32le(TurboTime.array[i], os); // saved to make autofire more tolerable to use with re-recording |
|
| 2681 |
+}*/ |
|
| 2682 |
+static bool loadUserInput(EMUFILE* is, int version) |
|
| 2683 |
+{
|
|
| 2684 |
+ bool rv = true; |
|
| 2685 |
+ rv &= loadUserInput(is, finalUserInput, version); |
|
| 2686 |
+ rv &= loadUserInput(is, intermediateUserInput, version); |
|
| 2687 |
+ readbool(&validToProcessInput, is); |
|
| 2688 |
+ for(int i = 0; i < 14; i++) |
|
| 2689 |
+ read32le((uint32_t*)&TurboTime.array[i], is); |
|
| 2690 |
+ return rv; |
|
| 2691 |
+} |
|
| 2692 |
+/*static void resetUserInput() |
|
| 2693 |
+{
|
|
| 2694 |
+ resetUserInput(finalUserInput); |
|
| 2695 |
+ resetUserInput(intermediateUserInput); |
|
| 2696 |
+}*/ |
|
| 2697 |
+ |
|
| 2698 |
+/*static inline void gotInputRequest() |
|
| 2699 |
+{
|
|
| 2700 |
+ // nobody should set the raw input while we're processing the input. |
|
| 2701 |
+ // it might not screw anything up but it would be completely useless. |
|
| 2702 |
+ assert(!validToProcessInput); |
|
| 2703 |
+}*/ |
|
| 2704 |
+ |
|
| 2705 |
+/*void NDS_setPad(bool R,bool L,bool D,bool U,bool T,bool S,bool B,bool A,bool Y,bool X,bool W,bool E,bool G, bool F) |
|
| 2706 |
+{
|
|
| 2707 |
+ gotInputRequest(); |
|
| 2708 |
+ UserButtons& rawButtons = rawUserInput.buttons; |
|
| 2709 |
+ rawButtons.R = R; |
|
| 2710 |
+ rawButtons.L = L; |
|
| 2711 |
+ rawButtons.D = D; |
|
| 2712 |
+ rawButtons.U = U; |
|
| 2713 |
+ rawButtons.T = T; |
|
| 2714 |
+ rawButtons.S = S; |
|
| 2715 |
+ rawButtons.B = B; |
|
| 2716 |
+ rawButtons.A = A; |
|
| 2717 |
+ rawButtons.Y = Y; |
|
| 2718 |
+ rawButtons.X = X; |
|
| 2719 |
+ rawButtons.W = W; |
|
| 2720 |
+ rawButtons.E = E; |
|
| 2721 |
+ rawButtons.G = G; |
|
| 2722 |
+ rawButtons.F = F; |
|
| 2723 |
+}*/ |
|
| 2724 |
+/*void NDS_setTouchPos(uint16_t x, uint16_t y) |
|
| 2725 |
+{
|
|
| 2726 |
+ gotInputRequest(); |
|
| 2727 |
+ rawUserInput.touch.touchX = NDS_getADCTouchPosX(x); |
|
| 2728 |
+ rawUserInput.touch.touchY = NDS_getADCTouchPosY(y); |
|
| 2729 |
+ rawUserInput.touch.isTouch = true;*/ |
|
| 2730 |
+ |
|
| 2731 |
+ /*if(movieMode != MOVIEMODE_INACTIVE && movieMode != MOVIEMODE_FINISHED) |
|
| 2732 |
+ {
|
|
| 2733 |
+ // just in case, since the movie only stores 8 bits per touch coord |
|
| 2734 |
+ rawUserInput.touch.touchX &= 0x0FF0; |
|
| 2735 |
+ rawUserInput.touch.touchY &= 0x0FF0; |
|
| 2736 |
+ }*/ |
|
| 2737 |
+/* |
|
| 2738 |
+#ifndef WIN32 |
|
| 2739 |
+ // FIXME: this code should be deleted from here, |
|
| 2740 |
+ // other platforms should call NDS_beginProcessingInput,NDS_endProcessingInput once per frame instead |
|
| 2741 |
+ // (see the function called "StepRunLoop_Core" in src/windows/main.cpp), |
|
| 2742 |
+ // but I'm leaving this here for now since I can't test those other platforms myself. |
|
| 2743 |
+ nds.touchX = rawUserInput.touch.touchX; |
|
| 2744 |
+ nds.touchY = rawUserInput.touch.touchY; |
|
| 2745 |
+ nds.isTouch = 1; |
|
| 2746 |
+ MMU.ARM7_REG[0x136] &= 0xBF; |
|
| 2747 |
+#endif |
|
| 2748 |
+}*/ |
|
| 2749 |
+/*void NDS_releaseTouch() |
|
| 2750 |
+{
|
|
| 2751 |
+ gotInputRequest(); |
|
| 2752 |
+ rawUserInput.touch.touchX = 0; |
|
| 2753 |
+ rawUserInput.touch.touchY = 0; |
|
| 2754 |
+ rawUserInput.touch.isTouch = false; |
|
| 2755 |
+ |
|
| 2756 |
+#ifndef WIN32 |
|
| 2757 |
+ // FIXME: this code should be deleted from here, |
|
| 2758 |
+ // other platforms should call NDS_beginProcessingInput,NDS_endProcessingInput once per frame instead |
|
| 2759 |
+ // (see the function called "StepRunLoop_Core" in src/windows/main.cpp), |
|
| 2760 |
+ // but I'm leaving this here for now since I can't test those other platforms myself. |
|
| 2761 |
+ nds.touchX = 0; |
|
| 2762 |
+ nds.touchY = 0; |
|
| 2763 |
+ nds.isTouch = 0; |
|
| 2764 |
+ MMU.ARM7_REG[0x136] |= 0x40; |
|
| 2765 |
+#endif |
|
| 2766 |
+}*/ |
|
| 2767 |
+/*void NDS_setMic(bool pressed) |
|
| 2768 |
+{
|
|
| 2769 |
+ gotInputRequest(); |
|
| 2770 |
+ rawUserInput.mic.micButtonPressed = (pressed ? true : false); |
|
| 2771 |
+}*/ |
|
| 2772 |
+ |
|
| 2773 |
+ |
|
| 2774 |
+//static void NDS_applyFinalInput(); |
|
| 2775 |
+ |
|
| 2776 |
+ |
|
| 2777 |
+/*void NDS_beginProcessingInput() |
|
| 2778 |
+{
|
|
| 2779 |
+ // start off from the raw input |
|
| 2780 |
+ intermediateUserInput = rawUserInput; |
|
| 2781 |
+ |
|
| 2782 |
+ // processing is valid now |
|
| 2783 |
+ validToProcessInput = true; |
|
| 2784 |
+}*/ |
|
| 2785 |
+ |
|
| 2786 |
+/*void NDS_endProcessingInput() |
|
| 2787 |
+{
|
|
| 2788 |
+ // transfer the processed input |
|
| 2789 |
+ finalUserInput = intermediateUserInput; |
|
| 2790 |
+ |
|
| 2791 |
+ // processing is invalid now |
|
| 2792 |
+ validToProcessInput = false; |
|
| 2793 |
+ |
|
| 2794 |
+ // use the final input for a few things right away |
|
| 2795 |
+ NDS_applyFinalInput(); |
|
| 2796 |
+}*/ |
|
| 2797 |
+ |
|
| 2798 |
+ |
|
| 2799 |
+ |
|
| 2800 |
+ |
|
| 2801 |
+ |
|
| 2802 |
+ |
|
| 2803 |
+ |
|
| 2804 |
+ |
|
| 2805 |
+/*static void NDS_applyFinalInput() |
|
| 2806 |
+{
|
|
| 2807 |
+ const UserInput& input = NDS_getFinalUserInput(); |
|
| 2808 |
+ |
|
| 2809 |
+ uint16_t pad = (0 | |
|
| 2810 |
+ ((input.buttons.A ? 0 : 0x80) >> 7) | |
|
| 2811 |
+ ((input.buttons.B ? 0 : 0x80) >> 6) | |
|
| 2812 |
+ ((input.buttons.T ? 0 : 0x80) >> 5) | |
|
| 2813 |
+ ((input.buttons.S ? 0 : 0x80) >> 4) | |
|
| 2814 |
+ ((input.buttons.R ? 0 : 0x80) >> 3) | |
|
| 2815 |
+ ((input.buttons.L ? 0 : 0x80) >> 2) | |
|
| 2816 |
+ ((input.buttons.U ? 0 : 0x80) >> 1) | |
|
| 2817 |
+ ((input.buttons.D ? 0 : 0x80) ) | |
|
| 2818 |
+ ((input.buttons.E ? 0 : 0x80) << 1) | |
|
| 2819 |
+ ((input.buttons.W ? 0 : 0x80) << 2)) ; |
|
| 2820 |
+ |
|
| 2821 |
+ ((uint16_t *)MMU.ARM9_REG)[0x130>>1] = (uint16_t)pad; |
|
| 2822 |
+ ((uint16_t *)MMU.ARM7_REG)[0x130>>1] = (uint16_t)pad; |
|
| 2823 |
+ |
|
| 2824 |
+ uint16_t k_cnt = ((uint16_t *)MMU.ARM9_REG)[0x132>>1]; |
|
| 2825 |
+ if ( k_cnt & (1<<14)) |
|
| 2826 |
+ {
|
|
| 2827 |
+ //INFO("ARM9: KeyPad IRQ (pad 0x%04X, cnt 0x%04X (condition %s))\n", pad, k_cnt, k_cnt&(1<<15)?"AND":"OR");
|
|
| 2828 |
+ uint16_t k_cnt_selected = (k_cnt & 0x3F); |
|
| 2829 |
+ if (k_cnt&(1<<15)) // AND |
|
| 2830 |
+ {
|
|
| 2831 |
+ if ((~pad & k_cnt_selected) == k_cnt_selected) NDS_makeIrq(ARMCPU_ARM9,IRQ_BIT_KEYPAD); |
|
| 2832 |
+ } |
|
| 2833 |
+ else // OR |
|
| 2834 |
+ {
|
|
| 2835 |
+ if (~pad & k_cnt_selected) NDS_makeIrq(ARMCPU_ARM9,IRQ_BIT_KEYPAD); |
|
| 2836 |
+ } |
|
| 2837 |
+ } |
|
| 2838 |
+ |
|
| 2839 |
+ k_cnt = ((uint16_t *)MMU.ARM7_REG)[0x132>>1]; |
|
| 2840 |
+ if ( k_cnt & (1<<14)) |
|
| 2841 |
+ {
|
|
| 2842 |
+ //INFO("ARM7: KeyPad IRQ (pad 0x%04X, cnt 0x%04X (condition %s))\n", pad, k_cnt, k_cnt&(1<<15)?"AND":"OR");
|
|
| 2843 |
+ uint16_t k_cnt_selected = (k_cnt & 0x3F); |
|
| 2844 |
+ if (k_cnt&(1<<15)) // AND |
|
| 2845 |
+ {
|
|
| 2846 |
+ if ((~pad & k_cnt_selected) == k_cnt_selected) NDS_makeIrq(ARMCPU_ARM7,IRQ_BIT_KEYPAD); |
|
| 2847 |
+ } |
|
| 2848 |
+ else // OR |
|
| 2849 |
+ {
|
|
| 2850 |
+ if (~pad & k_cnt_selected) NDS_makeIrq(ARMCPU_ARM7,IRQ_BIT_KEYPAD); |
|
| 2851 |
+ } |
|
| 2852 |
+ } |
|
| 2853 |
+ |
|
| 2854 |
+ |
|
| 2855 |
+ if(input.touch.isTouch) |
|
| 2856 |
+ {
|
|
| 2857 |
+ nds.touchX = input.touch.touchX; |
|
| 2858 |
+ nds.touchY = input.touch.touchY; |
|
| 2859 |
+ nds.isTouch = 1; |
|
| 2860 |
+ |
|
| 2861 |
+ MMU.ARM7_REG[0x136] &= 0xBF; |
|
| 2862 |
+ } |
|
| 2863 |
+ else |
|
| 2864 |
+ {
|
|
| 2865 |
+ |
|
| 2866 |
+ nds.touchX = 0; |
|
| 2867 |
+ nds.touchY = 0; |
|
| 2868 |
+ nds.isTouch = 0; |
|
| 2869 |
+ |
|
| 2870 |
+ MMU.ARM7_REG[0x136] |= 0x40; |
|
| 2871 |
+ } |
|
| 2872 |
+ |
|
| 2873 |
+ |
|
| 2874 |
+ if (input.buttons.F && !countLid) |
|
| 2875 |
+ {
|
|
| 2876 |
+ LidClosed = (!LidClosed) & 0x01; |
|
| 2877 |
+ if (!LidClosed) |
|
| 2878 |
+ {
|
|
| 2879 |
+ // SPU_Pause(false); |
|
| 2880 |
+ NDS_makeIrq(ARMCPU_ARM7,IRQ_BIT_ARM7_FOLD); |
|
| 2881 |
+ |
|
| 2882 |
+ } |
|
| 2883 |
+ //else |
|
| 2884 |
+ //SPU_Pause(true); |
|
| 2885 |
+ |
|
| 2886 |
+ countLid = 30; |
|
| 2887 |
+ } |
|
| 2888 |
+ else |
|
| 2889 |
+ {
|
|
| 2890 |
+ if (countLid > 0) |
|
| 2891 |
+ countLid--; |
|
| 2892 |
+ } |
|
| 2893 |
+ |
|
| 2894 |
+ uint16_t padExt = (((uint16_t *)MMU.ARM7_REG)[0x136>>1] & 0x0070) | |
|
| 2895 |
+ ((input.buttons.X ? 0 : 0x80) >> 7) | |
|
| 2896 |
+ ((input.buttons.Y ? 0 : 0x80) >> 6) | |
|
| 2897 |
+ ((input.buttons.G ? 0 : 0x80) >> 4) | |
|
| 2898 |
+ ((LidClosed) << 7) | |
|
| 2899 |
+ 0x0034; |
|
| 2900 |
+ |
|
| 2901 |
+ ((uint16_t *)MMU.ARM7_REG)[0x136>>1] = (uint16_t)padExt; |
|
| 2902 |
+ |
|
| 2903 |
+ InputDisplayString=MakeInputDisplayString(padExt, pad); |
|
| 2904 |
+ |
|
| 2905 |
+ //put into the format we want for the movie system |
|
| 2906 |
+ //fRLDUTSBAYXWEg |
|
| 2907 |
+ //we don't really need nds.pad anymore, but removing it would be a pain |
|
| 2908 |
+ |
|
| 2909 |
+ nds.pad = |
|
| 2910 |
+ ((input.buttons.R ? 1 : 0) << 12)| |
|
| 2911 |
+ ((input.buttons.L ? 1 : 0) << 11)| |
|
| 2912 |
+ ((input.buttons.D ? 1 : 0) << 10)| |
|
| 2913 |
+ ((input.buttons.U ? 1 : 0) << 9)| |
|
| 2914 |
+ ((input.buttons.T ? 1 : 0) << 8)| |
|
| 2915 |
+ ((input.buttons.S ? 1 : 0) << 7)| |
|
| 2916 |
+ ((input.buttons.B ? 1 : 0) << 6)| |
|
| 2917 |
+ ((input.buttons.A ? 1 : 0) << 5)| |
|
| 2918 |
+ ((input.buttons.Y ? 1 : 0) << 4)| |
|
| 2919 |
+ ((input.buttons.X ? 1 : 0) << 3)| |
|
| 2920 |
+ ((input.buttons.W ? 1 : 0) << 2)| |
|
| 2921 |
+ ((input.buttons.E ? 1 : 0) << 1); |
|
| 2922 |
+ |
|
| 2923 |
+ // TODO: low power IRQ |
|
| 2924 |
+}*/ |
|
| 2925 |
+ |
|
| 2926 |
+ |
|
| 2927 |
+/*void NDS_suspendProcessingInput(bool suspend) |
|
| 2928 |
+{
|
|
| 2929 |
+ static int suspendCount = 0; |
|
| 2930 |
+ if(suspend) |
|
| 2931 |
+ {
|
|
| 2932 |
+ // enter non-processing block |
|
| 2933 |
+ assert(validToProcessInput); |
|
| 2934 |
+ validToProcessInput = false; |
|
| 2935 |
+ suspendCount++; |
|
| 2936 |
+ } |
|
| 2937 |
+ else if(suspendCount) |
|
| 2938 |
+ {
|
|
| 2939 |
+ // exit non-processing block |
|
| 2940 |
+ validToProcessInput = true; |
|
| 2941 |
+ suspendCount--; |
|
| 2942 |
+ } |
|
| 2943 |
+ else |
|
| 2944 |
+ {
|
|
| 2945 |
+ // unwound past first time -> not processing |
|
| 2946 |
+ validToProcessInput = false; |
|
| 2947 |
+ } |
|
| 2948 |
+}*/ |
|
| 2949 |
+ |
|
| 2950 |
+ |
|
| 2951 |
+/*void emu_halt() {
|
|
| 2952 |
+ //printf("halting emu: ARM9 PC=%08X/%08X, ARM7 PC=%08X/%08X\n", NDS_ARM9.R[15], NDS_ARM9.instruct_adr, NDS_ARM7.R[15], NDS_ARM7.instruct_adr);
|
|
| 2953 |
+ execute = false; |
|
| 2954 |
+#ifdef LOG_ARM9 |
|
| 2955 |
+ if (fp_dis9) |
|
| 2956 |
+ {
|
|
| 2957 |
+ char buf[256] = { 0 };
|
|
| 2958 |
+ sprintf(buf, "halting emu: ARM9 PC=%08X/%08X\n", NDS_ARM9.R[15], NDS_ARM9.instruct_adr); |
|
| 2959 |
+ fwrite(buf, 1, strlen(buf), fp_dis9); |
|
| 2960 |
+ INFO("ARM9 halted\n");
|
|
| 2961 |
+ } |
|
| 2962 |
+#endif |
|
| 2963 |
+ |
|
| 2964 |
+#ifdef LOG_ARM7 |
|
| 2965 |
+ if (fp_dis7) |
|
| 2966 |
+ {
|
|
| 2967 |
+ char buf[256] = { 0 };
|
|
| 2968 |
+ sprintf(buf, "halting emu: ARM7 PC=%08X/%08X\n", NDS_ARM7.R[15], NDS_ARM7.instruct_adr); |
|
| 2969 |
+ fwrite(buf, 1, strlen(buf), fp_dis7); |
|
| 2970 |
+ INFO("ARM7 halted\n");
|
|
| 2971 |
+ } |
|
| 2972 |
+#endif |
|
| 2973 |
+}*/ |
|
| 2974 |
+ |
|
| 2975 |
+//returns true if exmemcnt specifies satisfactory parameters for the device, which calls this function |
|
| 2976 |
+/*bool ValidateSlot2Access(uint32_t procnum, uint32_t demandSRAMSpeed, uint32_t demand1stROMSpeed, uint32_t demand2ndROMSpeed, int clockbits) |
|
| 2977 |
+{
|
|
| 2978 |
+ static const uint32_t _sramSpeeds[] = {10,8,6,18};
|
|
| 2979 |
+ static const uint32_t _rom1Speeds[] = {10,8,6,18};
|
|
| 2980 |
+ static const uint32_t _rom2Speeds[] = {6,4};
|
|
| 2981 |
+ uint16_t exmemcnt = T1ReadWord(MMU.MMU_MEM[procnum][0x40], 0x204); |
|
| 2982 |
+ uint16_t exmemcnt9 = T1ReadWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x204); |
|
| 2983 |
+ uint32_t arm7access = (exmemcnt9 & EXMEMCNT_MASK_SLOT2_ARM7); |
|
| 2984 |
+ uint32_t sramSpeed = _sramSpeeds[(exmemcnt & EXMEMCNT_MASK_SLOT2_SRAM_TIME)]; |
|
| 2985 |
+ uint32_t romSpeed1 = _rom1Speeds[(exmemcnt & EXMEMCNT_MASK_SLOT2_ROM_1ST_TIME)>>2]; |
|
| 2986 |
+ uint32_t romSpeed2 = _rom2Speeds[(exmemcnt & EXMEMCNT_MASK_SLOT2_ROM_2ND_TIME)>>4]; |
|
| 2987 |
+ uint32_t curclockbits = (exmemcnt & EXMEMCNT_MASK_SLOT2_CLOCKRATE)>>5; |
|
| 2988 |
+ |
|
| 2989 |
+ if(procnum==ARMCPU_ARM9 && arm7access) return false; |
|
| 2990 |
+ if(procnum==ARMCPU_ARM7 && !arm7access) return false; |
|
| 2991 |
+ |
|
| 2992 |
+ //what we're interested in here is whether the rom/ram are too low -> too fast. then accesses won't have enough time to work. |
|
| 2993 |
+ //i'm not sure if this gives us enough flexibility, but it is good enough for now. |
|
| 2994 |
+ //should make the arguments to this function bitmasks later if we need better. |
|
| 2995 |
+ if(sramSpeed < demandSRAMSpeed) return false; |
|
| 2996 |
+ if(romSpeed1 < demand1stROMSpeed) return false; |
|
| 2997 |
+ if(romSpeed2 < demand2ndROMSpeed) return false; |
|
| 2998 |
+ |
|
| 2999 |
+ if(clockbits != -1 && clockbits != (int)curclockbits) return false; |
|
| 3000 |
+ |
|
| 3001 |
+ return true; |
|
| 3002 |
+}*/ |
|
| 3003 |
+ |
|
| 3004 |
+//these templates needed to be instantiated manually |
|
| 3005 |
+template void NDS_exec<false>(int32_t nb); |
|
| 3006 |
+template void NDS_exec<true>(int32_t nb); |