180

Non non, le but de l'union est bien de pouvoir présenter différentes représentations d'une même donnée, typiquement voire une structure comme un tableau d'octets, ou un entier comme un champ de bits, selon. Et là, tu serais en plein cas d'école pour le faire happy
avatar
Que cache le pays des Dieux ? - Forum Ghibli - Forum Littéraire

La fin d'un monde souillé est venue. L'oiseau blanc plane dans le ciel annonçant le début d'une longue ère de purification. Détachons-nous à jamais de notre vie dans ce monde de souffrance. Ô toi l'oiseau blanc, l'être vêtu de bleu, guide nous vers ce monde de pureté. - Sutra originel dork.

181

Bon ben impeccable. Ma vision était celle de l'optimiseur en asm, qui fait le cno avec son stack-frame pour le réduire à mort de deux ou quatre octets, même si ça sert strictement à rien. grin

Je suppose que cetet vision m'a été donnée parce que dans le failli bouquin que j'ai, il s'apesantissent sur le fait que la taille de l'union est celle de son plus long élément, ie pour un long et un char ça fera 4 octets, donc on imagine immédiatement une utilisation différente, pas juste une histoire de type différent.

182

Ah oui c'et mignon ça, mais je vais faire comment pour nommer les membres de ma structure ?
Voici mon union :
typedef union
{
	WIN_RECT;
	short x0,y0,x1,y1;
} WINRECT;

