Showing posts with label arm7. Show all posts
Showing posts with label arm7. Show all posts

Wednesday, April 12, 2023

StyleHax on DSi

For (too?) long, I've staid aside of DSi homebrew. Partly because there's little the camera could offer to my projects and I don't really need more than 4MiB of RAM, but mostly because until recently, running homebrew on that device felt like an arm race with Nintendo. You need to break into the machine through exploits the same way you'd take control of someone else's server on Internet and that has a taste of dark side I'm not fan of. Plus, once you've managed to get into things, you then have to install more permanent modification if you want to be sure to be able to do the same the next day, since Nintendo could ban the vulnerable software you've used to gain access (if you were lucky enough to have it on your device on first place).

But one post on hackaday might well change all this. Nathan Farlow has found a way to use the web browser shipped with the DSi firmware to execute arbitrary code.

 He just had to get his code into the right spot. For this he employed what’s known as a NOP sled; basically a long list of commands that do nothing, which if jumped into, will slide into his exploit code. In modern browsers a good way to allocate a chunk of memory and fill it would be a Float32Array, but since this is a 2008 browser, a smattering of RGBA canvases will do.

Ultimately, that will execute a boot.nds file from the SD card, such as a homebrew launcher.

Octobre dernier, j'avais jeté un oeil un peu plus attentif à "Comment on peut faire tourner des homebrews sur DSi". S'en était suivi un graphe compliqué dans mon calepin indiquant quel menu dépend de quel installateur qui dépend de quel firmware custom. Mais au final, on finissait toujours par dépendre d'un "hax" pour prendre le contrôle de la console. Un vrai piratage en règle, quoi, et qui dépend en général de la disponibilité d'un logiciel vulnérable sur sa console.

