Showing posts with label dldi. Show all posts
Showing posts with label dldi. Show all posts

Thursday, August 06, 2020

Petits essais desmume

J'ai pris conscience il y a quelques jours que je n'avais toujours pas écrit de document présentant le fonctionnement de AnimEDS, pourtant lauréat du concours NeoFlash.

Du coup, comme j'ai un PC windows qui traine à la maison en ces temps confinés, j'ai
- re-téléchargé un desmume-0.9.11
- configuré le chargement des ROM en mode "load into RAM" (pour la compatibilité DLDI)
- ajusté le SLOT 1 pour émuler une R4 vers le répertoire "efsroot" de mon dernier tuto en date (auquel j'ai quand-même rajouté un sous-répertoire "moving", pour la forme).

ça suffit pour LEDS. Maintenant, voyons AnimEDS ...
 
Some days ago, I realised I still had no document describing how one would use my Animation Editor for Nintendo DS: AnimEDS, despite it is the only homebrew I had ever submitted to a coding compo. 
Since I have a windows PC at home during "lock down", I re-downloaded desmume-0.9.11 and went through the required "load into RAM" and setup SLOT 1 folder through the 'Config' menu . (yep, I'll be emulating an R4 on slot 1, this time). Contents of the folder will be that latest tutorial I uploaded on gbatemp. That worked for LEDS (packed with the tutorial), but not with AnimEDS.
 
PS: oui, j'ai bien lu: les gens derrière le projet Desmume recommandent plutôt de prendre un "nightly build" plutôt que les "stable build", mais ces derniers sont les seuls à ne pas faire grincer les dents de Winwin avec un auteur du logiciel non défini. On ne va pas tenter le diable, non plus.

Par contre, le dernier build que j'ai d'AnimEDS ne parvient pas à charger les fichiers .spr de la même manière. J'aurais dû m'en douter >_<.

Puis les vacances sont arrivées. J'ai pris un moment pour comprendre ce qui se passait, et pourquoi il fallait une combinaison "desmume/devkit" pour que ça coince. 
 
I should have guessed. I knew there's a compatibility issue between desmume 0.9+ and devkitpro's resources since I downloaded them back in 2018. So far, I just rebuilt stuff with my 'older' devkit (still running GCC 4.x >_<), but the laptop where I did that seems to be definitely damaged. Well. It's locked-down holiday time and the painting is drying on the walls, so I kicked up my debugger and started investigating what happened.
  • things work fine on a real Nintendo DS
  • things work fine with an old emulator
  • things work fine with an old devkit compiling nearly the same sources.
  • when things go wrong, we see that fatInitDefault fails. Yet it found the 'fat' device but it cannot mount it.
Et j'ai fini par me rendre compte que toutes les fonctions liées au DLDI pointaient vers la même fonction qui return false.

Je creuse encore et je me rends compte que les fichiers .nds qui marchent sont renseigné comme ayant un autre type de header que les .nds qui échouent. Et que le code de desmume a un test du type "taille du header < 16K" pour décider si il a affaire ou non à un homebrew.

When I realised that all the IO functions in the DLDI interface were pointing to the same code (actually just returning false), I started to be very suspicious about desmume's DLDI patching feature, and I re-downloaded its sources. While it was building, I noticed that the old-built-working .NDS and the new-built-failing .NDS were not reported similarly by the 'file' linux tool. And here's the catch:
  • desmume has some code checking whether it is running a homebrew before patching DLDI
  • that code only work for so-called 'old' (512-bytes) headers.
  • 'new' devkitpro tools use 'new' (16K) headers by default.
Visiblement, les "nouveaux" homebrews ne sont plus reconnus comme tels, et donc même plus candidats au patch DLDI. Heureusement, l'outil ndstool est toujours capable de faire des "vieux headers" (-h 0x200) en plus des "nouveaux headers" (par défaut, -h 0x4000).

Il faudra que je vérifie que ça marche aussi avec l'émulateur "tout frais" sous Windows, bien sûr, et que je me souvienne que je suis aller bricoler dans /opt/devkitpro/devkitARM/ds_rules ... un patch qui n'était pas indispensable puisque j'ai repris une règle équivalente dans mon common.mk.
Enfin, avec un peu de chance, je pourrai enfin faire mon tuto "comment utiliser AnimEDS" ;)

In devkitpro packages, there is a tool that convert .elf compiled files and into a single .nds ROM image: ndstool. Hopefully, it is still able to produce both types of headers, you just have to request it with -h argument. And luckily, I already had replaced the default makefile rule that uses ndstool in my own common.mk helper, so I don't need to mess with the contents of /opt/devkitpro to get working NDS files again... and be able to load contents in AnimEDS. Tuto-writing can at lasts start (as soon as the temperature drops under 30°C, that is)
 
Sounds like it was all over ? Well, there's a bit more of it. While I was debugging desmume, I trigger another issue that makes desmume-0.9.11 crash on my Ubuntu laptop when it encounter a symbolic link. A bit of bug hunt located a pretty trivial error in vfat.cpp. I'm proud to say that this is my first accepted pull request on a homebrew-related project ^_^ 
 
So
  • I need to use the desmume-cli version I recompiled (0.9.12)
  • desmume-cli --slot1 R4 --preload-rom --slot1-fat-dir FAKEROOT_DIR TOOL.NDS
  • with 0.9.11 (still what's shipped on Ubuntu 22.04 :P) I frequently use desmume-cli --load-type=1 --gbaslot-rom=DS/Dreams/Dreams.nds DS/Dreams/Dreams.nds --nojoy=1 to run standalone games.

Tuesday, November 26, 2019

FlatWorld : public iWorld

Bon, je laisse un instant les commentaires sur Ori et Link's Awakening de côté, les pixels studies et compagnie. Les enfants commencent à me demander s'ils peuvent essayer les niveaux dans la forêt de Bilou, et j'ai une idée un peu plus claire du moteur de jeu que je voudrais avoir pour pouvoir le réaliser.

La première étape va être de faire en sorte que les propriétés du niveau soient conservées dans un tableau séparé, plus dans l'emplacement réservé aux couleurs d'une des deux couches de graphismes (une des plus vieilles fausses-bonnes-idées du projet).

Il faudra adapter l'éditeur de niveaux, mais ce sera pour la deuxième étape. Avant ça, j'utiliserai un "extracteur automatique" pour les "vieilles" maps (comme celle de School Rush et Apple Assault).

Je vais essayer d'avoir un bon design de classe dès le départ ce coup-ci, avec un type pour les données du moteur physique, l'implémentation qui reste un détail et iWorld qui est le seul élément connu du reste du code.

It was about to be a post on how I'm refactoring the Map/World/Camera classes to support my new tile types plans. And then I wanted to quick-check what I had so far with School Rush and problems kicked-in. I couldn't get the debugger handling it properly on my old laptop, and when I tried a rebuild on my fairy's laptop with "latest" devkitPro, I just got a blue screen reminding me that I should have dropped EFS years ago as it is no longer supported by the devkit team. All the previous tricks I could remind of didn't help.

J'ai voulu réessayer de faire tourner ça dans SchoolRush pour voir, mais je n'arrive qu'à avoir un écran bleu quand je compile avec le "dernier" devkitpro. Un conflit avec EFS, semble-t-il ... ou bien j'ai fini par oublier comment je devais invoquer le programme, mais
  • ni --load-type=1 ne semble marcher
  • ni un build plus ancien
  • ni --cflash-path=SchoolTest (et recherche dans les fichiers)
Un premier problème que je parviens à identifier, c'est lseek(..., SEEK_END) qui renvoie -1. Pas bon, vu que le code d'efs va chercher à comparer la taille trouvée avec celle pré-enregistrée. Et si ça foire avec lseek, c'est apparemment parce que open("fat:/SchoolTest.nds") échoue avec un beau ENOENT ... pourtant ce nom provenait d'argv[0]. Bref, c'est de nouveau la saison des guru meditations...

Par contre, le commit précédent marchait sans problèmes sur 'grizzly', mon vieux laptop de 2007 qui utilise toujours un ancien devkitpro. Et mon nouveau code passe sans problème la découverte du système de fichiers embarqué quand il est compilé sur grizzly. Au point que j'en viens à me demander si j'ai jamais fait un build de SchoolRush sur le nouveau système... Fort peu probable, en fait vu que le système de highscores dépend du stylet (décembre 2018) alors que je n'ai corrigé le bug d'intégration du stylet avec le nouveau devkitpro que 6 mois plus tard.

Using the old desmume-cli on newest devkitpro and investigating with their libfatdir sample program, I'm tempted to say that --cflash-path=SchoolTest should have worked (it will work some hours laters for whatever reason -- typically meaning 'make clean' left some stuff dirty), and that the --gbaslot-rom thing is the one that is truly broken with the new devkitpro setup.

And I guess I was too tired to realise I was trying to remote-debug SchoolTest.nds using the LevelEditor.elf image ... So I'd better go to bed sooner tonight.

Je sens que je vais archiver le setup devkitpro de grizzly sur mon nuc-à-tout-faire, moi.
mais, en utilisant grizzly-desmume-cli --cflash-path=directory/to directory/to/SchoolTest.nds, je peux faire tourner le code (c'est l'implémentation pour "cartouche GBA" qui ne marche plus, apparemment).
et en débuggant ce code-là, il apparaît que le destructeur d'InfiniMap se voit appelé lors du premier getflags()... c'est supposé être un iWorld, mais il a une vtable de Vblcallback ...

Et si desmume sur grizzly ne se laissait pas débugger avec ddd c'est parce que ... J'avais chargé l'éditeur de niveau dans ddd pendant que l'émulateur tournait le moteur de jeu et SchoolRush. Eh oui. Je vous en prie, balancez votre vanne préférée sur la quarantaine dans les commentaires.

Tuesday, June 25, 2019

couldn't list the directory.

For some reason, recent desmume (0.9.11) shipped with my Ubuntu distro cannot list files in directories passed as --cflash-path.
and this time, my 'old version' of desmume binaries are 32-bit while the system is running a 64-bit OS. I had multiarch-support package installed, but not libc6:i386, nor libstdc++6:i386, and as a result, and I just had a weird message about the 'file not being found', while it was obviously there. Once those core packages had been installed, I got more coder-friendly error messages mentioning which library was missing, so I could just find the corresponding package with apt-file and install e.g. libsdl1.2debian:i386, libglib2.0-0:i386 and the like.

And eventually, I could run a copy of desmume-cli so old that --version isn't even supported :P 0.9.6 svnr3873 dev+, it says. And that one granted me with proper file loading, so I'll be able to investigate whether my edits on the extended monsters editions are OK or not ... next time.

(and no, this time adding --load-type=1 did not help)
(bug confirmed with filesystem/libfat/libfatdir example from devkitpro)

Tuesday, February 28, 2017

--load-type=1

It seems like I finally figured out why I had so much trouble with desmume on my new Linux. It's nice from desmume developers to warn me that DLDI would not work. Maybe it would have been nicer if using --cflash-path had automatically modified the load-type so that the tryPatch wouldn't segv while trying to operate on a NULL pointer...

Now, I'm ready to resume checking whether my mode-switching code is worth a push.


Bien ... il suffisait donc d'ajouter --load-type=1 sur la ligne de commande pour pouvoir utiliser l'émulation de carte mémoire avec desmume. Je suppose que j'aurais dû pouvoir le trouver sans faire de back-tracking à partir d'un émulateur en train de planter, mais c'est mon côté guru: plus à l'aise dans les sources que dans la doc.

Thursday, December 02, 2010

SYSTEM POWERED OFF VIA ARM7 SPI POWER DEVICE

sauf erreur de ma part, je parviens maintenant à avoir le code de runme qui tourne sur desmume (version 0.9.6-SVN) quand il est compilé avec en mode "dkp-r32". Par contre, si j'essaie d'utiliser les même outils pour AppleAssault, j'ai droit à un magnifique "SYSTEM POWERED OFF VIA ARM7 SPI POWER DEVICE". Je soupçonne desmume de couper froidement toute communication avec GDB quand ça se produit, ce qui, du coup, m'empêche d'en chercher la cause >_<

IPC9@201564a send FIFO < 0x480A725C -- size 000 (l 0x8505, tail 00) (r 0x8501, tail 05)
-- IRQ delivering.
IPC7@37ff16a recv FIFO > 0x480A725C -- size 000 (l 0x8401, tail 05) (r 0x8504, tail 01)
IPC9@201564a send FIFO < 0x04010040 -- size 000 (l 0x8505, tail 01) (r 0x8501, tail 08)
-- IRQ delivering.
IPC7@37ff16a recv FIFO > 0x04010040 -- size 000 (l 0x8401, tail 08) (r 0x8504, tail 02)

Evidemment, la version "standard" de desmume (0.9.5, livrée par Ubuntu), elle, coince à l'initialisation du Wifi, et ça ne vaut donc même pas la peine de continuer à chercher. Je vais donc devoir aller ajouter l'équivalent-émulateur d'un gurumediation dans le code de emu_halt(), voire y ajouter un DEBUG_dumpMemory() ...

I think I can now get runMe running under desmume when it is compiled with my 'dkp-r32' install. If do try to use the same tools for AppleAssault, I end up with an error message suggesting ARM7 powered off sometihng. I bet the emulator doesn't try to talk to GDB any further when that occurs. Let's see if I manage to get more information by adding something helping guru meditation in emu_halt() ... and later a 'magic' fake register that allows me to track evolution.

After exploration, it turns out that something is calling `abort()` before my exception catch-and-report code could kick in. And abort() may shut power down. All this occurs because I forgot command line argument --gbaslot-rom to let DLDI code access files.


Après modification, et si j'en crois mon nouvel outil, c'est au niveau de libnds_exit.c que le processeur ARM9 s'est arrèté, juste après un appel à powerOn, qui aurait été appelé quelque part à partir de fifosystem.c (dans la fonction waitBlock, ce qui me paraît on ne peut plus louche ...) Le processeur ARM7, lui, s'est bloqué au niveau de writePowerManagement appelé depuis powerValueHandler. Ca, au moins, c'est cohérent. Le dernier message transmis de l'ARM9 vers l'ARM7 est (poétiquement) un 0x04010040, ce que je peux décoder en:
  • 0xxx.xxxx : Channel 0 : power management
  • x4xx.xxxx : Immediate value (type=4)
  • xxx1.xxxx : PM_REQ_ON
  • xxxx.0040 : PM_SYSTEM_PWR (?...)
Ma foi, ça me semble être tout à fait la situation découlant d'un appel à systemShutdown, dernière opération de __libnds_exit() lorsque le "retour à hbmenu" a échoué :P Bref, heureusement, je m'étais donné un "faux registre" 0x04042000 pour envoyer des mots de 32 bits hors de l'émulateur ... ce qui m'amène à la conclusion que mon interception des exceptions C++ s'est fait court-circuiter par un appel "abort()" qui a ordonné la fin du programme ... grr. ... et derrière tout ça, l'oubli de --gbaslot-rom, désormais indispensable pour EFS sous desmume >_<.

Tuesday, May 04, 2010

0.7.3 > 0.9.4 > 0.9.5

Fin janvier, j'étais bloqué dans le développement de mon level editor. par un bug crapuleux de desmume 0.9.4 (version par défaut dans Karmic Koala) qui m'empèchait d'utiliser le touchscreen dans mes dernières productions. J'avais heureusement toujours les sources de la version 0.7.3 (qui, elle, fonctionne sans soucis de ce côté) sous la main.

Là, je viens de réinstaller Lucid Lynx sur Beetle et rebelote pour les soucis: l'EFS de Noda essaie de fonctionner en mode "DLDI" plutôt qu'en mode "GBA".

I'm stuck to desmume-cli version 0.7.3 on my Ubuntu alambics... Karmic Koala ships a 0.9.4 release that somehow ignores clicks on the touchscreen ... 0.9.5 shipped with Lucid Lynx is even worse: it seems to misunderstand EFS attempts to read the ROM file through GBA slot (a technique known as "NitroFS", afaik) and falls back to DLDI-powered crawl through a (non-existant) filesystem. I filed a bug report on the desmume sourceforge project ... Hope it'll be of some help.

Edit: some tip from Ludo: install 0.9.6 and use desmume-cli --gbaslot-rom=mybrew.nds mybrew.nds

Tuesday, September 08, 2009

Compacting Tilesheet

'faut que je me méfie: j'atteinds de nouveau des taux d'occupation de ma tilesheet assez hauts. Il y a encore de la place (les bilous de la tilesheet peuvent être remplacés), mais j'aimerais autant éviter le genre de problème que j'ai eu dans le passé.

Et une solution pour ça consisterait à pouvoir réutiliser le même tile dans plusieurs blocs. C'est clairement un atout dans les blocs de terre, qui commencent à devenir fort nombreux. J'ai déjà des algorithmes pour ça sur le PC (en PERL), reste à voir si je parviendrais à les transposer en C++ sur la DS... Si c'est le cas, je descendrais de près de 1000 tiles à 666. Pas trop mal.

(PS: oui, je sais, c'est crapuleux de redimensionner une image comme ça. C'est pour ne pas gâcher la découverte des améliorations)

I'm done with the behaviour of appleman for now. It isn't perfect yet, and he can't be defeated, but it will do the trick for the next milestone. So i've started packaging all this into a new gedsdemo.nds, a job that has been greatly simplified with the addition of Noda's EFS library (when i don't forget to patch the .nds i produce :P) i still have to make sure the background music (and SFX) are properly loaded, and fix things here and there on the maps, but the last 5% shouldn't account for too much work.

Mais le "packaging" progresse bien. Du moins j'ai une première approximation pour faire des snapshots. Je la joue "ambitieux", mais je vais tenter d'ajouter le petit mod de Pierrick, cette foi-ci. Il y a encore du boulot pour arranger les maps et comme d'habitude, je me bagarre avec l'EFS de Noda. Je te parie que j'ai oublié de patcher le .nds, tiens.

Pour simplifier, j'oublie régulièrement un élément ici ou là, et je modifies les sources sans les mains pendant que je berce ma p'tite puce.

Friday, July 04, 2008

I see Debug Sessions coming, darker than night itself ...

Well, patching the ARM9 stub when executing another .nds, that works. Fine. But now, i also need to ensure that the stub patches the binary. This is supposed to take place in LoadNDSArm9(), and the DLDIEnabled flag and DLDIStub themselves are found in some "magic" addresses in VRAM that need to match those used by exec.cpp in the calling program.

As far as i can tell, everything should work fine in that regards. I tweaked the stub a bit (yeah, now i manage to compile it properly ;) to make it halt before and after patching ... it all seems right, but for some reason, the freshly downloaded "runme" do not detect the presence of DLDI, nor does it manage to access FAT (of course :P)

// Copy the DLDI patch into the application
- memcpy (pAH, pDH, dldiFileSize);
+ memcpy (pAH, pDH, ddmemSize);
+ printf("%i bytes of driver copied\n",ddmemSize);

Hmm. Fortunately enough, i'm now fluent with diff and other revision control tools, so just checking what changed in my own copy of chishm's DLDI patcher (integrated to runme when it patches the stub) revealed a wrong memcpy that was using 0 bytes (dldiFileSize) instead of the just-computed driver size (ddmemSize). This affects v1.23 as far as i can tell, though i cannot guarantee this isn't just something odd in DSchannels' copy of the DLDI tool, as this is where my stuff comes from.

(this is usually where Beyond Infinity waved his towels in a "GG. Stay Safe.")

*fix*
*compile*
*snip -- getting the SD card out of the R4*
*copying files*
*snap -- pushing the SD card back in the R4*
*can't help to press "start" again and again while the device is booting*
*launching runme*
*updating runme*
*seems to work*
*yeah. indeed, it works ^_^*
*updating again, then launching LEDS, just for fun*

Okay, everything seems fine. So it was "just" my exec_stub.arm9 that was buggy. it's now in the CVS too ...

credits : chishm for the libfat and DLDI patchers -- EyeballKid for DSlurper/happyhttp -- sgstair for the libwifi (of course) -- whoever wrote DSChannels and did not stick his name there -- chishm again for the exec_stub i'm using (as far as i can tell) -- padrinator for non-jumpy stylus input -- wintermute, darkfader and many others working on libnds and devkitpro ;)

*ahem* test ? un deux ? un deux? *broum* Chers amis francophones, bienvenue sur le Blog de Bilou. J'ai l'insigne honneur et l'immense plaisir de vous annoncer qu'au terme d'une longue et fastidieuse semaine de débugging, runme et mes éditeurs de sprite/niveau tournent enfin au maximum de leur possibilités sur le linker R4. J'ai de bonnes raisons de croire que du coup, la compatibilité sur l'ensemble des linkers devrait être améliorée. Merci pour votre attention. A vous les studios. *wiiiit*


edit: oh well, now it seems that SEDS is touch-screen-blind and only recognize "gba" buttons (e.g. it ignores X and Y aswell) when started directly. Launching it through runme still works fine.

edit again: fixed. When you have some interrupt handler checking a "commands" buffer shared between ARM7 and ARM9, better make sure that you initialized the command buffer properly, even if you don't intend to send any commands in your program ^^"

Thursday, July 03, 2008

car4mba! encore r4té

Bon, suivant les bons conseils de gbadev.org, j'ai essayé d'adapter un "exception handler" pour l'ARM7, histoire de savoir si oui ou non il y a un plantage sur ce processeur. J'en ai aussi profité pour remettre une ou deux choses en place et voilà que je me retrouve avec un ARM7 qui fonctionne sur R4 sans tout planter. Son, wifi, tout y est.

Bref. J'espère juste être mieux armé pour le prochain plantage (je n'aime pas laisser un bug derrière moi comme ça). En attendant, la guerilla avec le R4DS est encore loin d'être finie : j'en prends à témoin un message du genre "DLDI driver available ; using built-in driver for R4TF; operating without DLDI" ... mes routines de détections sont dans les choux, quoi.

