gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

Coding > Detect no$gba?

#141110 - Dwedit - Sat Sep 22, 2007 6:25 am

How do I detect the presence of no$gba?
_________________
"We are merely sprites that dance at the beck and call of our button pressing overlord."

#141115 - gladius - Sat Sep 22, 2007 8:05 am

Specifically? Or just emulators in general?

Emulators in general, you can use the fact that nobody emulates the pipeline correctly, so something like this will work:

Code:

isRealHardware:
ldr r1, =tmp
mov r0, #0
str r0, [r1]
tmp:
mov r0, #1
bx lr


The idea here is that the emulator will replace tmp with a nop, while on the real hardware, the instruction will already be in the pipeline and get executed.

#141121 - Peter - Sat Sep 22, 2007 9:31 am

Dwedit wrote:
How do I detect the presence of no$gba?

In No$gba Setup, under the Debug page is an option for emulator identification:
Emulator Identification wrote:

Register R0=CA5h on startup

Since it's only during startup, you probably have to extend your ctr0.s.
_________________
Kind Regards,
Peter

#141157 - tepples - Sat Sep 22, 2007 7:15 pm

Dwedit wrote:
How do I detect the presence of no$gba?

dir /s /b no$gba.exe

I'll assume Dwedit wrote:
How do I write a program that detects whether it is running inside no$gba?

Why? To pull a Demotronic or a WGA and make your projects not work on emulators? Where possible, sniffing behaviors is more reliable than sniffing brands, so what behavior of NO$GBA do you wish to distinguish from that of Game Boy Advance or Nintendo DS hardware? Or do you just want to put "on NO$GBA" at the bottom of PocketNES's menu, like you do for GBA, DS, or unknown BIOS?

gladius wrote:
Code:
isRealHardware:

Reminds me of those old four lines of assembly language to detect Nesticle's buggy vblank handler.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#141210 - Dwedit - Sun Sep 23, 2007 5:25 am

Mainly it's to have it run in NO$GBA without having annoying "Write to Read Only Memory" messages popping up when I probe for the presence of a GBAMP. Also I like to distinguish NO$GBA from other emulators since NO$GBA only provides 32k of SRAM.

