Quelles techniques sont disponibles pour l'optimisation de la mémoire dans le langage d'assemblage 8051?

StackOverflow https://stackoverflow.com/questions/335540

Question

Je dois optimiser le code pour avoir de la place pour un nouveau code. Je n'ai pas la place pour tous les changements. Je ne peux pas utiliser la commutation de banque de codes (80c31 avec 64k).

Était-ce utile?

La solution

Vous n'avez pas vraiment donné beaucoup de choses à faire ici, mais vous pouvez envisager deux niveaux d'optimisation principaux:

Micro-optimisations:   par exemple. XOR A au lieu de MOV A, 0   Adam en a déjà couvert joliment certains.

Optimisations macro:   Examinez la structure de votre programme, les structures de données et les algorithmes utilisés, les tâches effectuées, et réfléchissez TRÈS sérieusement à la manière dont ils pourraient être réorganisés, voire supprimés. Y at-il des morceaux de code entiers qui ne sont pas réellement utilisés? Votre code est-il plein d'énoncés de sortie de débogage que l'utilisateur ne voit jamais? Existe-t-il des fonctions spécifiques à un seul client que vous pouvez laisser dans une version générale?

Pour bien comprendre la situation, vous devez déterminer où votre mémoire est épuisée. La carte Linker est un bon point de départ pour cela. Les macro-optimisations sont l'endroit où les gros gains peuvent être réalisés.

En passant, vous pourriez essayer sérieusement de réécrire des parties de votre code avec un compilateur C optimisant. Vous serez peut-être étonné de la sévérité du code. Un vrai spécialiste des assembleurs peut peut-être l’améliorer, mais il peut facilement être meilleur que la plupart des codeurs. J'ai utilisé le IAR , il y a environ 20 ans, et il a soufflé mes chaussettes.

Autres conseils

Avec le langage d'assemblage, vous devrez optimiser manuellement. Voici quelques techniques:

Remarque: IANA8051P (je ne suis pas un programmeur 8501 mais j'ai beaucoup assemblé d'autres puces 8 bits).

Parcourez le code à la recherche de bits dupliqués, peu importe leur taille, et faites-les fonctionner.

Découvrez certaines des instructions les plus inhabituelles et voyez si vous pouvez les utiliser pour les optimiser, par exemple. Une bonne astuce consiste à utiliser XOR A pour effacer l’accumulateur au lieu de MOV A, 0 - il enregistre un octet.

Une autre astuce intéressante consiste à appeler une fonction avant de revenir, par exemple, au lieu de:

CALL otherfunc
RET

Il suffit de faire:

JMP otherfunc

Assurez-vous toujours que vous effectuez des sauts et des branches relatifs dans la mesure du possible. Ils utilisent moins de mémoire que les sauts absolus.

C’est tout ce que je peux penser à l’esprit pour le moment.

Désolé, j'arrive trop tard, mais j’ai eu exactement le même problème une fois, et c’est devenu un problème récurrent qui me revenait sans cesse. Dans mon cas, le projet était un téléphone, sur un processeur familial 8051, et j'avais totalement exploité la mémoire ROM (code). Cela me revenait sans cesse parce que la direction demandait sans cesse de nouvelles fonctionnalités. Chaque nouvelle fonctionnalité devenait donc un processus en deux étapes. 1) Optimisez les vieux éléments pour créer de la pièce 2) Mettez en œuvre la nouvelle fonctionnalité en utilisant la pièce que je viens de créer.

Il existe deux approches d'optimisation. Tactique et stratégique. Les optimisations tactiques économisent quelques octets à la fois avec une idée de micro-optimisation. Je pense que vous avez besoin d'optimisations stratégiques qui impliquent de repenser plus radicalement votre façon de faire les choses.

Quelque chose dont je me souviens a fonctionné pour moi et pourrait fonctionner pour vous;

Examinez l'essence de ce que votre code doit faire et essayez de distiller quelques opérations primitives flexibles très puissantes. Reconstruisez ensuite votre code de niveau supérieur de sorte qu'il ne fasse rien du plus bas niveau sauf appeler les primitives. Idéalement, utilisez une approche basée sur les tables, votre table contient des éléments tels que: Etat d'entrée, événement, état de sortie, primitives ... En d'autres termes, lorsqu'un événement se produit, recherchez une cellule dans la table pour cet événement dans l'état actuel. Cette cellule vous indique le nouvel état à modifier (éventuellement) et la ou les primitives à exécuter (le cas échéant). Vous aurez peut-être besoin de plusieurs ensembles d'états / événements / tables / primitives pour différentes couches / sous-systèmes.