Pendant toute la durée de vie de la bête, Nintendo a mené une chasse farouche à ce genre de vulnérabilité, supprimant jeux et applications du service DSiWare au fur et à mesure qu'elles étaient identifiées, étendant sa liste de cartouches "nds" interdites (dont les clés avaient été cassées et utilisées pour des linkers) lors de mises à jour système indispensables pour faire tourner les nouveaux jeux ou refaire un téléchargement sur le DSiWare. J'étais resté à l'écart de tout ça. Mais j'ai commencé à réviser ma position: un nouvel "exploit" (comprenez "mécanisme permettant de faire tourner son code à soi en exploitant une vulnérabilité) à été trouvée, et pour le navigateur intégré, tout simplement!

It should be trivial to try: install your favourite DSi-capable software as boot.nds on an SD card, direct your DSi browser to nathan's web page and voilà. Except nothing guarantees the contents of Nathan's page will stay the same over time, so I'd rather download that locally and study the stylehax source code before I start using that on my own device. 

At the start of the chain is an html document with some NDS binary embedded as "shellcode" in the html <script> part, plus some javascript to exploit the use-after-free bug of the browser. The payload.c featured in the stylehax repository contains actually just a little loop to inject the 'true payload' at some dedicated location (held as a blob into payload.h). And that true payload comes from another repository (well, actually, that second repository contains many exploits, but the one we'll use is the 'minitw' one, according to payload.h)

As soon as the 'payload.c' part is running, we already have access to most resources of the DSi. The goal of minitwlpayload is to setup the proper context for the default bootloader of the devkitpro project embedded into the .nds (yes, that comes from a third repository :P) The bootloader will mostly run on the ARM7 core, which is the only one to have access to SD card registers on the DSi. There will be many passme-loop-synchronization-points until we're ready to execute the NDS or DSi code contained in boot.nds, one for each ARM9 function we want to execute between two ARM7 functions.

Pour celui qui veut tenter sa chance, rien de plus simple! L'auteur de l'exploit a mis en ligne une page HTML (une seule) intégrant le code nécessaire pour aller exécuter le fichier boot.nds qu'on trouverait sur la carte SD de la DSi et le javascript qu'il faut pour faire bugger le navigateur au point qu'il se mette à exécuter un morceau de page web canvas HTML5 comme si c'était du code machine. Et surprise, c'est du code machine, cette fois-ci! Enfoncé, HTML Quest ;-)

One question remains, though: how does ARM9 exploit trigger execution of custom code on the ARM7 ? It looks like the answer lies within the following snippet of exploit.c:

    memcpy16(VRAM_C, decrbegin, decrsize); // writing custom code into VRAM at 0x6000000
	VRAM_C_CR = VRAM_ENABLE | VRAM_C_ARM7_0x06000000;
    // now inserting a jump at the start of ARM7-dedicated memory area.
	*(vu32*)0x2380000 = 0xE51FF004; // ldr pc, =0x06000000
	*(vu32*)0x2380004 = 0x06000000; // (constant for above)
	debug_color(0,15,0); // dark green
	IPC_SendSync(1); // MAGIC!

For some reason, when we trigger an IPC IRQ on the ARM7 with code 1 (out of 16 possible codes), it executes code from the start of the ARM7 area again, where we have installed our trampoline to VRAM. Why does it behave so ? I guess the reason lies in some line of code for the ARM7 code in the TWL sdk, sealed in a vault at Kyoto ...  I presume I'll have to accept it without further understanding.

Seulement moi, j'ai envie de comprendre un minimum ce qui se passe. Histoire entre-autre d'éviter que la page ne télécharge un jetaibieneu.nds au lieu de démarrer hbmenu.nds rebaptisé boot.nds, par exemple ?Et aussi pour enfin comprendre cette histoire de .twl et donner une meilleure chance à l'exécution de mes homebrews sur DSi. Donc je parcours les pages github, ma liseuse dans une main, mon calepin dans l'autre...

exomizer/exodecrunch

One notable action of exploit.c from minitwlpayload is to "decrunch" the embedded bootloader into VRAM where it will execute, that is, to undo the compression performed by the exomizer tool invoked by dsi/exploits/minitwlpayload/Makefile.

  • it packs the 'bootloader' from devkitpro github from 6KiB into a bit more than 4KiB. Unsure whether it was critical to use in this context :-P
  • ndsload.bin is just an 'objcopy' binary-extraction of the ndsload.elf
  • https://bitbucket.org/magli143/exomizer/src/master/src/Makefile could be the source for the exomizer tool, but I fail to get why it would need a 6502 emulator ... (I guess this is linked to the 'self-extracting for C64, Apple II and BBC micro' feature)

Possibly, such steps could make sense for larger payloads or for other exploits where the amount of data we can embed is limited (remember, there has even been exploits involving QR code readers)

Saturday, December 18, 2021

Ludricous Speed

 There's another bug with my modified version of libntxm. It has been around since at least early School Rush prototypes and possibly even Apple Assault. If you let the player spin for too long, it suddenly starts to play things at ridiculous speed that makes the song barely recognizable.

I had the Dreams demo running with ARM7 debugger plugged in for another reason (undefined instruction) and it started speeding the song up so I dropped all my kitchen stuff and jumped on the CTRL+C to be able to dig that later. And later is now.

One symptom of the issue seems to be that the tick_ms variable is now way larger than the MsPerTick() property of the Song.

Every time the playTimeHandler() is invoked, it recomputes how many milliseconds elapsed since last call, and here I get the value of 1. It won't get out of the issue because there's nowhere we could read tick_ms = 0. Instead, the amount of time expected is substracted from the time elapsed so far, so that 'extra milliseconds' are deduced from the next 'tick'.But watching that tick_ms evolve, it is properly decreasing. It has not just been gone wild. It got corrupted from something else.

It doesn't tell me what goes wrong in the soft, unfortunately, but at least, it gives me a way to make sure players won't experience it. If I cap the tick_ms to 2*MsPerTick(), I shouldn't have issues.

Note how buggy tick_ms is close to last_ms ...

Note how unlikely it is that the player has been running for 43509 seconds. I wasn't even running it for one hour! And when it eventually occured again, lastms was 43494543, or something alike (decimal, not hexa).

Seeing some more code featuring 'compute over 100' now makes much more sense. 100 times higher than 43 million, we're quite at MAXINT for an unsigned. Plus, if you've got an unsigned, comparing -t to something might very well produce something that is compiler-dependent. Likely, there might be a switch to produce a warning for that.

Il y a un truc qui me chagrinait, avec School Rush: au bout d'un certain temps la musique partait en vrille. Le problème se posait uniquement au bout d'un temps assez long, du coup, je n'avais jamais eu l'occasion de prendre le temps de chercher le problème. Mais hier, j'avais un débuggeur ARM7 prêt à fonctionner, un émulateur branché dessus avec le code qui 'là-normalement-ça-devrait-marcher' pour un autre soucis et j'étais en cuisine ... donc ils ont tourné pendant longtemps sans intervention ... assez longtemps pour que le problème de School Rush se produise. J'ai bondi sur mon ordi pour interrompre tout ça et débugguer enfin cette histoire.

Au premier tour, tout ce que j'ai pu dire c'est que "bin c'est parce que tout d'un coup, on découvre qu'on est en retard de plus de 40 millions de microsecondes pour passer au 'tic' de musique suivant". J'avais espéré qu'il s'agissait d'une déviation ou quelque-chose de ce genre, j'avais mis quelques 'break if...' dans ddd mais quand le problème s'était finalement re-reproduit (bonne journée, ça), on était passé de quelques millisecondes de retard à plus de 43 millions, comme ça, sans-transition-à-vous-les-studios. J'en venais à me dire que 'tant pis, je vais juste mettre un patch qui limite artificiellement ce délai' puis je tombe sur l'implémentation de la lecture du temps à partir du hardware qui cache une division par 100 ... et 100 * 43 million, on approche du plus grand entier 32 bits. Là, ça pue le bug de conversions arithmétique dû à une soustraction mal calibrée... ça je pourrai corriger pour de bon.

Tuesday, December 14, 2021

PlaySFX vs. PlayInst

 

Je refais un peu d'explication-BD parce que là, c'est un brin compliqué. Le mécanisme que j'avais ajouté pour faire des effets-par-pattern, je l'ai poussé un peu trop loin.

Au départ, c'était bien vu: un ensemble de flags permettant de dire si on doit suivre la "partition" normale du module ou continuer à avancer dans la piste en cours jusqu'à trouver un effet 'pattern break'. Mais il y a un cas que je n'avais pas en tête à ce moment-là: les effets 'normaux' fait d'un p'tit sample tout seul. Eh oui.

Dans ce cas-là, la piste sur laquelle on met le sample n'a normalement pas de contenu. Depuis le nouveau code, elle est ignorée puisqu'au-dessus du nombre de pistes définies dans le fichier .xm. La seule exception à cette règle, c'est pour les pistes qu'on a attachées à un morceau de piste d'effet.

Disclaimer first: many of the things I'm now doing with libntxm are far beyond what it was designed to do, that is running a soundtracker on the NDS. When thigns go wild because I stop a song and replace it with another before the Player class on the ARM7 get any chance to run its every-millisecond handler routine, I'm worse than a TAS-speedrunner producing superhuman inputs on the software. Right ? Same when I feed the Player with two patterns simultaneously and going 'yeah, play pattern 9 on channels 1-12 while at the same time playing pattern 27 on channels 14-16, will you ?'. None of this was part of the original plan, and that's perfectly natural. It's up to me to make it work if I want it to work.

Ça, ça marche bien pour le moment 'lecture de la nouvelle cellule (note) dans la ligne'. Mais si on veut qu'un p'tit son puisse être joué, il faut qu'on continue à faire des calculs d'enveloppe, la gestion des registres de volume. C'était déjà un peu à ça que servait le flag channel_active. Il reprend du service.

Bon, là je me suis limité à un p'tit test tout bas, parce que ma fée est pas ultra-fan de StrTrk et que c'est l'heure de la p'tite série qu'elle aime bien à la télé.

So a few weeks ago, I fixed a crash in the ARM7 code with 'oh, I know: I'll give NTXM player a NULL song first, and then delete-and-create another one'. Not a bad idea in itself, but I missed a few things that the player has to do even when I change the song, like progressively muting the channels when there are no more notes to do. Obviously, I shouldn't prevent it from doing so even though we activated the NULL song.

I also finally implemented an if-block for the GobScript (it turned out quite simple thing to do) and tried to use that so that we'd use pattern-effects only when playing a tune with such patterns, and play plain-samples-effects otherwise. Nice try, but it turned out that no sample was playing at all. That was because of my previous changes again: when playing such lone samples, we're perfectly right to do so on channels that are not present in the song. (Actually, we should better do so). But the code from SchoolRush would only start playing a sample if there was a pattern Cell to back it up. Either a regular one, or one from a pattern-effect. I had to identify the tasks where that test was mandatory (e.g. when processing effects or advancing to the next row) and tasks where it shouldn't be used (process volume envelopes, start the sample, turn down the volume when done playing the sample, etc.)

Reste à espérer qu'avec les corrections de 'quelle musique jouer quand' et 'okay, on a plus de partitions, mais continue quand-même à baisser le volume', ça suffise pour que les musiques de la prochaine démo soit un peu plus sous contrôle.

Ah oui. Et au cas où, ces choses en forme de tentacules (Bob) sont des statues-registres.

Saturday, June 01, 2019

touchInit()

J'espère que ce sera la dernière surprise dans la branche "mise à jour de mon kit de développement DS"... Après avoir enfin réussi à avoir des programmes qui tournent à nouveau sur la DS (et dans l'émulateur, au passage), je finis par me rendre compte que plus aucun de mes widgets ne fonctionne. Au point que j'en viens à soupçonnner quelque-chose dans le code qui relaie les mesures depuis le composant SPI en charge de l'écran tactile à travers le processeur ARM7 pour être exploité sur le processeur ARM9. D'autant que tous mes programmes utilisent un code ARM7 "custom", chose qui ne sera forcément pas testée lors des mises à jour de libnds, devkitARM et leurs sbires.

Mais mon code ARM7 voit toujours bien son gestionnaire d'interruption appelé, recompiler un des programmes d'exemple avec mon code ARM7 au lieu de la version officielle marche toujours ... Ou en tout cas, c'est l'impression que ça donne au premier regard. En débugguant de plus près, je constate que mon code sur l'ARM9 reçoit bien des 'touchPosition' en bout de chaine, mais chose curieuse, deux paramètres (px et py) sont toujours nuls. Il s'agit des valeurs traduites en pixels, à l'aide des paramètres de calibrage. Et le programme d'exemple fait pareil: il ne nous donne que les valeurs "brutes".

En réalité, il faut maintenant appeler une fonction "touchInit" pour appliquer les données de calibrage, et la version du devkitpro que j'avais installée avait fait la mise à jour correspondante dans le "code ARM7 par défaut", mais pas encore dans les programmes d'exemple utilisant du code ARM7 custom ... On va finir par y arriver.

Monday, May 27, 2019

.arm7.elf

écran tout blanc sur une DS, cascade de message d'erreur "MMU7 write32 to undefined register 044xxxxh = 00000000h (PC:00000000)" produits par desmume, avec des valeurs xxxx commençant je ne sais pas trop où et qui continuent de 2BD4 à 3A34 au moins, et ça même si j'essaie d'attacher un débugueur sur le processeur ARM7.

Il y a clairement quelque-chose qui va de travers avec les programmes recompilés sur mon NUC et sur le nouveau portable avec la dernière version téléchargée de devkitPro. Pourtant je parviens sans difficultés à recompiler les exemples. En essayant de retrouver la commande qui fait appel à ndstool -- cet outil permettant d'emballer deux programmes jusque-là tout à fait classiques (format ELF) en une image de ROM nds. Et en relisant la ligne de makefile produisant "lib/ppp7.arm7" à coup de copie de section de fichier (outil GNU 'objcopy) je suis pris d'un doute: et si la technique passant par objcopy était devenue obsolète pour l'ARM7 aussi. Après tout, j'ai réussi à compiler les sources avec le nouveau devkit, mais est-ce que j'ai essayé de les faire tourner après ? pas sûr.

