Index des articles > Programmation > Techniques de programmation en assembleur

Techniques de programmation en assembleur

Article posté par geogeo

Techniques d'optimisations en assembleur

Nous supposons que vous maîtrisez l'assembleur 68000 et que les instructions qui figurent dans cet article sont parfaitement connues.

Même si les performances des langages de haut niveau permettent, dans bien des cas, de se dispenser d'une phase de programmation en langage assembleur, certaines fonctionnalités rendent incontournable son utilisation qui seule peut assurer à la fois la rapidité, la concision et la précision réclamées dans ces circonstances précises. Même si l'économie de quelques microsecondes ou d'octets peut sembler dérisoire dans de nombreux cas, certaines circonstances, qui sont spécifiquement celles qui ont conduit à l'utilisation du langage assembleur, nécessitant la prise la prise en compte de ce besoin (routines d'interruption, d'entrées-sorties, programmation d'un système d'exploitation, routines graphiques, etc.). De toute façon, la recherche d'un rendement optimum du code programmé, si elle n'est pas toujours nécessaire, est une très bonne discipline, qui apporte de surcroît la satisfaction d'un résultat efficace.

Le jeu très varié du MC68000 (56 types d'instruction) permet une programmation simple des algorithmes même les plus complexes. Cependant, dans le but d'augmenter l'efficacité d'exécution du code dans un certain nombre de cas, plusieurs instructions ont été incluses dans le jeu. Leur examen attentif permet de découvrir quelques subtilités de programmation qui peuvent se révéler précieuses en plus d'une occasion.

Nous vous proposons ainsi d'étudier dans le détail quelques possibilités d'optimisation, en nous attachant tout d'abord aux instructions proprement dites avant d'examiner les structures de contrôle. Il est bien évident que plusieurs cas le code optimisé sera obligatoirement moins « lisible » qu'un code plus simplifié, c'est pourquoi il est préférable, au moins dans un premier temps, d'indiquer clairement en commentaire du programme la justification de l'emploi d'une solution qui peut apparaître un peu obscure.

Dans nos exemples, la version [a] expose le code simplifié, et [b] le code optimisé.

Les symboles suivants ont été utilisés :

  • Dn, Dm... = un des 8 registres de données.
  • An = un des 8 registres d'adresses.
  • SP = A7 en tant que pointeur de pile.
  • DATA = une donnée immédiate dont les valeurs limites sont précisées.
  • = Adresse effective en mémoire (dont l'accès se fait au moyen d'un mode d'adressage différent du mode registre direct).

Les temps d'exécution en cycles machine puis la taille en octets sont indiqués entre crochets pour chaque instruction. Le signe ~ indique que les valeurs ne prennent pas en compte le temps nécessaire pour effectuer le calcul de l'adresse effective ainsi que les mots d'extensions servant à préciser l'adresse des opérandes.

Entrons dans le vif su sujet.

Transferts de données

L'utilisation de l'instruction moveq qui permet de charger un registre entier (les 32 bits sont affectés) avec une valeur comprise entre -128 et 127, peut être étendue de plusieurs façon :

[1a] clr.l Dn [6 :2]

[1b] moveq #0,Dn [4 :2]

Cette optimisation se passe de commentaires ! Inutile de perdre 2 cycles.

127 < DATA <256

[2a] move.l #DATA,Dn [12:6]

[2b] moveq #DATA-128,Dn [4:2]

tas Dn [4:2]

ou not.b Dn [4:2]

ou neg.b Dn [4:2]

Total [8 :4]

Bien que l'instruction tas (test and set) soit destinée primitivement à positionner un bit sémaphore (dans le cas d'un système d'exploitation multitâche), son utilisation dans ce cas permet, par la mise à 1 du bit 7 du registre Dn, d'augmenter la première valeur chargée dans le registre Dn de 128. Le gain est double : en temps d'exécution et en taille d'instruction.

[3a] move.l #255,Dn [12:6]

move.w #255,Dn [8 :4]

[3b] st Dn [6 :2]

A condition de ne pas tenir compte des octets supérieurs du registre. Sinon utilisez les instructions précédentes.

-256 < DATA < -128

[4a] move.l #DATA,Dn [12:6]

[4b] moveq #-256-DATA,Dn [4:2]

neg.b Dn [4:2]

Total [8 :4]

-65536 < DATA < -65407

[5a] move.l #DATA,Dn [12:6]

[5b] moveq #-65536-DATA,Dn [4:2]

neg.w Dn [4:2]

Total [8 :4]

Deux usages de la négation sur un octet ou sur un mot. Le second cas est toutefois d'une utilisation beaucoup moins fréquente dans les programmes.

[6a] move.l #$FFFFFF00,Dn [12:6]

[6b] moveq #-1,Dn (-1 = #$FFFFFFFF)[4:2]

not.b Dn [4:2]

Total [8 :4]

[7a] move.l #$000000FF,Dn [12:6]

[7b] moveq #0,Dn [4:2]

not.b Dn [4:2]

Total [8 :4]

[8a] move.l #$FFFF0000,Dn [12:6]

[8b] moveq #-1,Dn [4:2]

not.w Dn [4:2]

Total [8 :4]

[9a] move.l #$0000FFFF,Dn [12:6]

[9b] moveq #0,Dn [4:2]

not.w Dn [4:2]

Total [8 :4]

Pour les secondes instructions [b] et [8b] on aurait bien entendu pu tout aussi bien employer l'instruction clr.b et clr.w. A chacun de choisir.

On peut de la même manière obtenir, par exemple des valeurs de masque plus complexes :

[10a] move.l #$FFFFFF0F,Dn

[10b] moveq #-16,Dn (-16 = #$FFFFFFF0)

neg.b Dn

ou

[11a] move.l #$FFFF000F,Dn

[11b] moveq #-16,Dn

neg.w Dn

Et ainsi de suite...

[12a] move.l #$FFF0FFFF,Dn [12:6]

[12b] moveq #-16,Dn [4:2]

swap Dn [4:2]

Total [8 :4]

[13a] move.l #$000F0000,Dn [12:6]

[13b] moveq #16,Dn (16 = #$0000000F)[4:2]

swap Dn [4:2]

Total [8:4]

Tout comme dans les exemples précédents, d'autres possibilités peuvent être utilisées.

-129 < DATA < +128

[14a] move.l #DATA, [16~:6~]

[14b] moveq #DATA,Dn [4:2]

move.l Dn, [8~:2~]

Total [12~:4~]

Cette codification est particulièrement utile pour l'empilage de paramètres, comme dans l'appel de certaines fonctions du système où ceux-ci peuvent être équivalentes à -1 ou 0.

Par exemple :

moveq #-1,D0 [4 :2]

move.l D0,-(SP) [12 :2]

moveq #0,D0 [4 :2]

move.l D0,-(SP) [12 :2]

Total [32 :8]

Au lieu de :

move.l #-1,-(SP) [20 :6]

clr.l -(SP) [22 :4]

Total [42 :10]

An = adresse impaire

[15a] move.b (An)+,Dn [8:2]

lsl.w #8,Dn [22:2]

move.b (An),Dn [8:2]

Total [38:6]

[15b] move.b (An)+,-(SP) [12:2]

move.w (SP)+,Dn [8:2]

move.b (An),Dn [8:2]

Total [28:6]

En présence du problème du transfert d'un mot à partir d'une adresse impaire, la décrémentation automatique d'un mot et non pas d'un octet du registre SP (pile système) permet de transférer directement l'octet provenant de An dans l'octet supérieur du mot empilé. Cet octet sera donc à sa place dans Dn lors du dépilement. Bien entendu pour une adresse paire le problème est immédiatement résolu !

[16a] move.b #WW,(An) [16:4]

move.b #XX,1(An) [16:4]

move.b #YY,2(An) [16:4]

move.b #ZZ,3(An) [16:4]

Total [64:16]

[16b] move.l #WWXXYYZZ,(An) [12:6]

movep est particulièrement destinée à l'interfaçage des microprocesseurs 8 bits mais peut for bien servir en beaucoup d'autres occasions à ne pas négliger. Elle opère également sur une taille d'un mot et dans le sens mémoire->registre. Son étude attentive peut être très profitable. Mais ne fonctionne dans le cas d'un système avec périphériques, ce qui n'est pas le cas des TI68K.

Transferts d'adresses

[17a] movea.l #0,An [12:6]

[17b] suba.l An,An [8 :2]

C'est évident !

8 < DATA < $0000FFFF ou

$FFFF0000 < DATA < $FFFFFFF8

[18a] adda.l #DATA,An [14:6]

ou

[19a] suba.l #DATA,An [14:6]

[18b] lea.l DATA(An),An [8 :4]

ou

[19b] lea.l -DATA(An),An [8 :4]

Cette instruction, l'une des moins bien comprises dans le jeu du MC68000, devrait notamment être employée lors des opérations de rectification de pointeur de pile qui interviennent après un appel à une routine. Quand 0 < DATA < 9, on emploi alors la version addq ou subq des instructions add et sub qui s'exécutent dans le même temps que l'instruction lea, mais ont une taille inférieure de 2 octets.

[20a] move.l #Adresse,-(SP) [20 :8]

move.l #Adresse+4,-(SP) [20 :6]

move.l #Adresse+8,-(SP) [20 :6]

...etc Total [60 :18]

[20b] lea.l Adresse,An [12:6]

pea (An)+ [12:2]

pea (An)+ [12:2]

pea (An) [12:2]

...etc Total [48:12]

L'instruction pea fonctionne exactement de la même façon que l'instruction lea. Toutes les deux n'admettent qu'une seule taille d'opérande, sur un mot long. Dans [18], le gain est indépendant du déplacement (à condition de ne pas oublier que ce dernier est codé sur au plus 16 bits), et s'accroît avec le nombre de paramètres empilés.

Opérations logiques et arithmétiques

[21a] andi.l #$0000FFFF,Dn [16:6]

[21b] swap Dn [4:2]

clr.w Dn [4:2]

Swap Dn [4:2]

Total [12:6]

Comme quoi 3 instructions peuvent parfois être plus efficaces qu'une seule !

-127 < DATA < +128

[22a] addi.l #DATA, [20~:16~]

[22b] moveq #DATA,Dn [4:2]

add.l Dn, [12~:2~]

Total [16~:4~]

On peut utiliser le même mécanisme pour les autres instructions immédiates, à savoir:

subi.l

andi.l

eori.l

ori.l

cmpi.l

DATA = 2 puissance k

[23a] cmpi.l #DATA,Dn [14 :6]

[23b] btst.l #k,Dn [10:4]

Si le bit k de Dn est à 1, la valeur de Dn est supérieurs ou égale à DATA. Par exemple :

btst.l #16,D0 [10 :4]

beq.s PLUS_LOIN [10 :2]

moveq #1,D0 [4 :2]

swap D0 [4 :2]

PLUS_LOIN :

move.l D0,D1 [4 :2]

Total [32 :12]

Au lieu de :

cmpi.l #$10000,D0 (#$10000 = 65536) [14 :6]

bmi.s PLUS_LOIN [10 :2]

move.l #$10000,D1 [12 :6]

PLUS_LOIN :

move.l D1,D2 [4 :2]

Total [40 :16]

0 < DATA < 8

[24a] moveq #DATA+8,Dn

rol.w Dn,Dm [22+DATA*2:2] (1a)

[24b] moveq #8-DATA,Dn

ror.w Dn,Dm [6+((8-DATA)*2):2] (1b)

0 < DATA < 16

[24a] moveq #DATA+16,Dn

rol.l Dn,Dm [32+DATA*2:2] (2a)

[24b] moveq #16-DATA,Dn

ror.l Dn,Dm [8+((16-DATA)*2):2] (2b)

On peut éviter les rotations importantes grâce à cette technique. Si, par exemple, dans [21] DATA-4, c'est-à-dire que l'on souhaite obtenir une rotation de 4+8, soit 12 bits. (1a) sera égal à 30, et (1b) à 14. La différence est notable ! Dans le cas d'une rotation sur un mot on économise donc 16 cycles machine, et sur un mot long, 32 cycles.

0 < DATA < 16

[26a] moveq #DATA+16,Dn

lsr.l Dn,Dm [40+(DATA*2) :2]

[26b] moveq #DATA,Dn

clr.w Dm [4:2]

swap Dm [4:2]

lsr.w Dm [6+(DATA*2):2]

Total [14+(DATA*2):6]

[27a] moveq #DATA+16,Dn

lsl.l Dn,Dm [40+(DATA*2):2]

[27b] moveq #DATA,Dn

lsl.w Dm [6+(DATA*2):2]

swap Dm [4:2]

clr.w Dm Total [14+(DATA*2):6]

[28a] moveq #DATA+16,Dn

asr.l Dn,Dm [40+(DATA*2):2]

[28b] moveq #DATA,Dn

swap Dm [4:2]

ext.l Dm [4:2]

asr.l Dn,Dm Total [14+(DATA*2):6]

Tout comme les rotations, les décalages importants peuvent être accélérés efficacement, en sacrifiant un peu la taille du code cette fois. Le décalage arithmétique à gauche (asl) s'effectue comme un décalage logique.

Multiplications et divisions rapides

Ces deux opérations sont les moins rapides des instructions courantes. Il peut être avantageux dans des circonstances bien précises d'utiliser des algorithmes de remplacement qui se révèlent plus rapides, au détriment toutefois de la taille du code. Le cas d'une multiplication par une donnée immédiate facilement décomposable en sommes de puissances de 2 en est un des exemples caractéristiques.

[29a] mulu #5,Dn [42 :4]

[29b] move.l Dn,Dm [4:2]

lsl.l #2,Dm [12:2]

add.l Dm,Dn [8:2]

Total [24:6]

[30a] mulu #20,Dn [44:4]

[30b] lsl.l #2,Dn [12:2]

move.l Dn,Dm [4:2]

lsl.l #2,Dm [12:2]

add.l Dm,Dn [8:2]

Total [36:8]

Dans le second cas, le premier décalage multiplie la valeur initiale de Dn par 4. Le second décalage la multiplie par 16. La somme équivaut donc à 16+4 et donne donc le même résultat qu'une multiplication par 20. il n'est pas inutile de rappeler q'un décalage d'un bit sur la gauche équivaut à une multiplication par 2 et que dans ce cas, une simple addition est que rapide que le décalage. Par exemple :

add Dn,Dn [4 :2]

au lieu de :

lsl.w #1,Dn [8 :2]

Si on souhaite effectuer une multiplication signée (muls), on emploiera alors un décalage arithmétique (asl), et un test du bit V du CCR permettra de connaître le signe du résultat.

Pour une division dont le quotient attendu est inférieur à 6, on peut employer l'algorithme suivant, dans lequel le diviseur est contenu dans Dn, le diviseur dans Dm. A la sortie de la boucle, le quotient se trouve dans Dr et le reste dans Dm :

[31] moveq #-1,Dr [4 :2]

sub.w Dn,Dm [4 :2]

DIVISE_1 :

sub.w Dn,Dm [4 :2]

dbmi.w Dr,DIVISE_1 [10:4] ou [12 :2]

neg.w Dr [4 :2]

add.w Dn,Dm [4 :2]

Total [16+14*quotient+2:14)

Le temps d'exécution varie entre 18 cycles (quotient = 0) et 130 cycles (quotient = 8) alors que l'instruction équivalente

divu Dn,Dm

demande entre 126 et 140 cycles. Cet algorithme divise les 16 bits de poids faible de Dm par les 16 bits de poids faible de Dn. Pour réaliser une division sur 32 bits, il faut modifier les opérations portant sur Dn et Dm pour les faire porter sur des longword, et dans ce cas, le temps d'exécution est de 24+18*quotient+2, donc il ne devient intéressant que pour des quotients <= 5.
Si le reste de la division n'est pas utilisé, la dernière ligne du code peut être omise.

Dans le même ordre d'idées, le calcul d'un modulo peut s'effectuer ainsi :

3 < DATA1 < $3FFFF (modulo recherché)

DATA2 = (puissance de 2)-1 immédiatement supérieure à DATA1. Par exemple si DATA1 = 5 (%101), DATA2 = 7 (%111).

[32a] divu #DATA,Dn [140 :4]

swap Dn [4:2]

move Dn,Dm [4:2]

Total [148:8]

[32b] move #DATA,Dm [8:4]

and Dn,Dm [4:2]

cmp Dn,Dm [4:2]

bmi.s VAL_MODULO [10:2]

sub Dn,Dm [4:2]

VAL_MODULO: Total [26 ou 28:12]

La valeur de Dn modulo DATA1 se trouve dans Dm. Et si DATA1 < 128, on gagne encore 4 cycles en utilisant moveq dans [32b]. De plus l'opération peut être effectuée sur un mot long sans difficulté.

La suite prochainement

Source : ST Magazine numéro 17 et 18 par Daniel Fournier, modifié par Geoffrey Anneheim, copyright Ti-Gen 2005.


>> Vos commentaires [20]

[Commentaire n°1]

Posté par sasume le 02/04/2005
Pour le 3, si il est important que les 32 bits du registre soient affectés, plutôt que de garder le move.l #255,dn, on peut faire :
moveq.l #0,dn ; st.b dn [10 : 4] (on gagne 2 cycles et 2 octets) :)

Pour le 16, il est possible d'écrire directement movea.l #WWXXYYZZ,(an) [20:6]
(et le code que tu as écrit toi est incorrect d'ailleurs)

Pour le 17, ma table de cycle me dit que c'est 6, pas 8. Mais j'avoue que ça me paraît bizarre.

Pour le 20, on peut même, si le contexte l'autorise, remplacer le lea.l Adresse,an par un lea.l Adresse(pc),an, qui sauve 2 octets et 4 cycles !

Pour le 22, il faut rectifier, cela n'est possible que si DATA est compris dans l'intervalle [-127;128], et puis ça bouffe un registre supplémentaire.

Pour le 23, c'est btst.l #k,dn ; pas k-1

Je me suis arrêté là, je n'ai pas le temps de lire la suite. Je le ferai plus tard.
Ce tuto est une bonne idée, j'ai appris des petites astuces dedans :)
Par contre, il y a quelques erreurs ou imprécisions, c'est dommage.


Commentaires :: [Commentaire n°2]

Posté par Kevin Kofler le 03/04/2005
Pour le 2, GCC utilise neg.b ou not.b plutôt que tas.b et ça marche aussi, en la même taille et vitesse.
Le 16 est incorrect, je pense que ça décrivait movep, pas movea, et ça ne marche pas exactement comme ça. Le code tel qu'il est est faux, movea ne marche qu'avec un registre d'adresses en destination.
Et les dernières (à partir du 26) sont nulles, ce sont des optimisations vitesse qui pessimisent la taille.

Membre de l'équipe de TIGCC: http://tigcc.ticalc.org
Mainteneur du portage Linux/Unix de TIGCC: http://tigcc.ticalc.org/linux/
Membre de l'équipe de TiEmu: http://lpg.ticalc.org/prj_tiemu/

Participez à la reprise de Ti-Gen!


[Commentaire n°3]

Posté par sasume le 03/04/2005
Pour le 31, je me demande si on ne peut pas améliorer encore avec l'instruction DBcc... Je vais réfléchir à ça :)


[Commentaire n°4]

Posté par sasume le 03/04/2005
Après relecture, il y a une petite erreur sur le 31, au niveau de l'instruction bpl. Voici ce que devrait être la ligne :
bpl.s DIVISE_1 ; [10:2] ou [8 :2]


Et voici ma version au fait. Peut-être encore optimisable :
  moveq.l #-1,dr  ; [4:2]
DIVISE_1:
    sub.w   dn,dm  ; [4:2]
    dbpl    dr,DIVISE_1  ; [10:4] ou [12:4]
  addq.w  #1,dr  ; [4:2]
  not.w   dr  ; [4:2]
  add.w  dn,dm  ; [4:2]

Soit un total de [16+(quotient+1)*14+2:14]
Ce qui donne un gain pour les quotients inférieurs à 7.
Mais ma solution prend plus de place que celle proposée, pour pas grand chose de mieux. Mais je pense qu'il doit être possible de simplifier les traitements autour de la boucle...


[Commentaire n°5]

Posté par sasume le 03/04/2005
Nouvelle version :
  moveq.l #-1,dr  ; [4:2]
  sub.w   dn,dm  ; [4:2]
DIVISE_1:
    sub.w   dn,dm  ; [4:2]
    dbpl    dr,DIVISE_1  ; [10:4] ou [12:4]
  not.w   dr  ; [4:2]
  add.w   dn,dm  ; [4:2]

Cette solution prend 14 octets, et offre un gain si le quotient est inférieur à 8.

edit:correction de balise


[Commentaire n°6]

Posté par geogeo le 03/04/2005
Pour le 17, ma table de cycle me dit que c'est 6, pas 8. Mais j'avoue que ça me paraît bizarre.


C'est bien 8 et non 6.


Pour le 20, on peut même, si le contexte l'autorise, remplacer le lea.l Adresse,an par un lea.l Adresse(pc),an, qui sauve 2 octets et 4 cycles !


Mon exemple est un cas général, bien entendu qu'on peut ajouter (PC) mais sous certaines conditions.

Pour le 2, GCC utilise neg.b ou not.b plutôt que tas.b et ça marche aussi, en la même taille et vitesse.
Le 16 est incorrect, je pense que ça décrivait movep, pas movea, et ça ne marche pas exactement comme ça. Le code tel qu'il est est faux, movea ne marche qu'avec un registre d'adresses en destination.
Et les dernières (à partir du 26) sont nulles, ce sont des optimisations vitesse qui pessimisent la taille.


Corrigé, en effet s'était movep et non movea se qui était logique mais movep n'est pas fait pour les TI68K.
Ensuite t'es jamais content, y a tout d'afficher, nombre de cycles et taille du code, au programmeur de choisir, mais perso si j'économise 48 cycles et que je perd 4 octets je prend tout de suite cette optimisation.




[Commentaire n°7]

Posté par sasume le 03/04/2005
C'est bien 8 et non 6.
Quelle est ta source ?

Mon exemple est un cas général, bien entendu qu'on peut ajouter (PC) mais sous certaines conditions.
Oui, mais précise le tout de même parce que c'est très souvent le cas.


[Commentaire n°8]

Posté par sasume le 03/04/2005
Euh, pour le 31, tu as mis n'importe quoi #roll#

Voilà le code exact :
[31]
  moveq.l #-1,Dr            [4:2]
  sub.w   Dn,Dm             [4:2]
DIVISE_1 :
    sub.w   Dn,Dm             [4:2]
    dbpl.w  Dr,DIVISE_1       [10:4] ou [12:4]
  not.w   Dr                [4:2]
  add.w   Dn,Dm             [4:2]
                                         Total [16+(14*quotient)+2 :14)

L'exécution de ce code varie entre 18 cycles (quotient = 0) et 130 cycles (quotient = 8), tandis que le temps d'exécution d'un divu se situe entre 126 et 140 cycles. Cet algorithme divise les 16 bits de poids faible de Dm par les 16 bits de poids faible de Dn. Pour réaliser une division sur 32 bits, il faut modifier les opérations portant sur Dn et Dm pour les faire porter sur des longword, et dans ce cas, le temps d'exécution est de 24+18*quotient+2, donc il ne devient intéressant que pour des quotients <= 5.
Si le reste de la division n'est pas utilisé, la dernière ligne du code peut être omise.


[Commentaire n°9]

Posté par geogeo le 06/04/2005
http://www.grid.unina.it/Didattica/CE/CEI/INFORMATICA/68k/68000um.pdf

Rapport avec suba An,An.

Je vais ajouter ta précision sur PC mais (PC) n'est plus valide quand le programme dépasse 24 Ko?

Encore merci pour ton aide, je vais essayer quand j'aurai du temps de faire la partie "optimisations des structures (sauts...)".


[Commentaire n°10]

Posté par sasume le 07/04/2005
Pour le suba, effectivement, j'utilise la même doc que toi et je l'avais mal lue #roll#

Pour l'adressage en pc-relatif, ça peut être inutilisable si le prog dépasse 32ko, mais ce ne sera pas forcément le cas.


[Commentaire n°11]

Posté par sasume le 07/04/2005
Au fait, tu t'es encore trompé pour le 31, le calcul du temps d'exécution est 16+14*quotient+2, pas 16+14*(quotient+2)


[Commentaire n°12]

Posté par sasume le 07/04/2005
Et en fait, mon code est complètement faux #top#
Il faut mettre un dbmi à la place du dbpl et remplacer le not par un neg.


[Commentaire n°13]

Posté par geogeo le 07/04/2005
Corrigé et ajout aussi d'une bref explication de PC. Merci :)



[Commentaire n°14]

Posté par sasume le 08/04/2005
Il reste encore une faute dans l'expression du calcul du temps d'exécution !
Et puis ton explication sur l'adressage PC-relatif n'est pas placée au bon endroit, et est de toute façon complètement fausse.
L'adressage #DATA(pc) ne veut strictement rien dire...
Et c'est faux que ça ne marche que pour les prog < 32ko. Des problèmes peuvent survenir dans le cas de programmes de plus de 32ko, mais c'est assez rare, et en général on peut très bien les éviter.

Franchement je n'en reviens pas que tu fasses autant de fautes geogeo, on dirait que tu n'as jamais codé en ASM !


[Commentaire n°15]

Posté par geogeo le 08/04/2005
Il reste encore une faute dans l'expression du calcul du temps d'exécution !


Corrigé!

Et puis ton explication sur l'adressage PC-relatif n'est pas placée au bon endroit, et est de toute façon complètement fausse.
L'adressage #DATA(pc) ne veut strictement rien dire...


Viré et j'avoue que j'ai fait n'importe quoi là, surtout avec un PC après un #DATA %) Viré j'ajouterai ça plus tard!

Et c'est faux que ça ne marche que pour les prog < 32ko. Des problèmes peuvent survenir dans le cas de programmes de plus de 32ko, mais c'est assez rare, et en général on peut très bien les éviter.


Je ne connais pas en détail tout ça donc oui j'ai fait une erreur et je l'admet!

Franchement je n'en reviens pas que tu fasses autant de fautes geogeo, on dirait que tu n'as jamais codé en ASM !


J'avoue, je prend ta remarque mais je te laisse deviner combien de temps il faut pour faire un tel article aussi nase qui ne sera lu que par 4 personnes. Alors j'estime que mes erreurs sont minimes vu l'article. Surtout que cet article se base aussi sur le travail de Daniel Fournier dont tu as critiqué certaines parties (et c'était des bonnes critiques!).
Mais bon soit je ne fais pas d'article et on ne pourra plus me faire des remarques genre je sais pas coder soit j'en fait et je m'en prend plein la gueule. Je vise la dernière solution. :D





(PC) :: [Commentaire n°16]

Posté par Kevin Kofler le 09/04/2005
Ne codez pas (PC) en dur dans vos programmes, laissez le linker décider si c'est possible ou non! (Et il réordonnera même les sections pour que ce soit possible au maximum d'endroits.)

Membre de l'équipe de TIGCC: http://tigcc.ticalc.org
Mainteneur du portage Linux/Unix de TIGCC: http://tigcc.ticalc.org/linux/
Membre de l'équipe de TiEmu: http://lpg.ticalc.org/prj_tiemu/

Participez à la reprise de Ti-Gen!


[Commentaire n°17]

Posté par geogeo le 09/04/2005
Bof j'viens de tester et TIGCC n'optimise pas au maximum.
Dans quel cas un problème peut arriver quand on utilise (PC)? La variable se trouve 32 Ko plus loin que la valeur actuelle du PC???


[Commentaire n°18]

Posté par sasume le 10/04/2005
Kevin> ld-tigcc ne permet pas de produire des fichiers utilisables sur Atari ST.


Réponses :: [Commentaire n°19]

Posté par Kevin Kofler le 10/04/2005
Bof j'viens de tester et TIGCC n'optimise pas au maximum.

C'est-à-dire? Exemples? Compiles-tu bien avec les optimisations du linker activées (--optimize-code --cut-ranges si tu compiles en ligne de commande, et aussi --reorder-sections, éventuellement)? Et es-tu sûr que l'adressage en (PC) soit permis en cet endroit? (PC) n'est permis que pour les opérandes source, pas pour les opérandes de destination.

Dans quel cas un problème peut arriver quand on utilise (PC)? La variable se trouve 32 Ko plus loin que la valeur actuelle du PC???

Oui.

Kevin> ld-tigcc ne permet pas de produire des fichiers utilisables sur Atari ST.

Oui, mais là, on parle de TIs. L'article d'origine aurait pu en parler, en effet. Et sinon, ld-tigcc est un logiciel libre, rien ne t'empêche de coder un export Atari ST. :) On a déjà comme exports possibles: exécutable AMS (_nostub ou kernel), DLL _nostub, fichier de données externe, Fargo, Flash OS (TIB), infos de débogage (COFF avec stabs ou DWARF 2). Donc notre linker est flexible sur ce point.

Membre de l'équipe de TIGCC: http://tigcc.ticalc.org
Mainteneur du portage Linux/Unix de TIGCC: http://tigcc.ticalc.org/linux/
Membre de l'équipe de TiEmu: http://lpg.ticalc.org/prj_tiemu/

Participez à la reprise de Ti-Gen!


[Commentaire n°20]

Posté par geogeo le 10/04/2005
C'est-à-dire? Exemples? Compiles-tu bien avec les optimisations du linker activées (--optimize-code --cut-ranges si tu compiles en ligne de commande, et aussi --reorder-sections, éventuellement)? Et es-tu sûr que l'adressage en (PC) soit permis en cet endroit? (PC) n'est permis que pour les opérandes source, pas pour les opérandes de destination.


Oui toutes les options sont activées sauf --reorder-sections car je fias une initialisation de variables au début de mon programme. Et enfin je n'utilise que (PC) pour les opérandes sources.


Poster un commentaire


Seuls les membres peuvent poster des commentaires