Résultat, si je lance SEDS depuis Runme, par exemple, SEDS n'aura plus accès à la carte mémoire (et donc sera incapable de se remettre à jour) ... hum, hum ...

Monday, June 30, 2008

r4volu7ion

Bon. Si je veux convaincre mes potes de tester mes p'tits Bilous sur leur DS, il serait temps que je m'assure de la compatibilité avec les linkers autres que mon "supercard". Mon frère est sur le point de se marier, donc il n'a pas vraiment besoin de sa DS pour les semaines qui viennent. Je la lui chipe donc, histoire de voir ce qui coince...
  • 26 juin : selon Smealum, ma p'tite démo ne passe pas sur le R4
  • 29 juin : premier test sur la R4 de mon frère, visiblement c'est l'initialisation ARM7/ARM9 qui coince
  • 30 juin: ouf. la R4 est quand-même capable de charger un .nds avec du code 'custom' sur le processeur ARM7. C'est donc juste que mon code est foireux.
  • 13:37 petit debugging à coup de "changement de couleur de fond". l'ARM7 compilé sans NTXM entre bien dans la routine "setupWifi()", mais reste bloqué en attente d'un fifo_temp==IPC_WIFI_INIT. Normal : j'ai retiré toute référence au wifi du côté ARM9 :P ... A noter malgré tout que celà n'empêche plus le traitement des autres évènements ...
  • 17:00 "si tu veux, je teste ça ce soir sur mon M3" dixit Oli ... wait'n'see
  • 20:00 je re-teste entre deux copies ... apparemment, c'est l'activation de la bibliothèque NTXM qui pose des problèmes ... je reprends mes habitudes de développeur de bootsector: on change la couleur de l'écran en fonction des étapes franchies dans le code, avec une légère variation pour prouver que le CPU est toujours bien actif ;)
  • 22:30 ok. c'est l'interruption timer qui douille. je la désactive, ça me fait toujours un runme fonctionnel sur R4 (auto-update et téléchargement compris. fini le card-swapping) mais pas de son :'(
  • 22:55 YES! on rajoute Song=0 dans le constructeur de Player et hop! ça marche "revolution ... r4volu7ion ... mem0ry ... m0re mem0ry" comme disais JMJ ;)

