owned this note
owned this note
Published
Linked with GitHub
# Three donkeys.
TODO: Merge with Raymond Tracing.
[Bande-son](https://psygnosis.bandcamp.com/album/n-e-p-t-u-n-e)
Au programme :
* De la 3D en assembleur, plus lumineuse qu'un quasar.
* Comment remplacer 4 multiplications par 2.
* Un orgams par jour : utilisation des imports.
Autrement dit : rapide, propre, éthique, choisissez-en 3.
A l'heure où j'écris (et la demi-heure suivante), les imports orgams souffrent de graves restrictions, décrites dans [la notice](http://orgams.wikidot.com/userguide#toc38).
Ils autorisent neanmoins un soigneux découpage modulaire, tel que démontré dans cette page.
Le programme d'exemple est la version assembleur du tore basic et basique décrit [ici](https://64nops.wordpress.com/2021/01/21/rosetta-sugar-japprends-a-coder-avec-mon-cpc/). Seule la rotation suivant l'axe X est gérée. Cela dit:
* Il est trivial d'enchainer avec une rotation selon un autre axe.
* Cela serait même plus rapide qu'avec une matrice de rotation complète (reste à prouver), ne totalisant que 4 ou 6 multiplications.
Par ailleurs, la précision est moindre (8 bits plutôt que flottant sur 40 bits). Ce n'est pas non plus un effet de demo ultra-optimisé, à dessein. On cherche ici un bon compromis simplicité / vitesse.
Chaque module est tellement clair et bellement documenté (dixit mon agent) que seule une petite présentation s'impose.
## Params.i
J'utilise l'extension `i` (comme import / include / input / iconoclaste) quand le source ne genere pas de code. Assembler un tel source isolement n'aurait pas d'utilite.
Il est plus clair et plus flexible de regrouper les parametres dans un source dedie, Didier, selon les gouts. Observez que ce meme fichier est importe par `main.o` et `objtorus.o`
## Profile.o
Mesure grossiere du temps machine (+/- 3.34 millisecondes aka 52 lignes rasters). Utilise le firmware, d'où le préfixe pour éviter les bourdes.
Une version non-firmware (incrément d'un compteur sous interruption) est laissée comme exercice au lecteur.
Une version précise à la micro-seconde est disponible à la rédac. Le principe est simple et efficace : on se synchonise sur une interruption, on appelle la routine à mesurer, puis on compte le nombre de nops jusqu’à la prochaine interruption.
* Pour les routines < 52 lignes raster, aucune contrainte.
* Pour les autres, une combinaison des approches devient nécessaire, ce qui implique d'autoriser les interruptions et l'écriture sur la pile de deux mots (sauvegarde de PC et HL).
WIP! Cf article 2.
## ObjTorus.o
On génère une fois pour toute les coordonnées de l'objet souhaité.
* Pro: Expressions numériques d'orgams à disposition (sin, cos, division, ...).
* Con: Ne permet pas de changer les attributs de l'objet de façon dynamique.
* Con: Moins compressible.
```
objtorus.o
; dots# * X, Y, Z coordinates (one signed byte each).
r1 = 200
r2 = 30
; Static generation: done at assembly time.
; The slowness of this operation (xx secondes)
; is one remaining weakness of Orgams (with its knees).
; But since it's imported, it will be assembled only once,
; due to caching mecanisme.
```
Maintenant, il y a deux façon d'injecter ces données.
### Via Import
* Pro: Permet de changer facilement les paramètres en phase de mise au point.
* Pro: Calculé seulement une fois par session, et non pas à chaque assemblage (sauf quand paramètres modifiés).
* Con: Calculé une fois par session (c'est une fois de trop quand on est habitué à la réactivité d'un CPC).
### Via Binaire
Enregistrer le binaire, et le charger depuis le source principale.
## Math.o
## MathT.o
Tests unitaires, kezako ?
En programmation de jeux ou de demos, le visuel nous rassure rapidement sur le comportement correct des routines.
Quand le résultat est inattendu, comment corriger ? Debugguer pas à pas est long et fastidieux. Une bonne approche est de rajouter des assertions, statiques et dynamiques (voir article 1).
L'idée présentée ici est de vérifier (tester) mécaniquement les routines isolées (unitaires).
Par exemple, plutôt que de mettre un breakpoint pour vérifier manuellement le bon résultat d'une routine `A` (valeur ou table), pourquoi ne pas écrire un routine auxillaire (le fameux test unitaire) qui va exécuter A et comparer avec la valeur attendue.
Avantage collateral : une fois `A` corrigee (une bonne fessee bien sentie et consentie), si elle est ulterieurement peaufinee (e.g. pour la rendre plus docile ou rapide), le test aidera à garantir qu'on ne re-introduit pas de bug. C'est pour cela qu'on entend aussi le terme "test de non-regression" dans les quartiers rouges de la ville.
Maintenant, la portion de code à analyser n'est peut-etre bien isolee en tant que routine a appeler, mais nage au milieu d'un flux de code tumultueux.
Deux options dans ce cas : macro ou hamecon.
Dans ce source d'exemple, on compare pour un millier d'entrées distinctes le résultat de la routine avec chaque valeur de référence calculée statiquement par orgams (successifs). C'est bourrin, pour citer la baronne de Rotchschschild.
Une approche plus ingénieuse est de comparer avec une routine de référence, qui n'a pas à être particulièrement rapide (par exemple, multiplication `B*C` en ajoutant `C`, `B` fois, via une boucle `djnz`).
Mais bon, parfois, un petit "quick & dirty" s’avère plus que satisfaisant (toujours la baronne).
On agrémentera le moteuuur de test en affichant le nombre de tests, le nombre d'échecs, etc.
Dans cet exemple, seul le minimum syndical se voit fourni :
* Succès : le code revient à Orgams sans se plaindre.
* Echec : un breakpoint est émis quand la réalité ne rejoint pas les espérances. L'affichage `stack trace` permet de voir quel test est pris en défaut.
## Rotate.o
## Proj.o
## Display.o
## Main.o
Chef d'orchestre, point d'entrée du projet. Le nom est arbitraire, `main` est une convention fréquente, on s'en fout.
Assembler (CONTROL-1) ce source chargera toutes les dépendances, ce qui devrait faire plaisir à Hicks, à moins qu'il ne soit encore d'humeur bougonne.
Ce source ne consiste qu'à appeler les diverse routines. Avantage collatéral : donne une bonne vue d'ensemble du programme.
Si l'on souhaite conserver cette belle propriété sans appels intempestifs, on remplacera les `calls` par des invocations de macros cross-sources. Mais ce n'est pas encore supporté dans Orgams. Quelle bande de nazes !
# Conclusion
La phrase précédente était déjà une forte conclusion, applicable dans de nombreux contexts.
Maintenant, il ne reste plus qu'a mettre en place un dépot de routines (a voir: reutiliser https://rasmlive.amstrad.info/)?