(NO$GBA also fails to emulate sprite blend mode correctly, but that's another story)
_________________
"We are merely sprites that dance at the beck and call of our button pressing overlord."

#141333 - gladius - Mon Sep 24, 2007 5:22 am

tepples wrote:
Reminds me of those old four lines of assembly language to detect Nesticle's buggy vblank handler.

Actually, we can beat that, using pc-relative addressing:
Code:

isRealHardware:
mov r0, #0
str r0, [pc, #-4]
mov r0, #1
bx lr

Not counting the bx lr, that's only 3 instructions to detect emulators. Not nearly as serious as firing the vblank handler all the time though :).

#141335 - Dwedit - Mon Sep 24, 2007 5:48 am

Do the GBA emulators still fall for such an obvious check if the instructions are prefetched?
_________________
"We are merely sprites that dance at the beck and call of our button pressing overlord."

#141337 - wintermute - Mon Sep 24, 2007 7:05 am

Dwedit wrote:
Do the GBA emulators still fall for such an obvious check if the instructions are prefetched?


Yes, emulating a pipeline is slow and doesn't change accuracy.

You know you can disable those warning messages in no$gba?
_________________
devkitPro - professional toolchains at amateur prices
devkitPro IRC support
Personal Blog

#141376 - tepples - Mon Sep 24, 2007 8:42 pm

Dwedit wrote:
Mainly it's to have it run in NO$GBA without having annoying "Write to Read Only Memory" messages popping up when I probe for the presence of a GBAMP.

There are a few situations you have to distinguish:
  1. Running from RAM, using appended file system (e.g. MBV2 or XBOO cable, compy builds, or GBAMP version 2 firmware's automatic compilation generator)
  2. Running from RAM, using CF interface (GBAMP version 2)
  3. Running from ROM, using appended file system (NOR cards, NAND cards with compilations, or NAND cards using flash card firmware's automatic compilation generator)
  4. Running from ROM, using CF interface (possibly with GBAMP version 3)
  5. Running from RAM, using a file in ROM (using emulator under PogoShell)

You're using the GBAMP in situation 2 and the PC-based emulator in situation 3, right? You can distinguish 1 and 2 from 3 and 4 by saving the initial program counter before you copy the emulator engine down to EWRAM and IWRAM. Or if the ROM title in the GBA header matches the ROM title in RAM, then you're probably not running on a GBAMP.

Quote:
Also I like to distinguish NO$GBA from other emulators since NO$GBA only provides 32k of SRAM.

Read 0x0E007FFF and 0x0E00FFFF; if changing one changes the other, you have 32 KiB of SRAM. Some versions of PocketNES, designed for use with an XBOO cable and a GBA Game Pak, have called this situation "SRAM cannibalism mode".
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#144647 - HyperHacker - Mon Nov 05, 2007 10:38 am

Mind the bump, but if you want to detect a GBAMP, couldn't you just check if the GBA ROM title is "GBAMP Hack"? (You could check for the non-hacked title too, but I doubt anyone is using a GBAMP for homebrew without hacking it. <_<)
_________________
I'm a PSP hacker now, but I still <3 DS.

#151034 - PadrinatoR - Sun Feb 17, 2008 4:11 pm

gladius wrote:
Specifically? Or just emulators in general?

Emulators in general, you can use the fact that nobody emulates the pipeline correctly, so something like this will work:

Code:

isRealHardware:
ldr r1, =tmp
mov r0, #0
str r0, [r1]
tmp:
mov r0, #1
bx lr


The idea here is that the emulator will replace tmp with a nop, while on the real hardware, the instruction will already be in the pipeline and get executed.


Sorry if it's a noob question but... how do I use that?
I've created a .s file and pasted that code on it, but now how can I use that code?

Thank you in advance :)

Bye!
_________________
DSAmp: control Winamp with your Nintendo DS

#151042 - tepples - Sun Feb 17, 2008 5:20 pm

HyperHacker wrote:
(You could check for the non-hacked title too, but I doubt anyone is using a GBAMP for homebrew without hacking it. <_<)

Why would you hack it if you don't have a Nintendo DS or Nintendo DS Lite? Plenty of people on Lik-Sang forums used GBAMP for movies, music, and etexts on a Game Boy Advance SP, with an occasional round of Luminesweeper or something.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#151068 - strager - Mon Feb 18, 2008 2:45 am

PadrinatoR wrote:
gladius wrote:
Code:

isRealHardware:
ldr r1, =tmp
mov r0, #0
str r0, [r1]
tmp:
mov r0, #1
bx lr



Sorry if it's a noob question but... how do I use that?
I've created a .s file and pasted that code on it, but now how can I use that code?

Thank you in advance :)

Bye!


In a header file:

Code:
// isrealhardware.h
#ifndef __ISREALHARDWARE_H__
#define __ISREALHARDWARE_H__

#ifdef __cplusplus
extern "C" {
#endif

extern int isRealHardware(void);

#ifndef __cplusplus
}
#endif

#endif


Usage:

Code:
if(isRealHardware())
    printf("DS hardware detected\n");


That should work. Be sure the .s is compiled and linked! Also, add the following lines at the beginning of the .s file:

Code:
.arm
.align
.global isRealHardware


[/untested]

#151082 - PadrinatoR - Mon Feb 18, 2008 4:54 pm

Thank you strager, it compiled :D But it always says that I'm using an emulator. I've tested both version (the one I quoted in my last post and the other one) :S

What's happening? :S
_________________
DSAmp: control Winamp with your Nintendo DS

#151097 - wintermute - Mon Feb 18, 2008 10:49 pm

Works fine for me, I modified the code slightly to stop no$ moaning about meaningless opcodes and avoid the entry in the literal pool though.

The assembly code.

Code:

   .text
   .arm

   .global   isHardware
isHardware:
   adr r1, tmp + 2
   mov r0, #0
   strh r0, [r1]
tmp:
   mov r0, #1
   bx lr


C/C+ source

Code:

#include <nds.h>
#include <stdio.h>


extern "C" bool isHardware();

int main() {


   irqInit();
   irqEnable(IRQ_VBLANK);

   consoleDemoInit();
   
   printf("I'm running on a%s\n", isHardware() ? " real DS!" :"n emulator!" );

   while(1) swiWaitForVBlank();
}


Built project http://www.devkitpro.org/files/isHardware.zip
_________________
devkitPro - professional toolchains at amateur prices
devkitPro IRC support
Personal Blog

#151098 - PadrinatoR - Mon Feb 18, 2008 11:09 pm

Thank you very much wintermute!

It seems like I should call this function at the beginning of my application, if I call it later it always returns false.

Well, it works now, thank you again :D
_________________
DSAmp: control Winamp with your Nintendo DS

#151102 - tepples - Tue Feb 19, 2008 12:02 am

Are you sure you want this to go in .text, which on the GBA is likely to be ROM (or at least NOR flash)?
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#151104 - Fling - Tue Feb 19, 2008 12:29 am

PadrinatoR wrote:
It seems like I should call this function at the beginning of my application, if I call it later it always returns false.


Seems that this was the key for me as well. Thanks for pointing it out!

#151119 - wintermute - Tue Feb 19, 2008 11:49 am

PadrinatoR wrote:

It seems like I should call this function at the beginning of my application, if I call it later it always returns false.


That's a bit odd, what are you doing in the rest of the app? It might be an interrupt kicking in at just the wrong time. Try this instead.

Code:

   .section   .ewram,"ax",%progbits
   .arm

   .global   isHardware
@---------------------------------------------------------------------------------
isHardware:
@---------------------------------------------------------------------------------
   mov   r3, #0x4000000      @ REG_BASE
   ldr   r2, [r3, #0x208]   @ r2 = IME
   str   r3, [r3, #0x208]   @ disable IME
   adr r1, tmp + 2
   mov r0, #0
   strh r0, [r1]
   str   r2, [r3, #0x208]   @ restore IME
tmp:
   mov r0, #1
   bx lr


Failing that try .itcm instead of .ewram in the code above and add a long call attribute to the prototype.

Code:

extern "C" bool isHardware() __attribute__((long_call));




tepples wrote:
Are you sure you want this to go in .text, which on the GBA is likely to be ROM (or at least NOR flash)?


Well no, on GBA it obviously needs to be in RAM. The above code works fine there too but it needs the long_call attribute if the rest of the code is in ROM.
_________________
devkitPro - professional toolchains at amateur prices
devkitPro IRC support
Personal Blog

#151120 - kusma - Tue Feb 19, 2008 12:12 pm

Am I missing something obvious, or is it worth noting that this function should only work the first time you call it, since it modifies the actual code? Perhaps that was the problem PadrinatoR had?

#151125 - wintermute - Tue Feb 19, 2008 1:35 pm

good point, I didn't associate what Padrinator said with calling the function more than once.
_________________
devkitPro - professional toolchains at amateur prices
devkitPro IRC support
Personal Blog

#151127 - PadrinatoR - Tue Feb 19, 2008 2:49 pm

Yep, I called that function everywhere I need to check if it's real hardware or an emulator, I didn't think it could be a problem :S

Thank you for your help :D
I'm sorry about my English, I'm Spanish and my English is not so good ^_^'
_________________
DSAmp: control Winamp with your Nintendo DS

#151316 - gladius - Sat Feb 23, 2008 9:25 am

Hehe, I guess I should have put that caveat with the function. Also, instead of using the adr it can be done even smaller using pc-relative addressing (I posted this version on page 1).

Code:

isRealHardware:
mov r0, #0
str r0, [pc, #-4]
mov r0, #1
bx lr

#151321 - Dwedit - Sat Feb 23, 2008 11:16 am

Did VBA ever get around to emulating the prefetch?
_________________
"We are merely sprites that dance at the beck and call of our button pressing overlord."

#151329 - gmiller - Sat Feb 23, 2008 3:05 pm

The 1.8 version did but I had to fix it to get it to work (prefetch was not what I had to fix).