I'm doing tests with my brother's R4 this week and trying to find out what's going wrong with that latest demo. After a couple of hacks, it turned out that the ARM7 is apparently halting at some point when the NTXM player is enabled ... weirdo.

I already found a couple of uninitialized pointers, but unfortunately, the problem can only be reproduced when launching the software from R4 menu (launching from runme works like a charm, but then you need a no-sound version of runme to get bootstrapped :P) I've been somehow cheated in my attempts, though, by the fact that i kept the SuperCard in slot 2 while doing tests from the R4 on slot 1 ... Somehow, the FAT library "prefers" the supercard and i ended up running program out of the R4 that was doing I/O (and WiFi upgrades) through the SCSD :P 

(PS: je ferai une nouvelle release demain, après m'être assuré que j'ai bien un binaire qui marche, l'EFS lib et le DLDI fonctionnel, etc)

edit: éviter le mélange SCSD dans le slot 2 et R4DS dans le slot 1 pour le dev. on est jamais trop sûr duquel est utilisé par la libfat :P du coup, je m'interroge ... est-ce que j'ai vraiment réussi à avoir le son et le wifi sur la R4 ?

Wednesday, February 20, 2008

BatWindow

Rien avoir avec un personnage de noir vétu qui porte son slip sur la tête dans le ciel de gotham, je vous rassure ... Je testais hier soir une manière assez amusante d'assurer les transferts de répertoires entiers avec runme: des fichiers batch.

J'ai déjà une structure d'interpréteur de commandes ligne par ligne (pour les scripts de jeu), j'en ai juste tiré une variante (héritage et abstraction, hein ^_^) qui supporte d'autre commandes comme "chdir", "mkdir", "wget" ou "sendmsg". Seul le mode de transfer "natif" (avec mon petit protocole) semble poser quelques soucis (encodage des adresses IP, sans doute). Il n'y a pas l'air d'avoir de "inet_aton" dans la bibliothèque NDS, donc je tâtonne à coups de wireshark :P

Quand ça sera fait, je n'aurai plus qu'à modifier le serveur pour qu'il produise le fichier de commande correspondant au répertoire à transférer, et roulez jeunesse ! Comme j'ai aussi une commande "sendmsg" pour envoyer un paquet UDP avec un message convenu, tout va bien : je pourrai signaler au serveur que je veux le fichier suivant ;)