Et effectivement, en utilisant ppp7.arm7.elf directement, ça marche beaucoup mieux. 'faudra que j'aille corriger tout ça.

Sunday, March 12, 2017

runMe truly resumed (hopefully)

All of sudden, runMe works as expected again. I have sound playback (missing since 1st of January) and I can use the GUI on the bottom screen while playing on the top screen. I'm relieved, but I can't really feel proud. This is the most silly fix I've done in years. For all that time, I've been linking runMe with the default ARM7 binary instead of using my own "ppp7.arm7" that integrates my modified version of libntxm. Some commands thus had no effect, and others had undefined effect (including likely crashing the ARM7, meaning that reading touchscreen no longer worked).

Tout à coup, runMe re-marche.Et je ne m'en sens même pas fier après cette descente dans les arcanes du système de la libnds. Voyez-vous, j'avais fini par suspecter un crash du processeur ARM7, celui qui se charge de lire la position du stylet dans les puces-esclaves de la DS pour en informer l'ARM9, le processeur principal. Mais aucune de mes théories ne semblait fonctionner. J'ajoute un p'tit embryon de widget succeptible de me dire en temps réel où on en est dans le fichier XM (la musique, pour ceux qui reviendrait de looongues vacances ou d'une rédaction de thèse), et il ne me donne aucune information pertinente ... je branche ddd sur le processeur 7, et il déclenche les break-points n'importe comment, comme si les fonctions s'enchaînaient les unes derrière les autres et ce avant même que main() ne soit appelé.

Jusqu'à ce que je me rende compte que la connexion ddd-arm7 marche sans problème avec SchoolTest et que je sois pris d'un très gros doute: est-ce que je compile bien ce que je crois ? est-ce que j'ai bien dit à l'outil qui rassemble le binaire pour ARM7 et le binaire pour ARM9 en un seul et même fichier (.nds) que je voulais utiliser mon binaire pour ARM7 et non celui par défaut de devkitpro ...
Eh bien non.

Donc si vous me le permettez, je sors chercher un miroir pour me lancer des noms d'oiseaux.

Saturday, September 29, 2012

Yellowl and Redowl

I tried again, with the updated SEDS and properly charged battery. I could save a first draft (just the shadow lines), and then when I tried to save my "finished" work, the editor crashed again. That's *really* getting on my nerves, now.
Hopefully enough, I had a real camera powered up and ready-to-shoot just one floor below, this time, so I've shot pictures of my screen and did some Gimp post-processing to try to enhance and restore the picture into something that could be shown or fixed afterwards. I started the owl again, from the 'shadow lines' that were saved, using the version of SEDS I submitted to NEOflash compo. Everything went fine, and I made tons of intermediate saves. Then I thought "oh, well, that should be it for now", and clapped the lid of the DSi. As usual, I then thought of a small last improvement I could do, so I opened the lid, applied the change and tried to save again ... stalled. So this is what goes wrong: I cannot read/write to the SD media card anymore after I put the device in "sleep mode" for a while. And that happens regardless of whether I use the "1.x" or "2.0" version of my GUI engine.

Tuesday, March 13, 2012

guruMediationDump()

I love it when my wish have been granted even before I'm aware of the wish. In this case, devkitpro team has revamped the way exceptions are handled in libnds "r32". The large "wizardry" part of the guru mediation screen, that dumps registers and all has been extracted in a guruMeditationDump() library function, and the default handler is a 2-lines function that definitely locks the DS once the dump has occured.

Ah, bin au moins, je ne me fatiguerai pas trop à retrouver comment-j'avais-modifié-guru-meditation-pour-mon-usage-personnel: l'équipe de devkitpro m'a mâché la besogne en plaçant tout ce qui était utile dans une fonction et tout ce que je ne voulais plus (ou presque) dans une autre ^_^. Je vais pouvoir reprendre mes tests sur la school zone très prochainement (dès que je n'ai plus les yeux qui piquent et "OIUY" imprimé sur mon front à la fin de la journée, quoi :P)

Instead, I used in "r21" to define a die() function that allows me to perform recovery such as leaving to moonshell or inspecting memory. So all I should need is to redefine my own 2-lines function and use setExceptionHandler() rather than defaultExceptionHandler(). Let's see whether that helps me figuring out why the school zone is so freaky.


edit: it looks like using scanKeys() in die() is not such a good idea. With the r32, it relies on some working communication between arm7 and arm9, which afaik requires the Fifo (and thus the interrupts) to work. If for some reason the crash comes from an interrupt handler, you'll find yourself unable to see keys changes. Polling the following register could help:


//! Key input register.
/*! On the ARM9, the hinge "button," the touch status, and the
X and Y buttons cannot be accessed directly.
*/
#define REG_KEYINPUT (*(vuint16*)0x04000130)