L’un des nombreux avantages de cette approche est que vous pouvez l’imaginer en construisant un langage personnalisé pour votre problème particulier, dans lequel vous pouvez très efficacement (c’est-à-dire avec un minimum de code) créer de nouvelles fonctionnalités en modifiant simplement la table.

Désolé, j'ai plusieurs mois de retard et vous n'avez probablement pas eu le temps de faire quelque chose d'aussi radical. Pour tout ce que je sais, vous utilisiez déjà une approche similaire! Mais ma réponse pourrait un jour aider quelqu'un d'autre qui sait.

Dans le rayon des objets masqués, vous pouvez également envisager de compresser une partie de votre code et de ne conserver qu'une partie activement utilisée, décompressée à un moment donné. J'ai du mal à croire que le code requis pour le système de compression / décompression soit suffisamment petit pour constituer une partie de la mémoire minuscule du 8051 pour que cela en vaille la peine, mais a fait des miracles sur des systèmes légèrement plus grands.

Une autre approche consiste à utiliser un format de code octet ou le type de code piloté par une table généré par certaines machines d'état: le fait de comprendre une machine à ce que fait votre application et de générer une implémentation totalement incompréhensible peut s'avérer très utile. moyen de gagner de la place:)

Enfin, si le code est effectivement compilé en C, je suggérerais de compiler avec une gamme d’options différentes pour voir ce qui se passe. J'ai écrit un article sur le codage C compact pour le CES en 2001. cela reste d'actualité. Voir ce texte pour d'autres astuces pour les petites machines.

1) Dans la mesure du possible, enregistrez vos variables dans Idata et non dans xdata
2) Regardez vos déclarations Jmp & # 8211; utiliser SJmp et AJmp

Je suppose que vous savez que cela ne conviendra pas, car vous avez écrit / exécuté et obtenu le "manque de mémoire". Erreur. :) Il semble que les réponses répondent assez précisément à votre question. à court d’obtenir des exemples de code.

Je recommanderais cependant quelques réflexions supplémentaires;

  1. Assurez-vous que tout le code est vraiment utilisé - test de couverture de code? Un sous utilisé est une grande victoire - c'est un étape difficile - si vous êtes l'original auteur, il peut être plus facile - (enfin, peut-être):)
  2. Assurez-vous que le niveau de " vérification " et initialisation - parfois nous avoir tendance à être trop zélé en assurant nous avons initialisé variables / mémoire et bien sûr à juste titre, combien de fois avons-nous été mordu par elle. Ne pas dire ne pas initialiser (duh), mais si nous faisons un mouvement de mémoire, la destination n'a-t-il pas besoin d'être zéro en premier - cette queue d'aronde avec

    1 -

  3. Évaluez les nouvelles fonctionnalités - pouvez-vous sous existant soit être amélioré pour couvrir les deux fonctions ou peut-être un fonctionnalité existante remplacée?
  4. Casser le gros code si un morceau du Un gros code peut sauver créer une nouvelle petit code.

ou peut-être qu'il y a un argument pour la version matérielle 2.0 sur la table maintenant ...:)

salutations

Outre les optimisations (plus ou moins) évidentes déjà mentionnées, il en existe une vraiment étrange (et presque impossible à réaliser): la réutilisation de code. Et avec Réutilisation du code, je ne parle pas de la réutilisation normale, mais pour a) réutiliser votre code en tant que données ou b) pour réutiliser votre code comme autre code. Peut-être que vous pouvez créer un fichier lut (ou toute donnée statique) qu’il peut représenter par les opcodes asm hex (ici, vous devez regarder l’architecture harvard vs von neumann).

L'autre réutiliserait le code en lui donnant un sens différent lorsque vous l'adresseriez différemment. Voici un exemple pour clarifier ce que je veux dire. Si les octets de votre code ressemblent à ceci: AABCCCDDEEFFGGHH à l'adresse X où chaque lettre correspond à un code d'opération, imaginez que vous passez maintenant à X + 1. Peut-être obtenez-vous une fonctionnalité complètement différente où les octets séparés par un espace maintenant forment les nouveaux opcodes: ABC CCD DE EF GH.

Mais méfiez-vous: ce n’est pas seulement difficile à réaliser (c’est peut-être impossible), mais c’est une horreur à maintenir. Donc, si vous n’êtes pas un code de démonstration (ou quelque chose d’exotique similaire), je vous recommanderais d’utiliser les autres moyens déjà mentionnés pour enregistrer de la mémoire.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top