Et la structure dans laquelle je veux l'utiliser :
struct Misc
{
	short	CursX0;
	short	CursY0;
	short	CursX1;
	short	CursY1;
	...

Si j'écris ça :
struct Misc
{
	WINRECT
	...

Je fais comment après, pour faire un Data.CursX0, Data.CursY1 etc ?

183

Je ne comprends pas en fait. Si WIN_RECT est déjà une structure dont les quatre membres sont quatre shorts, et que ce à quoi tu veux accéder ce sont lesdits shorts, tu n'as même pas besoin de faire une union, il suffit d'accéder aux membres de la structure ?
il suffit que dans struct Misc tu mettes un membre WIN_RECT Rect; à la place des quatre shorts
et ensuite tu remplaces Data.CursX0 par Data.Rect.NomdupremiermembredeWIN_RECT, et hop ^^



Sinon pour répondre à ta question je ne connais pas bien les union, mais à mon avis ta déclaration n'est pas bonne. D'abord le membre WIN_RECT devrait avoir un nom, pas juste un type, et ensuite il me semble que là x0, x1 etc. sont déclarés comme des membres différents, ça ne va pas. Il faut les mettre soit dans une structure soit dans un tableau, pour que ce soit un seul élément.
en fait il faudrait un truc du genre :
typedef union {
WIN_RECT Rect;
struct {short x0, y0, x1, y1;} Curs;
} WINRECT;

et struct Misc {
WINRECT Rect;
...

et pour Data.CursX0 tu fais : Data.Rect.Curs.x0
mais c'est plus compliqué que ma première proposition et je suis pas sûr que ce soit plus utile ^^
avatar
« Le bonheur, c'est une carte de bibliothèque ! » — The gostak distims the doshes.
Membrane fondatrice de la confrérie des artistes flous.
L'univers est-il un dodécaèdre de Poincaré ?
(``·\ powaaaaaaaaa ! #love#

184

Bien vu, ça doit marcher ce que tu proposes, vu que je viens décrire ça :
	SCR_RECT Rect;
	Rect.xy.x0 = (char)Data->CursX0;
	Rect.xy.y0 = (char)Data->CursY0;
	Rect.xy.x1 = (char)Data->CursX1;
	Rect.xy.y1 = (char)Data->CursY1;
	PortSetPlane(Planes);
	ScrRectFill(&Rect,&Data->Clip,Data->FrameModePlane0);

top

SCR_RECT est défini ainsi :
typedef union { 
 struct { 
 unsigned char x0, y0, x1, y1; 
 } xy; 
 unsigned long l; 
} SCR_RECT; 

185

Erf... je suis pris de gros doutes...
J'ai écrit ça :
typedef union
{
	WIN_RECT;
	struct {short x0,y0,x1,y1;};
} WINRECT;

Donc j'ai pas nommé l'union.
Et ma structure :
struct Misc
{
	WINRECT	Curs;
	short	CursModePlane0;
	short	CursModePlane1;
	...

Pourtant, quand je fais un Data.Curs.y0, ça a l'air de marcher (ie ça compile sans rien dire).
Mais il me dit que le type de pointeur est incompatible si j'écris Data->Curs.y0
Où est-ce que je merde ?

(ok, je devrais faire plus simple en utilisant directement la structure WIN_RECT telle qu'elle est proposée, mais pourquoi ça marche pas ???)

186

Sally (./175) :
je suppose que c'est un ROM call, il te donne juste son adresse...

Oui, *(*200u+1620u), c'est le ROM_CALL nº1620/4.
Folco (./176) :
Ok, j'avais pas pensé à caster, chsuikon ! Je déclare pas ça en WIN_RECT, parce que ces données (4 shorts) me servent tantôt à afficher un point (là faut des shorts), une ligne (idem), ou des rectangles (et là, on est sur du WIN_RECT)...

Et ben, tu le déclares en WIN_RECT, et tu utilises Data->CursX0.x0 etc. comme il faut quand tu as besoin des short directement.
Folco (./177) :
Et voilà, ça, ça marche :
DrawClipRect((WIN_RECT*)&(Data->CursX0),&(Data->Clip),Data->RectangleModePlane0);

Ce cast est une violation des règles d'aliasing, tu n'as pas le droit de faire ça, même si ça a l'air de marcher.
Folco (./185) :
Donc j'ai pas nommé l'union.

C'est une union anonyme, tu peux accéder à ses éléments directement sans passer par un nom d'union. C'est une extension GNU. (Et insérer WIN_RECT; sans nom est une extension de Visual C/C++ que GCC gère avec le flag -fms-extensions, activé par défaut dans TIGCC (en interne dans le compilateur).)
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

187

Au fait, plutôt que de passer le pointeur de ma structure contenant les variables principales à un peu toutes les fonctions, ne serait-il pas mieux de déclarer cette variable externe ? Quelle différence celà ferait-il au niveau du code généré ? Quels avantages ou quels inconvénients ?

188

C'est difficile de répondre de manière exhaustive ET courte à ton post grin
Le tutorial TICT S1P9 (dans le SVN ExtGraph, mais il n'a pas dû changer depuis 2.00 Beta 5) contient quelques infos là-dessus.

Premièrement: est-ce que tu veux TOUT stocker, y compris des choses que tu pourrais mettre en arguments des fonctions, dans ta struct ?
C'est le style d'architecture mémoire partagée: communication par les variables globables. L'avantage principal est l'efficacité, mais ça réduit la debuggabilité et la maintenabilité.

Passer un argument supplémentaire (un pointeur vers la struct) aux fonctions est tolérable, mais passer trop d'arguments aux fonctions est une très mauvaise idée pour l'efficacité et la maintenabilité. Voir Pinball89.
Si tu ne veux pas passer un argument supplémentaire à tes fonctions, plusieurs solutions:
* tu peux déclarer la variable externe et c'est tout, sans utiliser d'adressage direct par rapport à un registre. C'est ce que font la plupart des programmes de TICT (qui n'utilisent en général pas une struct pour stocker les variables principales, mais plusieurs variables globales). Les accès en lecture peuvent être pc-relatifs, pas ceux en écriture (xxx.l relogés).
* tu peux mettre la variable externe en tant que global register variable (dont l'adresse est initialisée au début du programme, d'une manière ou d'une autre). Accès reg-relatifs non relogés en lecture ET en écriture. J'ai utilisé cette solution quelques fois, je sais que Flanker l'a fait aussi dans son shell (avec a6, il me semble).
* tu peux compiler tout ton programme en register relative (-freg-relative-an), qui permettra d'avoir, en plus des accès reg-relatifs non relogés en lecture ET en écriture, des jumps reg-relatifs non relogés.


N'hésite pas à demander plus de détails grin
Là, j'ai surtout mentionné les options qui s'offrent à toi, et peu la façon de les utiliser.
avatar
Membre de la TI-Chess Team.
Co-mainteneur de GCC4TI (documentation en ligne de GCC4TI), TIEmu et TILP.
Co-admin de TI-Planet.

189

Personnellement, je déconseille l'antipattern de la grosse structure passée à toutes les fonctions, quelle que soit la méthode. Comme je l'ai déjà dit plus haut, il est beaucoup plus propre de se limiter à passer les variables que la fonction utilise réellement.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

190

Ah ! Je suis intéressé, voilà des réponses concrètes au niveau de ce qui se cache derrière le compilateur. grin
En asm, j'utilise la même technique que Flanker et toi visiblement, j'utilise un stack-frame pointé par a6 partout dans le programme (et l'alias %fp pour %a6 est ici très explicite). C'est en fait ce qui me conviendrait, bien sûr.
J'ai essayé les variables globales, elles étaient mises en BSS (ou alors j'ai vraiment raté un truc), c'est pour ça que je me suis tourné vers autre chose.

Pour la maintenabilité/débogage, j'accède toujours à mes stack-frames de manière très propre (ie par le frame pointer + offset à chaque accès). Pas de hack d'adressage. Ca reste donc normalement très lisible et maintenable, pas dur à déboguer. En tout cas, j'ai eu aucun souci avec ça en asm.

Maintenant que tu connais mon avis, je t'attends pour la suite. grin

191

Kevin Kofler (./189) :
Comme je l'ai déjà dit plus haut, il est beaucoup plus propre de se limiter à passer les variables que la fonction utilise réellement.

Passer un pointeur j'imagine ? Comment fait cette fonction pour modifier la variable sinon ?

Et puis ça doit pas être efficace pour deux sous ton truc, ça nécessite une première copie en RAM de la valeur, ou un pea de l'adresse de l'élément choisi si on passe un pointeur, et ensuite une relecture en RAM pour, par exemple, reconstituer une pile de paramètres en vu d'appeler un ROM call. Ca fait beaucoup d'accès mémoire alors qu'on en fait un au maximum avec un passage de pointeur de structure.

192

./190 -> C'est une manière de programmer très "ASM", ça. En C, normalement, chaque fonction a son stack frame, tu n'utilises pas un stack frame partagé partout, il faut passer les variables dont la fonction se sert en argument. Dans un langage de moyen (C) ou haut niveau, une fonction a des entrées et des sorties, on ne lui donne pas accès à toute l'information contextuelle du programme entier.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

193

Folco (./191) :
Passer un pointeur j'imagine ?

Seulement si tu dois pouvoir modifier la valeur de la variable, ce qui est plutôt déconseillé en général (il y a la valeur de retour pour ça en général).
Et puis ça doit pas être efficace pour deux sous ton truc, ça nécessite une première copie en RAM de la valeur, ou un pea de l'adresse de l'élément choisi si on passe un pointeur, et ensuite une relecture en RAM pour, par exemple, reconstituer une pile de paramètres en vu d'appeler un ROM call. Ca fait beaucoup d'accès mémoire alors qu'on en fait un au maximum avec un passage de pointeur de structure.

C'est une histoire de lisibilité, pas d'efficacité.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

194

Ah ben putain... Je comprends pourquoi tu conseilles du 5 fps dans les jeux, toute façon avec des techniques pareilles on doit même pas arriver à 3. gnimod

195

J'ai essayé les variables globales, elles étaient mises en BSS (ou alors j'ai vraiment raté un truc)

Si elles ne sont pas explicitement initialisées, et que les BSS ne sont pas désactivés, elles sont mises en BSS.
Sinon, elles sont mises en .data.

En général, je conseille (cf. S1P9) de désactiver les BSS (ou de les merger avec la section .data, ce qui revient au même) pour des raisons d'efficacité: les BSS sont accédés à travers des xxx.l relogés, en lecture et en écriture...


Je vais essayer de te retrouver un exemple d'utilisation d'une global register variable. J'ai moins utilisé les global register variables que -freg-relative-an.
[EDIT: ah ouais, mais je n'ai pas TIGCC/GCC4TI sur cette machine. Ca va être plus difficile de trouver et surtout, de re-tester...]

Ah, un truc: fais attention si tu utilises la global register variable (ou le registre à partir duquel les accès dans le programme sont faits, c'est pareil) dans un handler d'interruption. Il faut, dès le début du handler, réinitialiser le registre correspondant. Sinon, tu risques le gros crash grin
avatar
Membre de la TI-Chess Team.
Co-mainteneur de GCC4TI (documentation en ligne de GCC4TI), TIEmu et TILP.
Co-admin de TI-Planet.

196

Attention, code TRES moche (et non re-testé), représentant d'une époque où on définissait encore les directives pour la compilation de TIGCCLIB dans le source (au lieu de les définir globalement dans le TPR, si on utilise un TPR). C'est une libre modification de l'exemple "Progress Bar" de TIGCC, qui a commencé comme test ("tiens, qu'est-ce que ça fait si on remplit la structure à la main pour mettre une progress bar super grande ?"), et montre à quel point AMS sux pour la vitesse...
Je précise aussi que j'ai fait exprès d'aller, quand j'ai fait cette optimisation, de l'autre côté de la limite des normes de lisibilité et de propreté. Ceci dit, un programmeur ASM comme toi devrait tout de suite comprendre la copie manuelle de structure WIN_RECT grin

// Progress bar example for TIGCC
// Optimized version, the old version is left commented after this one.
// Compilation options: -O3 -Wall -W -Wwrite-strings -Wa,-l
// (-Os generates bigger code !)
//
// We could even replace the calls to the system timer functions by
// waiting loops in plain assembly. That would reduce the size, while
// not being a problem, since we don't need accuracy here...

#define USE_TI89              // Compile for TI-89
#define USE_TI92PLUS          // Compile for TI-92 Plus
#define USE_V200              // Compile for V200

#define MIN_AMS 200           // Compile for AMS 2.00 or higher
#define NO_CALC_DETECT

#define NO_EXIT_SUPPORT
#define OPTIMIZE_ROM_CALLS

#include <tigcclib.h>         // Include All Header Files

ST_PROGRESS_BAR spb = {NULL, {0, 0, 0, 0}, 0, 0, 100, 100, 0};
// Using that trick, we can reduce size.
register ST_PROGRESS_BAR * spbptr asm("%a2");

// Main Function
void _main(void)
{
  short j;

  spbptr = &spb; // Initialize the global register variable.

  WINDOW w;
  WINDOW * wptr = &w;

  // WIN_RECT is 8 bytes...
  WIN_RECT * winrect = ScrToWin (ScrRect);
  *(unsigned long *)((unsigned char *)spbptr+OFFSETOF(ST_PROGRESS_BAR,rect)) =
      *(unsigned long *)winrect;
  *(unsigned long *)((unsigned char *)spbptr+OFFSETOF(ST_PROGRESS_BAR,rect)+4) =
      *(unsigned long *)((unsigned char *)winrect+4);
  
  spbptr->physwidth = spbptr->rect.x1 - spbptr->rect.x0 + 1;
  WinOpen (wptr, (WIN_RECT*)((unsigned char *)spbptr+OFFSETOF(ST_PROGRESS_BAR,rect)), WF_SAVE_SCR | WF_NOBORDER);
  spbptr->w = wptr;
  
  spbptr->value = 0;
  
  for (j = 0; j < 20; j++)
    {
// The function is so slow if the progress bar is huge, that no waiting loop
// is necessary !
      OSFreeTimer (USER_TIMER);
      OSRegisterTimer (USER_TIMER, 2);
      while (!OSTimerExpired (USER_TIMER)); // Wait a little...
      ST_progressIncrement (spbptr, 1); // Increment the progress bar by 1/100.
    }

  ST_progressUpdate (spbptr, 50); // Increment the progress bar up to 50/100.
  OSFreeTimer (USER_TIMER);
  OSRegisterTimer (USER_TIMER, 20);
  while (!OSTimerExpired (USER_TIMER)); // Wait for about 1 second...

  OSFreeTimer (USER_TIMER);
  ST_progressUpdate (spbptr, 100); // Fill the progress bar entirely.
  GKeyIn (NULL, 0);

  // ST_progressDismiss does nothing if the progress bar is in a window.
  ST_progressDismiss (spbptr); // Remove the progress bar, redraw status line.
  WinClose (wptr);
}
avatar
Membre de la TI-Chess Team.
Co-mainteneur de GCC4TI (documentation en ligne de GCC4TI), TIEmu et TILP.
Co-admin de TI-Planet.

197

Merci pour ça Lionel.

Question, si ma structure, je la déclare extern, chaque fonction va y accéder, ie si le compilateur est con chaque fonction va faire un lea dessus, ça serait déjà une solution pas mal, non ? En tout cas, mieux que le passage d'un pointeur.

198

Lionel Debroux (./195) :
Je vais essayer de te retrouver un exemple d'utilisation d'une global register variable. J'ai moins utilisé les global register variables que -freg-relative-an.
J'ai aussi donné un exemple dans l'autre topic hehe (et moi, en plus, j'en utilise trois cheeky)
avatar
« Le bonheur, c'est une carte de bibliothèque ! » — The gostak distims the doshes.
Membrane fondatrice de la confrérie des artistes flous.
L'univers est-il un dodécaèdre de Poincaré ?
(``·\ powaaaaaaaaa ! #love#

199

(oui, oui, ton header, j'ai pas oublié cheeky)

200

Ca serait effectivement un peu mieux que de passer un pointeur, mais moins bien qu'avec la global register variable, qui n'aurait qu'un lea dans le _main (plus, éventuellement, un lea dans les handlers d'interruption).

En réalité, le seul truc sale, dans le code que j'ai posté, est la copie manuelle de WIN_RECT.
(WIN_RECT*)((unsigned char *)spbptr+OFFSETOF(ST_PROGRESS_BAR,rect))
n'est qu'une façon typique ASM d'écrire
&(spbptr->rect)
avatar
Membre de la TI-Chess Team.
Co-mainteneur de GCC4TI (documentation en ligne de GCC4TI), TIEmu et TILP.
Co-admin de TI-Planet.

201

Ok. Pour faire gaffe aux handlers d'interruption, t'inquiète pas on se vautre pareil en asm la première fois. grin
En tout cas, merci pour la réponse. On verra ptêt dans un second temps le registre global. Je veu me cantonner aux C pur pour le moment. smile

202

Tiens, je comprends pas cette écriture :
*(unsigned long *)((unsigned char *)spbptr+OFFSETOF(ST_PROGRESS_BAR,rect)) = *(unsigned long *)winrect;
c'est quoi la différence avec
(unsigned long *)((unsigned char *)spbptr+OFFSETOF(ST_PROGRESS_BAR,rect)) = (unsigned long *)winrect;
ie si on vire les deux étoiles à la gauche de chaque membre ?

203

Ben le premier lit le unsigned long qui se trouve à l'adresse pointée par winrect et le recopie à l'adresse spbptr+machin.
Le second... n'est pas du C en fait, en l'occurrence grin. Je prends un exemple simplifié :
*bidule = *(unsigned long*)winrect;
lit un unsigned long à l'adresse pointée par winrect et le recopie à l'adresse pointée par bidule

bidule = (unsigned long*)winrect;
lit l'adresse stockée dans le pointeur winrect et la recopie dans le pointeur bidule.
Là en l'occurrence c'est correct, mais si à la place de bidule (une variable) tu as une expression compliquée, ça ne veut plus rien dire (tu essayes d'écrire dans une expression, ça n'a pas de sens...)
avatar
« Le bonheur, c'est une carte de bibliothèque ! » — The gostak distims the doshes.
Membrane fondatrice de la confrérie des artistes flous.
L'univers est-il un dodécaèdre de Poincaré ?
(``·\ powaaaaaaaaa ! #love#

204

Ah ok. Je me suis laissé piéger par les long*. Bref, je me comprends grin

205

Un autre exemple (moins lisible trioui) d'utilisation de * (avec la seule occurrence de "&*" que j'ai jamais vue, ici pour transformer "type[n]" en "type* n"):
#define DEREFSMALL(__p, __i) (*((typeof(&*(__p)))((unsigned char*)(__p)+(long)(short)((short)(__i)*sizeof(*(__p))))))
Courtesy of Kevin.

Pour donner une idée de ce que ça fait: c'est une macro de ce genre qu'il faut pour écrire HeapDeref tel qu'elle est sous AMS 1.xx, au lieu d'utiliser tout simplement HeapTable[ i ] (qui donne le code d'AMS 2.xx et 3.xx).

[EDIT: merci squalyl grin]
avatar
Membre de la TI-Chess Team.
Co-mainteneur de GCC4TI (documentation en ligne de GCC4TI), TIEmu et TILP.
Co-admin de TI-Planet.

206

rhah je kiffe ce genre de macro trilove trilove
par contre [ pre ] [ /cite ] ça marche pas grin

207

Ben putain la douche froide !!!

J'ai défini ça :
struct Misc
{
	WIN_RECT	Curs;
	short	CursModePlane0;
	short	CursModePlane1;
	short	LineModePlane0;
	short	LineModePlane1;
	short	CircleModePlane0;
	short	CircleModePlane1;
	short	EllipseModePlane0;
	short	EllipseModePlane1;
	short	RectangleModePlane0;
	short	RectangleModePlane1;
	short	FrameModePlane0;
	short	FrameModePlane1;
	short	Tool;
	short	Cursor;
	short	Flags;
	short	CircleRadius;
	short	EllipseAxe1;
	short	EllipseAxe2;
	SCR_RECT	Clip;
} DrawingData;

extern struct Misc DrawingData;

J'accède donc plus qu'avec des DrawingData.Curs.coordonnée, ou encore DrawingData.FrameModePlane0 etc...
Et maintenant, au lieu de 0 relogements, j'en ai 33 !!! fou

208

pourquoi tu déclares ta structure deux fois de suite dont une extern ? tu peux mettre extern dans la première déclaration, ça devrait marcher ^^
avatar
« Le bonheur, c'est une carte de bibliothèque ! » — The gostak distims the doshes.
Membrane fondatrice de la confrérie des artistes flous.
L'univers est-il un dodécaèdre de Poincaré ?
(``·\ powaaaaaaaaa ! #love#

209

Parce que si je fais "extern struct Misc {...} DrawingData;", il me dit que DrawingData et pas déclarée dans les sources où pourtant, j'inclus le header. confus J'ai encore un problème de compréhension de ce qui se passe à ce niveau ...

210

Ah bon, ben je ne comprends pas non plus alors grin
C'était en faisant quoi que tu avais 0 relogement ?
avatar
« Le bonheur, c'est une carte de bibliothèque ! » — The gostak distims the doshes.
Membrane fondatrice de la confrérie des artistes flous.
L'univers est-il un dodécaèdre de Poincaré ?
(``·\ powaaaaaaaaa ! #love#