and checking the value of REG_IE and REG_IF could explain the situation as well.

Tuesday, January 11, 2011

swiSleep()

Je suis resté sans support de la mise en veille pour mes programmes jusqu'en juillet 2009, puis j'ai copié un petit bout de code qui permettait de s'approcher pas trop mal de cette fonction. Thoduv dans un post précédent, expliquait alors qu'il y avait techniquement moyen de faire mieux, que l'approche était en cours d'intégration dans la libnds, et que ça lui donnait du fil à retordre pour son "Lapinou Jumps" ...

Du coup, je me retrouve maintenant avec deux bouts de code qui tentent de mettre le programme en veille : mon "code utilisateur" sur l'ARM9 et le "code système" sur l'ARM7... et de temps en temps, le programme qui éteint la console au lieu de se mettre en veille >_<

Here's how 'sleeping' is implemented in the "devkitpro-r32" : there are SLEEP_DISABLE and SLEEP_ENABLE messages that can be sent to the powerValueHandler on the ARM7. When sleep is enabled on the ARM7, systemSleep() is invoked by inputGetAndSend() directly when the lid is closed for more than 20 frames (1/3 second). The ARM9 "acknowledges" this by echoing the PM_REQ_SLEEP message and the ARM7 side then proceed to the suspension of execution through the hardware power management register. swiSleep() on the ARM7 is the core of this shutdown. The rest is turning off the speaker, changing LED stats, etc.

So far, it makes my programs randomly shutdown with low probability when one closes the lid. I still have to define whether it's due to an intermix of the old code with the new lib or to something more intrinsic to swiSleep()... That's not really a problem for runme or apple assault, but it will definitely be a nuisance for the editors. Also, I haven't seen anything sending _SLEEP_DISABLE or _SLEEP_ENABLE, though, while it would be a good thing that I could prevent the DS to enter sleep mode in the middle of a wifi transfer. I'm also unsure of the reason for that 1/3 second delay, and I fear it could lead to gameplay issues (the game state change too much while I'm closing the lid).

Wednesday, December 22, 2010

So long, exec.cpp

hbmenu
Since August 2007 the exec.cpp file from GrizzlyAdams has been a corner stone of my activities on the Nintendo DS. It allowed me to launch NDS files from other NDS files -- a functionality that was missing of the "standard" features of libnds by then. Combined with dswifi and a small HTTP retriever, it allowed me to introduce a "self-update" feature that replaced the media card mounting/unmounting that was previously taking most of my development time. Since I mostly work on my DS project on lunch time or in the evening, it had a major impact on my ability to keep going on.
En août 2007, mes projets sur DS ont pris un grand tournant avec l'ajout d'un morceau de code de DsChannel de GrizzlyAdams, qui permettait d'enchaîner un NDS vers un autre. Combiné à un petit code HTTP, je devenais capable d'écrire des programmes se mettant à jour eux-même. Et il n'y a pas à dire, celà a nettement boosté le travail sur le Sprite Editor, le Level Editor, la lecture de modules et plus tard, le moteur de jeu à la base d'Apple Assault ...

But here we are, 3 years later, at devkitArm revision 32, with all the libraries changed. The handling of FIFO code, among other things, received a major revision, that breaks the compatibility with the custom loader. Meanwhile, too, Wintermute included a similar feature in HBMenu and made several part of the libnds dependent of its own approach. Reseting the ARM7 on request from the ARM9, for instance, is directly located in fifosystem.c, and a C++ exception will try to return to the launcher of a program. Rather than fighting against this, I decided to try and see to what extent the bare bones of "HBmenu" can be converted to support runME.

Mais voilà. Ce code utilisait le FIFO -- pratiquement inutilisé du temps du devkitArm 21 -- qui entretemps a subit une refonte importante, et Wintermute et ses accolytes ont cherché à intégrer une fonction similaire dans la libnds. L'astuce, en fait, c'est que la fonction n'est pas directement offerte aux programmes, mais intégrée dans HBmenu, qui laisse une partie de son code à un emplacement "persistant" qui (si je comprends bien) est uniquement capable de revenir au programme qui a installé ce programme persistant. Plutôt que de me battre à essayer de faire cohabiter le code de GrizzlyAdams dans le nouvel environnement, j'ai donc repris la base de HBMenu pour reconstruire runMe par-dessus. Ca marche plutôt bien, dirait-on, même si je n'ai pas encore fini le portage ... mais curieusement, ça me fait un peu chose de laisser tomber cet "exec.cpp" qui m'a soutenu tout ce temps ...

The result is encouraging, although I've got a small tear in my eye for that piece of software that I analysed and debugged to make it fully support DLDI ... Although the code from the devkitpro project shares many similarities with "my" previous approach, a larger part of the stub executes from the ARM7 (as far as I understood), meaning that it's not possible to perform debugging for it. The new code consists of
  • nds_loader_arm9.c, acting as a library and directly linked to your program (runme or HBMenu), that mainly ensure software reset of the two processors and DLDI patching of the loader
  • bootstub.bin, installed from the end of the ARM9 memory (the upper 48K of the 4MB area) by installBootStub() function in the "library" file
  • loader.bin, copied in VRAM by runNdsFile(). It contains its own (stripped-down) FAT access, the DLDI patcher.
PS: loader.bin and bootstub.bin are thus by-products of HBMenu compilation. To get them, you need to gather the latest sources from SVN, compile them (make all is enough provided that you have devkitpro installed with the appropriate libraries), and find them in the hbmenu/data directory.

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 >_<.

Monday, November 29, 2010

7 of 9 -- personal Log

27/11 : quelque soit le code ARM7 que j'utilise (le mien modifié, celui de Tobias ou le code DefaultARm7), runme ne passe pas le cap "sync with 7" sur l'ARM9 ...
28/11 : avec le code ARM7 de Tobias et le code ARM9 de l'exemple httpget.c, je parviens à avoir une transmission WiFi fonctionnelle. C'est donc (contre toute attente) le code ARM9 qui foire.
29/11 : la présence d'IrqInit() dans le code de GuiEngine::prepare() était clairement une des causes d'erreur, mais je ne sais pas encore dire si c'était la seule. Je vais devoir continuer à importer petit à petit les fonctionnalités de runme sur cette nouvelle base pour mettre le doigt sur les éléments perturbateurs.

Seven's log, stardate 201011.27 -- I am trapped in my ARM7 cortical implants. Although I could potentially still communicate with the WiFi collective -- if any was at short range -- I have lost connection with the ARM9 behaviour controller that would allow me to communicate with the crew of the Voyager. I have analysed the defect starfleet fifosystem.c that the Doctor installed to replace my damaged borg implants that is the root cause of my malfunction. The only tool I have to operate is a standard DESMuMe tricorder from the federation filled with irrelevant features, and that reaches only 67.3% of the efficience of a corresponding Borg nanoprobe.

Seven's log, supplemental -- A double initialisation of my interrupt mask might be the cause of this FIFO dysfunction. Deeper inspection of the starfleet FIFO protocol revealed a rigid structure with 16 virtual channels and imperfect typing of messages into one-word addresses, one-word value and external larger dataquads. I will resume my investigation when my refresh cycle is complete.



PS: curieux qu'avec le couple de processeurs ARM7 et ARM9, personne (que je connaisse) n'ai fait le rapprochement entre la DS de nintendo et le borg converti "Seven of Nine" de Star Trek : Voyager, vous ne trouvez pas ?

Note: j'aimerais bien également en savoir plus sur le support des fonctions FIFO dans desmume ... je note par exemple dans la fonction _MMU_ARM9_write32

case REG_IPCFIFOSEND :

  IPC_FIFOsend(ARMCPU_ARM9, val);

  return;

Mais aussi (dans le même fichier FIFO.cpp) des fonctions GFX_FIFOsend, apparemment utilisées par l'implémentation des fonctions 3d -- et qui n'a donc probablement rien à voir dans le cas qui m'intéresse.

PS: to the devkitpro and desmume teams : no offense intended. That's Seven's "personality". Watch season 4 of Star Trek Voyager if you haven't yet: you'll know what I mean.

PPS: here's a patch against svn revision 3601 of desmume that enhance debugging of FIFO by
1) enabling per-direction logging of writes to FIFO registers through the DESMUME_FIFOLOG environment variable
2) uses location 0x04042000 as REG_DEBUG : everytime you write some 32-bit word there, it will be dumped -- together with processor no and PC value -- on STDERR.
I don't think I have "fixed" anything, so it looks like r3601 of desmume-cli already supported the full FIFO features (even though generation of interrupts are a bit obscured and could use some more documentation), but it could certainly help people understanding or validating the fifosystem.c of libnds, or other ARM7 initialisation code.