Yesterday evening was a speed-coding evening. I just figured out a funny way to upload full directories in a single click with "runme": batch files. Since the "game script interpreter" component of runme was already doing line-per-line parsing, all i had to do was (virtually) to replace "spr.load" and "bg.load" with "chdir", "mkdir", "wget" (for http transfers) and friends. I also gave the batch language the ability of sending custom strings towards a UDP port and to execute .nds files out of the SD card. Actually, only the 'native' transfer commands aren't working that well. I might have something going wrong with encoding of IP addresses, and the lack of "inet_aton" in the DKP release i'm using doesn't help.

edit: oh, j'oubliais: il y a aussi une commande "exec", donc potentiellement, je pourrais remplacer le téléchargement d'un fichier ".nds" par un .bat qui le sauve puis l'exécute. Pour l'instant, j'écris les .bat d'exécution à la main, ce qui est presque plus lent que de rebooter la DS. Seul point noir, ça ne marche pas avec tous les homebrew (je soupçonne quelque-chose du côté de l'ARM7), et j'ai toujours du mal avec le patch DLDI à la volée...

Thursday, February 14, 2008

[todo] runme reloaded

"Runme", c'est ma "combox" à moi. Entendez par là un petit outil pour la DS qui permet de se passer de linker et d'accélérer le cycle développement. Il est capable de transférer des fichiers d'un PC vers le répertoire "moving" de la DS à 90KB/s, techniquement capable (également) de transférer des fichiers de la DS vers le PC, mais pour l'heure, je me suis limité au choix des 4 fichiers édités par le Sprite Editor. Côté PC, il faut un programme spécial (petit script perl ou un programme java) pour "offrir" un fichier au téléchargement.

"Runme" is my all-in-one transfer and testing tool on the nintendo DS. The kind of "get-rid-of-your-linker" or "i-lost-my-media-card-reader" tool that is intended to boost software development on the console. It's my favourite way of transferring content from a PC to the console through WiFi at speeds approaching 90KB/s.
With the proper program running on your PC, it can also beam files out of the console (though i don't have a user-friendly interface for this atm).
Over time, it has gathered module player and bare game engine facilities, but it still lacks a couple of features to get a release of its own as "runme: reloaded".

Bref. Il serait temps que je fasse quelque-chose de "releasable" à partir de ce projet . Genre:

  • [wish] faire une version java qui intègre upload et download sur PC.
  • [done] permettre de choisir n'importe quel fichier pour l'exporter hors de la DS
  • [done] choisir le répertoire dans lequel les transferts s'opèrent sur la carte flash (pour l'instant, tout ce passe dans /moving)
  • [wish] prévoir un type "répertoire" pour l'importation vers la DS. Il apparaît comme une simple entrée dans la liste des transferts, mais quand on l'active, il crèe un nouveau répertoire sur la DS, recontacte le serveur et lui demande les fichiers un par un ... Ce serait bien pour tester VGDMS ^_^ (edit: remplacé par un server.pl qui présente les fichiers les uns après les autres).
  • [wish] intégrer les stubs "auto-update" dans la PAlib pour conquérir le monde...
  • [done] m'assurer que le démarrage d'un autre programme marche même lorsque les patches DLDI entrent en jeu.
edit: j'ai re-testé les patches DLDI ce midi. Au moins, le patcheur embarqué est cohérent avec lui-même et le fait que le "stub" qui passe d'un programme à l'autre soit en mémoire vidéo n'affecte pas son bon fonctionnement. Cherchons ailleurs ...
So the todo-list for the runme software include mostly integration of browsing widgets (to pick the import
directory or the exported file), integrate downloader and uploader in a single java program. I also need to support a "directory" transfer type which would make the DS ring back the PC and perform bulk transfers of many files at once (e.g. to test VGDMS).
The ultimate killer feature, though, would be to provide a twisted version of PALib that would be compatible with runme's program booting mechanism, but this means i first need to fix DLDI patcher embedded in the software.

Monday, January 21, 2008

dldi - chishm & stub

Well, i was trying to allow SEDS to be distributed as a single .nds file, while it actually requires plenty of stubs to be installed on the flash card in order to re-load fresh updates of itself (or to return to the "runme" root program). Making sure that stubs (and runme) are downloaded on demand was quite easy, but then i stumbled upon an unexpected difficulty: DLDI patching.

As most modern linkers perform that "driver patching" automatically when loading our homebrew, we tend to forget that they even exists (especially me, since i'm owning a pre-DLDI linker that works with built-in drivers of the libfat :P). Arialia first notified me of that i was missing something in the process... Then began the hide-and-seek game with (undocumented?) process of loading and patching code with DLDI drivers.


Lick said on gbadev.org:>
Chishm has already proven that it works. His VRAM boot stub gets patched before it's executed. There's hackery involved so check its source.
me:>
thanks. I'll google that.


A bit of googling could not locate chishm's source for the NDS loader, but crawling the forum did. One of the nice things chishm does in his loader is to reuse the DLDI driver of the current binary to patch the loader (and the program to be loaded). Let's see how it works.

pDH = (data_t*)(((u32*)(&_io_dldi)) -24);
pAH = &(binData[patchOffset]);

The first entry in the IOinterfaces table is reserved for DLDI devices. Note that the DLDI patcher will *keep* this "placeholder" interface so that, once patched, the driver's description is still at _io_dldi ^_^. Moreover, right before the actual ioInterface structure, we can find a placeholder for the DLDI header, including code/data sizes, and location of the Global Offset Table required for patching.

if (*((u32*)(pDH + DO_ioType)) == DEVICE_TYPE_DLDI) {
// No DLDI patch
return false;
}

One of the tricks involved is that, if no DLDI driver is installed, the ioInterface's "type" is set at compile-time to the "DLDI" string. Once patched, it gets replaced with the vendor/product mini-id (e.g. SCSD for Supercard, securedigital or MPCF for "media player, compactflash", etc).

The rest is just going smoothly. I initially feared that the restriction of 16-bits access to the VRAM would doom the entire loading process, but obviously, it does not apply when VRAM is mapped as "LCD" (plain CPU access, offscreen). That's nice.

Thursday, August 16, 2007

ARM7 et ARM9 sont sur un bateau ... ARM9 tombe à l'eau. Qui reset?

here: br[here]

I'm trying to make sense of the "execute .nds file" libraries ... Somewhere in an old version of the DSWiki, i found this piece of code (the trick only works with GBamp cartridge, afaik):



REG_IME = IME_DISABLE; // Disable interrupts
WAIT_CR |= (0x8080); // ARM7 has access to GBA cart
*((vu32*)0x027FFFFC) = fileCluster; // Start cluster of NDS to load
*((vu32*)0x027FFE04) = (u32)0xE59FF018; // ldr pc, 0x027FFE24
*((vu32*)0x027FFE24) = (u32)0x027FFE04; // Set ARM9 Loop address
swiSoftReset(); // Reset



which suggests that the software reset will branch the code on 0x27FFE04 at some point, and that the file to be loaded is found at 0x27FFFFC (its first cluster in the FAT flashsystem, at least, which suggests much reverse-engineering of the GBAMP firmware, imho).

J'essaie de comprendre un peu les mécanismes mis en jeu lors du redémarrage de la nintendo DS, et en particulier comment s'y prendre pour lui faire démarrer un fichier .nds précis (lancer le Sprite Editor depuis un programme "menu", par exemple). Une des propositions dans ce sens venait de DSwiki (cf supra), mais ne fonctionne apparemment que pour l'adaptateur GBAmp. Après le reset software, le processeur finit par se placer en 27FFE04, et le mot mémoire @27FFFFC contient le numéro du premier cluster du fichier à démarrer (l'adresse sur le disque, pour ceux qui n'ont pas passé 3 ans à décortiquer le FAT32 ;)

Bien sûr, il est nécessaire d'obtenir la coopération du 2eme processeur, le ARM7 (code ci-dessous), ce qui nous donne à contempler le genre de "magie noire" mise en oeuvre pour synchroniser les deux processeurs de la DS: périodiquement, le ARM7 va inspecter la mémoire (partagée) à l'adresse 27FFE24 (le "pointeur magique"), et si il y trouve l'adresse prévue pour la "boucle Passme", il va déclencher son propre reset.

The trick of course only works if the ARM7 side co-operates, which gives us an idea of how the dual-cpu-with-shared-memory can turn simple things in obscure wizardry:



if (*((vu32*)0x027FFE24) == (u32)0x027FFE04) // Check for ARM9 reset
{
REG_IME = IME_DISABLE; // Disable interrupts
REG_IF = REG_IF; // Acknowledge interrupt
*((vu32*)0x027FFE34) = (u32)0x08000000; // Bootloader start address
swiSoftReset(); // Jump to boot loader
}



In other words, the ARM7 cpu will periodically check whether the "reboot" has been invoked on the ARM9 cpu (in which case, it is trapped in the so-called "passme loop" that consists of a "MAGIC_HERE: jump [MAGIC_POINTER]" instruction where the memory at address MAGIC_POINTER contains the address of the jump instruction, i.e. MAGIC_HERE.

'MAGIC_POINTER (0x27FFE24)' is actually something that is nintendo-firmware related and this is where swiSoftReset() will send us back on the ARM9 cpu. On the ARM7, swiSoftReset() will do the same, but using another magic pointer at 0x27FFE34, which we reprogrammed with the "cartridge entry point" address (0x8000000). Voilà. that should do the trick: ARM9 resets and enters a loop, ARM7 detects it and resets as well. ARM7 then execute the cartridge's initialization as well (which will take care of taking ARM9 out of that loop, hopefully).

Après un petit tour sur "gba&ds tek", il apparaît que le service "softreset" du BIOS de la DS se sert du contenu de 0x027FFE24 (notre "pointeur magique") et de 0x027FFE34 respectivement pour savoir où reprendre le code après la réinitialisation. Pendant que l'ARM9 tourne en rond (le code sur lequel on l'a envoyer lit en permanence le contenu du 'pointeur magique' et s'y rebranche: c'est ça notre "boucle passme" et il suffira à l'ARM7 de modifier le contenu du "pointeur magique" pour débloquer l'ARM9 et de l'envoyer vers le programme de son choix), l'ARM7 relance pour sa part l'exécution vers le point d'entrée de la cartouche en ROM, et l'on devrait se retrouver à nouveau dans la partie du firmware GBAmp qui lance un fichier... sauf qu'il ne s'agira plus de son propre menu, cette fois!

stubs join the game


Now, if we look at the "run .nds file" code in rebootlib or in grizzlyadams' DSchannels, it works a bit differently. The new thing here is the presence of stubs, chunks of code that will help the transition from old software to the new one. The stub will typically take care of filling the RAM with the new program while trying to avoid being destroyed. Some of them simply live on the ARM7 and will thus only support programs that do not use a "custom" loop (basically denying execution of anything that is WiFi-related :-/)

Jetons à présent un oeil au code "executer(char* ndsfilename)" de la rebootlib de lick ou du DSchannels de grizzlyadams. Tout d'abord, ce qui est nouveau ici, ce sont les stubs, des petits bouts de programme qui vont assurer temporairement le chargement entre le programme appelant et le programme appelé. Un stub se charge généralement de préparer l'environnement du nouveau programme et de l'amener en mémoire en prenant soin de ne pas se supprimer lui-même. Dans le plus simple des cas, il s'agira simplement d'un exécutable pour le ARM7 un peu particulier qui se comporte comme le programme-modèle une fois le chargement effectué. L'inconvénient de cette technique, c'est évidemment que les programmes qui ont un "coté 7" spécifique (et notamment faisant appel au WiFi, etc) échoueront lamentablement :-/

In DS channels, grizzlyadams rather use the video memory to store the stub. This of course require special rules for building the stub (as the memory layout of the produced binary has nothing to do with a regular DS environment)

/*
We assume, that VRAM is set up as follows:
- VRAM_A is mapped to 0x6000000 for text screen
- VRAM_B is mapped to 0x6820000 for passed vars
- VRAM_C is mapped to ARM7 WRAM for arm7 stub
- VRAM_D is mapped to 0x6860000 for arm9 stub
*/

(*(vu32*)0x027FFFF8) = 0x06000000; // ARM7 Entry
(*(vu32*)0x027FFE24) = 0x06860000; // ARM9 Entry



Nothing like a "passme loop" here (see specs/ds_arm9vram_crt0.s, the assembly file that contains the initialization code for the stub) the ARM9 prepares the environment and enters "main()". Once the stub has loaded your requested .nds file (optionnally applying DLDI patching), the 'Execute()' function will play hide-and-seek with the ARM7, which is waiting for instructions through the FIFO hardware.

Le stub de DSchannel est un peu particulier en ce sens qu'il va squatter la mémoire vidéo pendant son exécution. Et celle-ci est tellement vaste par rapport à ce qui est nécessaire pour quelques messages texte que cela passera complètement inaperçu pour l'utilisateur. Pourtant, aussi bien le stub7, le stub9 que les arguments qu'ils reçoive (p.ex. le nom du fichier à lancer ;) tiennent dedans ^_^.

C'est le stub9 qui entre en jeu le premier, suite au 'soft reset'. le code d'initialisation (specs/ds_arm9vram_crt0.s) prépare à nouveau les cache, mais ne contient pas l'ombre d'une "boucle passme". Il démarre la fonction main() du stub qui à son tour, va charger l'exécutable NDS en mémoire (ajustant les drivers DLDI au passage, si nécessaire) avant de commencer à piloter l'ARM7 à travers quelques commandes via le FIFO hardware.
Celà signifie donc qu'au moins une commande 'EXEC' (qui ne fait rien de plus que de provoquer un reboot de l'ARM7 vers une adresse indiquée à l'avance par l'ARM9: celle du stub7) avant de faire une petite partie de 'cache-cache' entre les commandes FIFO et les valeurs de retour annoncées par une variable partagée ("synchro" à l'adresse 0x027FFFF8) jusqu'à ce que les deux moitiés de l'exécutable nds soient en place.

Another original thing here is that the original ARM7 code is still running while the ARM9 is already executing its own stub. Things will only change with the 'EXEC' command sent through the FIFO.
/* in stub_main9.c */
if(DebugEnabled) { a7(); iprintf("Booting...\n"); }
FIFO_Send(IPC_CMD_EXEC, 0);

/* in myapp_main7.c */
void IPC_Exec()
{
swiWaitForVBlank();

*(vu16*)(0x04000208) = 0; //REG_IME = IME_DISABLE;
*((vu32*)0x027FFE34) = *((vu32*)0x027FFFF8);

asm("swi 0x00"); //swiSoftReset();
asm("bx lr");
}

The ARM7 stub and the ARM9 stub then start playing hide-and-seek again, exchanging more commands through the FIFO and using a special "synchro" shared variable (0x27FFFF8) to report each other's progression.

Monday, August 13, 2007

"update homebrew via WiFi ..."

So, i finally successfully included Ben Campbell's "slurping" as part of my NDS WiFi attempt.
I guess it will save me hours in future development as i can now simply retrieve an update of the program as part of running the program itself.

Ideally, i'd have also include a reset of the software or at least a reset of the cartridge so that you're back at the .nds selection menu after the upgrade is complete, but this didn't worked as expected.

  • "Exec.cpp" from Bjoern Giesler's DSFTP works fine and allows me to transfer execution to another program. However, despite all my attempts, it seems that the started program cannot cannot access WiFi hardware when started in that way. This may not be a problem for a one-shot update of a non-WiFi related tool (like SEDS atm), but it certainly kills the idea of a debugging session free of DS power-cycling. (edit: maybe my code before exec() is missing Wifi_DisconnectAP(); ?)

  • libcartreset by Lick required a bit of source-tweaking (it assumed booleans in C :P) to compile, but it simply didn't work. Not the way i used it, at least, and i failed to find a decent tutorial on how to use it. All it does is halting the program, period. It may break any attempt to use the FAT library (or anything else that is cartridge-related) between the "cartSetMenuMode" and the "passmeloopEnter" calls, too.

  • Rebootlib by Lick is clearly something more complex. It supports more hardware, makes use of a DLDI-compliant "bootstrapping stub" that is patched at reboot-time against the running hardware. It is clearly designed to work with a more recent release of the DevkitPro than the one i have and required a couple of fixes on the registers name so that it almost compiles. Yet it expects some external _dldi_io symbol -- i guess this one would come from my own nds if it were DLDI-compliant -- which i cannot provide unfortunately.
All in one, it simply looks like it's time for me to drop my "working" release of devkitpro, upgrade to the latest one, find out how DLDI patches work and pray for my software to work flawlessly with that updated libfat ... Then screw the new devkitpro so that i can still use the "non-jumpy drawing" patch of padrinator

edit: installation of devkitpro r20 in progress ...
edit: good news #1 just found out the following comment in touch.c from the latest libnds:
$Log: touch.c,v $
Revision 1.19 2006/12/16 22:29:37 wntrmute
Incorporate Padrinator's touch code

edit: good news #2, in case everything else fails, there is "reboot.cpp" to be studied in tftpds-2.4beta