Friday, November 26, 2010

#undef DSMI

La bonne nouvelle avec le passage au DKP-r32, c'est que du coup, j'ai les bonnes bibliothèques et outils pour compiler le projet NitroTracker d'0xtob ... et donc, que je suis potentiellement un peu plus proche d'un portage de mon support des effets de la libNTXM vers son projet d'origine ... On verra ça ;)

Il se pourrait bien, par contre, que les sources d'0xt0b soient autrement précieuses, puisque mon code ARM7 custom a du mal à passer à la vitesse supérieure, alors que le code d'0xt0b, lui, est déjà prêt à l'emploi. Finalement, il me resterait "juste" à lui ajouter le support de l'exécution d'un autre .nds pour revenir sur les bases nécessaires pour mes outils...

the good thing with the switch to "release 32" of the devkitpro is that I'm now able to compile the Nitro Tracker project -- the one where theNTXM sound library I use originates from. That brings me one step closer to backporting of my own NTXM extension to its seminate project, but also, it means that recycling the ARM7 code of 0xt0b could be more efficient than trying to upgrade my own custom ARM7 code, since Tobias has included support for the WiFi as well.

Wednesday, November 24, 2010

source setup-r32

Bion, un package sources pour Apple Assault, c'est sympa, mais si le code pouvait être compilé avec les versions en date du devkitpro, ça ne serait pas plus mal, hein ? Il faut dire que j'étais resté à la version r21 qui doit dater d'octobre 2007 et sur laquelle j'ai pas mal bricolé entretemps.

I guess it'll make more sense to do a source release if you're able to compile Apple Assault from the source, right ? That's where you'll need devkitpro, the open-source cross-compiling and core-libraries project for homebrew console development ... as it was back in October 2007. Sticking to a working -- but obsolete -- development kit helped me during 3 years to stay focus and work on my tools rather than doing pointless bugfixes, but now it's time to move on. I fear it won't be an easy task, though, as I use a custom ARM7 and so on ... Hopefully, again, the ease of branching with subversion should help a lot.

  • gcc 4.5.1 râle sur char * x = "hello" et insiste pour qu'on ait const char* x = "hello", histoire que la chaîne (normalement considérée comme une constante) ne puisse pas être altérée par le programme. Dans l'absolu il a raison et c'est facile (mais chaint) à corriger... d'autant (C++ oblige) que le code de la bibliothèque doit lui aussi être recompilé pour bénéficier de l'update :P
  • IPC n'existe plus ou a été modifié. Je m'en servais pour gérer la mise en veille de la console ... 'faudra trouver autre chose. Plus gênant, mon code custom pour le côté ARM7 devra sans doute être mis à jour lui aussi, et de manière substancielle.
  • SUB_DISPLAY_CR a été renommé, de même que BGx_CR, BGx_X0 et leur variantes SUB_xxx (pour assurer la cohérence avec GBAtek, ce qui n'est pas plus mal, soit dit en passant). Pas vraiment gênant pour l'exécutable lui-même, mais ça va être pénible pour la mise à jour de mes bibliothèques
Bien sûr, mélanger les libgeds.a ou libpppnds.a de devkitpro r21 avec AppleAssault.o compilé pour devkitpro r32 (libnds 1.4.8, libfat 1.0.7, dswifi 0.3.13) serait voué à l'échec. C'est donc l'ensemble du projet qui a besoin d'être migré >_<

L'alternative, c'est de fourguer libnds, libfat et dswifi précompilé dans le "package sources", mais ça me tente tout de suite moins :P

PS: "source setup-r32" parce que j'ai pris l'habitude d'avoir un script shell nommé "setup" à la racine de chaque projet qui configure toutes les variables d'environnements (CLASSPATH, LD_LIBRARY_PATH, CFLAGS, voire même PATH pour utiliser des cross-compilers) ce qui me permet d'utiliser la commande shell source pour "activer le mode OMNet++" ou "activer le mode devkitpro". En l'occurence, pour devkitpro, j'ai un setup-rxx selon que je veux utiliser la release 19, 20, 21 ... ou maintenant 32.

Sunday, November 21, 2010

Last Minute Panic...

Mouais. Pas si finale que ça, finalement, la version 1.4 d'Apple Assault. En tout cas, elle mériterait bien un bugfix. Un conseil si vous devez faire une pause, fermez la console un niveau, pas entre deux niveaux. Disons que le suivi d'un pattern pour déclencher des actions sur certaines lignes n'aime pas trop qu'on laisse le pattern tourner sur l'ARM7 pendant que l'ARM9 est mis en veille.

It looks like the final release of Apple Assault might need some more tweaking, finally. Anyway, if you need a break during the game, close the lid within a level and not between two levels... You've been warned. Well, let's say the TrackSequence that follows an XM pattern launching actions such as clearing the screen and loading a new level isn't that happy when you suddenly freeze the ARM9 that executes commands while the ARM7 keeps playing the music :-/

I tried a trivial workaround, that slightly improves the situation. But it's not improved enough : there is an interference remaining between fading-out and fading-in actions that may leave the screen partly obscured for the next level >_<


Je croyais contourner le problème facilement mais ce n'est pas si évident: la preuve, le jeu n'est plus bloqué, mais il y a eu interférence entre les opérations avant-veille et après-veille ... et du coup, l'écran reste à moitié noir :P

Par contre, j'ai pu faire une petite démo à Pierrick et Parmy ... et ça, c'était bien chouette ^_^

edit: corrigé

Sunday, November 14, 2010

Bleeps and Bloops...

Je dois avoir découvert Donkey Kong Country II chez un gamin en '96 ou '97, qui m'avais demandé de lui passer un de ces niveaux au-dessus de la lave dans le Chaudron du Croco. Le jeu m'avait fait une forte impression et je sais l'avoir fini sur SNES avant de me lancer dans la chasse au 103% avec ZSNES. Mon frère l'ayant dégotté en GBA -- alors qu'il n'a jamais été très Donkey --, je lui chippe une petite semaine. Hélas, le portage n'est pas à la hauteur de l'original: son "rabotté" qui sonne "début des années 90 sur Amiga" et des graphismes curieusement pauvres en couleurs ... Le gameplay semble être resté assez bien le même, mais garder le bouton 'B' enfoncé pendant tout un niveau se révèle pénible sur DS lite avec mes paluches d'adulte. Déçu, donc, mais intrigué de savoir pourquoi Captain N a ainsi décidé de massacrer un chef-d'oeuvre d'immersion sensorielle pour le faire tenir sur une console près de 10 ans après sa sortie sur SNES ... Voilà ce que j'ai trouvé au niveau du son.

My brother dug two GBA cartridges that we tested last week-end : Donkey Kong Country 2 and Super Mario World -- two major SNES hits that were converted to "prime" the new console. Both turned out to be fairly disappointing, esp. DKC2 that sounds and look like a cheap clone. This post collects pointers to the audio specs of the original Game Boy, the Gameboy Advance and the Super NES in an attempt to explain why the "cool sound" of the SNES couldn't be retrieved and why the SNES tunes usually sound more like MIDI than like tracked music, although the hardware 'looks' tracking-compatible.

Game Boy :

2 square waves, 1 programmable 32-sample 4-bit PCM wave, 1 white noise, and one audio input from the cartridge.[25] The unit only has one speaker, but headphones provide stereo sound (for further information, see Game Boy music)


En clair, au niveau rhytmique, on est proche de ce que fait le beat-voxing: un son masque complètement le précédent. Et celui qui veut faire dire "Ghostbuster ... wha hahahaa !" a sa console doit reprogrammer à la volée le buffer de 16 bytes jusqu'à ce que l'ensemble du sample ait été joué. Oui, quand ils disent "32-sample", ils parlent bien de 32 bytes si le son avait été 8-bit, et de 16 bytes vu qu'on a que 4 bit par échantillon. Rien à voir donc avec le "sample" d'un soundtracker.
Autant dire que quand "Zelda: Link's awakening" nous chante une mouette qui passe, le "z80" ne doit pas être loin du 100% d'utilisation de ses 4MHz tout mouillés (en fait, non. La mouette est faite à coup de square waves, et pour le reste, c'est surtout la technique des wave tables qui est utilisée).

SNES et son SPC-700 -- une sorte de System-on-Chip intégrant un CPU de C64 (6502), des unités de conversion Analogique/Digital, de l'ADSR en hardware, lecture de samples à vitesse variable et mixage hardware pour 8 pistes. 64KB de RAM dédié au contrôle de tout ce petit monde (et aux samples, évidemment) grâce à un programme pour SPC qui aura été "uploadé" depuis le CPU principal de la console. Ca me rappelle un peu le tandem ARM7/ARM9 de la DS, mais en horriblement plus custom :P

GBA :
The GBA supplies four 'analogue' sound channels for Tone and Noise (mostly compatible to CGB sound), as well as two 'digital' sound channels (which can be used to replay 8bit DMA sample data).

La réalité me semble un peu plus tordue: deux canaux de "square wave à timbre programmable", avec enveloppe simplifiée (linéaire, quoi), et un de ces canaux est capable de "portamento" en hardware. On a un canal de bruit (canal#4) et un "chipsound programmable" similaire au canal 3 du bon vieux gameboy. A côté de ça, deux canaux jouent ce qui sort de la ROM (ou de la RAM si on veut faire un modplayer) à grand renfort de transfer DMA -- exactement comme une Sound Blaster 8 bit, donc. De quoi expliquer le "look" si particulier de la bande son de Zelda: Minish Cap qui mélange "sons gameboy" avec des strings orchestraux et des voix numérisées pour les personnages. Pour jouer un .MOD de 4 pistes sur cette console, il faudra faire le mixage et le traitement de la hauteur de la note entièrement en software sur le processeur ARM à 33MHz. Si c'est techniquement possible, on aura sans doute plus grand-chose comme puissance de calcul à dédier au jeu lui-même qui devient une sorte "d'annexe au modplayer" façon Crazy Brix. Il faut aussi rappeler que le GBA a relativement peu de RAM (32K, plus de la "EWRAM" à accès probablement plus lent, mais dont je n'ai pas saisi le rôle précis jusqu'ici), et que si le SPC de la SNES pouvait laisser la lecture des samples au hardware dédié, avec un mixage en software, ça passera forcément à travers le même bus que le reste des données...

I'm pretty sure you remember your good old 486 DX 33 and his soundblaster, right ? That computer had the guts to do software rendering of a multi-track sample-based tune, but still, 90% of the games you can find on any DOS museum site will use AdLib (or clone) for the background music. And for a good reason: doing software real-time mixing of the samples will consume a good deal of your CPU's power. Yet, that .MOD tune you're struggling to play was likely written on an Amiga 500 clocked at 8MHz -- but that had dedicated hardware for bending, shaping and mixing samples. The very same thing occured between GBA and SNES : the GBA inherited from the sound system of the original Game Boy and has a stereo DMA channel to stream something else -- including something that is mixed in real time -- where the SNES had a slower clock speed, but hardware sound mixing.

plein d'infos sur le son du GBC (sauf à quel point celà diffère du GB :P) On notera sur GB et GBC la présence d'une ligne "audio IN" de la cartouche vers la machine. Pas souvent utilisée commercialement, mais ça ouvre la possibilité de monter un soundchip ADlib sur une cartouche GBC pour se faire un remake ultime de Fury of the Furries ;)

Tuesday, September 15, 2009

Debugging sur DS

En règle générale, j'aime encore bien le débugging "à la dure" à grand coup de désassembleur et autres guru meditation, mais de temps en temps, ça ne suffit plus. Je ne suis pas contre le débugging "tea-time" avec une bonne tisane, un fluo et quelques listings, ceci dit ...

I usually enjoy the "guru meditation" kind of debugging, analyzing machine code and registers dump, with a good cup of tea, listings and a "swing" fluo pen. Yet, this time it wasn't enough, so i reused the kind of techniques i've mastered toying with my network processor, a few years ago. Since there are tons of tutos on using GDB in English, I'll focus on trying to give you the feeling of what's going on.
Mais cette fois-ci, c'est le module player NTXM qui tourne sur l'ARM7 qui posait problème, et sur l'ARM7, pas de moyen facile de sortir des messages d'erreur. J'avais bien bricolé un petit mécanisme de "rapport d'erreur" pour libntxm, qui restait désespérément muet. Bref, c'est un peu par chance que j'ai découvert que la version 0.7.3 de desmume (sous Linux, en tout cas) intègre un double "stub GDB". Du coup, moi:

desmume-cli gedsdemo.nds --arm7gdb=6667 --arm9gdb=6669
ln -s `which arm-eabi-gdb` gdb
ddd runme/arm7/runme.arm7.elf &
ddd gedsdemo.elf &
Ca mérite un mot d'explication. GDB est le débugguer intégré au compilateur gcc et g++ dans les systèmes Linux, les distributions cygwin, et le devkitpro. Dans la plupart des cas, on appellera directement le débuggueur avec le programme à corriger sur le système-cible, mais pour le développement embarqué, on sait rarement faire tourner le débuggueur complet sur le système-cible. Dans ce cas, on fait tourner une version minimale du debuggueur (le stub) avec le programme, sur le système-cible (ici, l'émulateur DS) et le front-end peut tourner sur un autre système (le PC linux, en l'occurence). Desmume intègre deux 'stubs', un pour chaque processeur de la DS, et on donne au démarrage le numéro de port à utiliser pour chacun d'eux.

desmume-cli gedsdemo.nds --arm7gdb=6667 --arm9gdb=6669
Gdb is the natural companion debugger in the GNU gcc/g++ compiler suite. It is a command-line debugger with a fairly crude (compared e.g. to Borland's debugger), but very complete and powerful interface. It is naturally available in the devkitpro toolchain as arm-eabi-gdb binary where it can disassemble and understand ARM7 and ARM9 machine code as long as they are in .ELF binaries. To get a fancy environment that lets me browse source and data structure, i use DDD (data display debugger) that acts as a front-end for a gdb session that it will launch and completely manage for you. And as crème de la crème, DDD also provides you a direct interface through the GDB session by means of a console at the bottom of its window, so if some magic button is missing for you to use the gdb tricks you know, just type it and you'll get it.
Ensuite, on démarre le débuggueur en lui donnant le fichier ELF à manipuler. Personnellement, j'utilise ddd (Data Display Debugger), qui permet l'affichage des données en graphe et le suivi de l'exécution dans les sources, en plus de toutes les fonctionnalités de gdb (breakpoints, inspection de la pile et des registres, etc.)
L'astuce est d'expliquer à ddd d'utiliser la version de gdb pour processeur ARM du devkitpro plutôt que la version pour intel propre à ma machine. Il suffit pour ça de créer un lien symbolique du nom de "gdb" pointant vers arm-eabi-gdb dans un des répertoires couverts par la variable $PATH. Dans mon cas, le répertoire courant fait l'affaire.

Reste à expliquer à chacun des gdb qu'il doit s'attacher à un stub existant plutôt que d'essayer de faire tourner lui-même le programme (par la commande run, qu'on aurait utilisé dans une session de débugging classique). Pour ça, j'utilise

target remote localhost:6667
dans la fenêtre qui fait tourner le code ARM7 et

target remote localhost:6669
dans la fenêtre qui fait tourner le code ARM9. Histoire de pouvoir suivre l'exécution des programmes, j'ai donné un "break main" dans chaque fenêtre, histoire d'interrompre le programme lors du début de son exécution en C.

Now, the system you want to debug is different from the system that runs the debugger. You may not be used to it, but remember that it is an über-common situation for people doing cross-compiling, kernel development and embedded systems. Debugging your NDS program with DDD and Desmume emulator just happens to be a specific instance of this problem. The debugged system will have to provide a (lightweight) stub for gdb, that is, a piece of code that blindly grab memory content, dumps registers, enforce breakpoints and stuff. On your debugging system, gdb has the guts to attach to this stub through the "target remote " command. Once attached, it all happens as if your debugged system had an extra process running gdb through a window of your desktop. Enjoy conditional breakpoints, data structure browsing and all ^_^.

Le reste dépend évidemment du problème qu'on cherche à résoudre. Ici, c'était une histoire de communication entre ARM7 et ARM9 (du moins, c'est ce que je croyais). Un breakpoint côté ARM9 sur l'envoi de commandes m'apprend que cette partie-là s'exécute bien sans problème, par contre mon breakpoint sur "calcNextPos" dans le module player n'est jamais appelé. Je passe en revue l'initialisation de l'ARM7 pas à pas et je me rends compte qu'il bloque au niveau de l'initialisation du Wifi ... logique, le code ARM9 pour la démo n'utilisait pas le Wifi. Faute d'un "ppp-nowifi.arm7", j'ajoute un "new Wifi(...); Wifi_Disable()" dans le code de ma démo pour pouvoir faire ma release "dans les temps" (avant le 9/9/2009 :)

PS: pour ceux que ça intéresse, je précise que QEMU (émulateur PC) intègre également un stub gdb, et que pour les autres programmes (p.ex. mes outils sur network processor), il suffit d'utiliser gdbserver qui supporte aussi bien les connexions TCP que le debugging sur cable null-modem.

Ca marche tellement bien que pour les tests que je veux faire sur mon LevelEditor, je vais carrément construire une "version light" (ledsdemo) qui tourne sous desmume et développer les nouveaux widgets, etc. dans cet environnement-là. Je le sens bien.

To conclude, 0xtob's library wasn't to blame if i got no sound: i made a slight mistake in my ARM7 initialisation code that prevented the module player from ever executing. Oh, and btw, yes, I am aware that a GDB stub running on bare DS hardware and accepting connections through WiFi is available. It just haven't been needed so far.

Just one last trick that is handy: ddd comes with tons of options to select the "inferior debugger", but i just prefer symlinking arm-eabi-gdb so that it is found under the name "gdb" when the $PATH is scanned, looking for the command to be run. Aliases won't work here.

Thursday, September 03, 2009

Sound Effects

Bon, il est temps de faire du bruit. Voilà le bout de code de la libntxm qui traite les nouvelles notes lors de la lecture du pattern. Le reste du temps, le player se contente d'ajuster le volume et de traiter les effets définis par une "cell" (une case du pattern).

Pour pouvoir faire des effets sonores, il faudra en quelques sortes que j'appelle ce même code à la demande depuis le processeur ARM9, probablement en réutilisant la technique d'IPC qui a servi à indiquer que le module devait être lancé ou arrêté (cf. NTXM7::updateCommands et le fichier command7.cpp)

It's been roughly 1 year that my game engine is waiting for sound effects. Let's see how to proceed, and add them to the ARM7 NTXM player that is the core of sound playback on the DS. This post is a sort of "exploration mission" to see how i'll proceed with programming them.
Primo, if i want to issue sound effects, the first thing to do is to ensure that I can invoke the "playNote" function (and surrounding code) on request from the game engine running on ARM9 . The most likely approach will be to mimmic the IPC approach 0xtob used to instruct the ARM7 to start or stop playing the whole song.
Funny enough, all the "commands handling code" always look the same. PLAY_SAMPLE and PLAY_INST commands already exist (i guess 0xtob needed them for the nitrotracker), but the actual stubs are missing. On the other hand, the "proxy" functions at the ARM9 are already present in command9.cpp ; they just lack an API in ntxm9.cpp ...

It should be running in a couple of evenings. It's really a shame it took me so0o long to check it out. It sounds that most of the effort will be to make GobExpression invoke ntxm9::playNote(), after all.

Tss. Même après l'an 2000, tous ces codes de "gestion des commandes" se ressemblent. PLAY_SAMPLE et PLAY_INST existent déjà, j'ai même déjà struct PlayInstCommand. Ils ne sont juste pas encore implémentés, mais Oxtob a bien préparé le terrain, pas de doute. Eh bien on va y remédier.
Cerise sur le gateau: CommandPlayInst et CommandStopInst sont déjà là dans command9.cpp ... Il reste juste à ajouter ça à NTXM9 et à faire en sorte que ce soit appelable depuis le GameScript et confrères.

edit: okay. Ca marche. Les pommes font "bzing!" quand on les prend. Il a fallu un peu plus de code que prévu du côté du game engine: c'est la première fois qu'une GobExpression du script appelle du code C++ ;)

Wednesday, July 29, 2009

powersave

Jusqu'ici, mes petits programmes étaient plutôt dévoreurs de batterie sur la DS. J'avais beau dire à mes p'tits n'veux que "tu fermes ta DS et tu viens manger tes frites, le jeu sera toujours là quand tu auras fini", c'était loin d'être le cas pour Bilou ou mon sprite editor.

Et pourtant, le fonctionnement est plutôt simple: un registre (REG_POWERCNT dans libnds et POWCNT1 sur gbatek) permet d'activer ou de désactiver certaines puces de la DS pour réduire la consommation. Côté ARM7 (connu alors sous POWCNT2), il contrôle le son et le Wifi. Côté ARM9, il contrôle les processeurs graphiques, permettant d'activer ou de désactiver séparément la 2D, la 3D, etc. Tout ce qu'il y a à faire, c'est :

if (lid_closed()) {
u16 power = REG_POWER;
REG_POWER = 0;
while (lid_closed()) swiWaitForVBlank();
REG_POWER = power;
}
la position du capot étant donnée par le 7eme bit des "boutons" de la console. Le coeur du fonctionnement étant évidemment la boucle "while(lid_closed) waitForVBlank() qui va utiliser les fonctions du BIOS de la DS pour mettre le CPU en pause jusqu'à ce qu'une interruption se produise (en l'occurrence un retour d'écran), et ce en continu tant que le capot est fermé. Au lieu d'exécuter 66 millions d'instructions par secondes, le processeur se contentera alors d'environ 600 à 1200 d'entre-elles (à la grosse louche, hein) et le rendu graphique est désactivé.

Evidemment, pour faire "pro", il faudrait aussi signaler au co-processeur (l'ARM7) de mettre en berne le son (sauf si on programme un iPoDS) et le Wifi (sauf si un transfer de fichier est en cours). En clair, si l'ARM7 pourrait gérer sa puissance de manière autonome, il reste préférable de le reléguer dans un rôle d'esclave.

Ma première tentative pour appliquer ça n'a pas été franchement probante, mais quelques "printf" m'ont vite révélé mon erreur : je n'ai encore aucune routine d'interruption pour le 'retour d'écran' (VBLANK) et les interruptions VBLANK sont carrément masquées par mes programmes. Résultat, swiWaitForVBlank() attend indéfiniment :P Si j'y remédie et que je passe à du "waitForVBlank" dans ma boucle principale également, c'est toute l'application qui devrait devenir nettement moins gourmande.
while(REG_VCOUNT>192); // wait for vblank
while(REG_VCOUNT<192);
c'est indigne d'un vétéran. Quand mes étudiants codent comme ça, je les menace de leur imposer de coder sous DOS.

Et si je vous raconte tout ça au conditionnel, c'est que mon routeur WiFi à la maison m'a lâchement laché, rendant le développement DS aussi pratique qu'à Bâle, le temps libre en moins.

edit: après essai, curieusement, le son est mis en veille lui aussi, automatiquement et sans communication explicite de ma part entre ARM7 et ARM9 ... Ne loupez pas non plus le commentaire très intéressant de thoduv (lapinou jumps) pour passer de la théorie à la pratique "pro".

Tuesday, August 19, 2008

32x32 : ça y est (presque?)

Je vais éviter de crier définitivement victoire trop tôt, mais je crois que cette fois-ci, je tiens le bon bout pour l'édition en mode 32x32. Preuve en est ce 'chibby commander keen' bidouillé "en vitesse" avec la bonne vieille palette EGA (plus une petite couleur qui joue les trouble-fêtes :P

L'est-y pas mignon ^_^
plus inspiré par le webcomic de bob que par les vrais jeux EGA, en fait.

I came up with this chibby Commander Keen as result of my experiments with the 32x32 editing mode of my sprite editor tonight. (yes, fairy is away, that means too much pixeling and midnight coding for my health and funny eyes in the morning %P) Kinda cute, isn't he ? All i hope is that i didn't erase anything important while saving him before beaming up to the Web. It's really about time i make that "backup system" when overwriting sheets or at least that i give SEDS the ability to beam things without altering the existing spriteA.spr..spriteY.spr files.

J'espère juste n'avoir rien perdu dans le transfert. Il serait vraiment temps

  • [done] que je remette en place les fichiers .bak quand on sauve
  • [wish] que je permette de voir ce qu'il y a dans les différents fichiers au moment de sauver...
  • [wish] ou au pire, que j'autorise l'export d'une page isolée par le Wifi...
  • [done] vérifier que les animations, les copies, les effacements et tout ça fonctionne toujours.
  • [done] zoom pour changer la taille de grille en cours d'édition.
  • [done] pouvoir choisir la taille des blocs quand on construit une nouvelle page
  • [wish] support des sprites "rectangulaires" 16x32, 16x8, etc.
  • [done] "overlay sprite over current grid content", p.ex. avec B en mode curseur.
  • [done] tri automatique des couleurs par QuickPal (via le bouton 'scan')
  • [done] remettre en route la fenêtre d'édition de palette qui ne marche plus du tout ^^"
et toujours, pour LEDS
(wouw. finalement, ça fait une belle liste tout ça)
Ensuite, on pourra lancer la release ... je sais pas moi ... 0.3.2 ?

*edit*: oh. Bonne nouvelle. Depuis la correction de l'ARM7 (ou la mise à jour de desmume ?) SEDS, malgré son wifi, peut tourner sur desmume (et peut-être d'autres émulateurs ? l'avenir nous le dira ;)