Brevet FR2698980A1 — publié le 19940610

La présente invention concerne une technique nouvelle qui augmente considérablement la vitesse d'assemblage des programmes d'ordinateurs ou de microprocesseurs. Dans la technique actuelle, les assembleurs sont tous du type "deux passes". Lors de la première passe, la ligne source du programme est examinée de façon à connaître le nombre d'octets que comprend l'instruction. Cet examen consiste plus précisément à extraire les différents champs de la ligne-source et à retrouver les éléments de l'opcode, des modes d'adressage et du champ opérande. Le compteur ordinal (ou "Pc") est incrémenté en conséquence. Les étiquettes sont mises dans une table de symboles. Lors de la passe 2, chaque ligne d'instruction est réexaminée une deuxième fois en vue de l'encodage final. Chaque ligne de programme est donc examinée deux fois, à raison d'une fois par passe. De plus, la table des symboles est entièrement "balayée" à chaque fois qu'un symbole nouveau se présente pour être résolu, aussi bien en passe 1 qu'en passe 2. Si un programme est corrigé cinq fois de suite par exemple, l'examen d'une ligne quelconque sera fait dix fois puisqu'il y aura cinq assemblages, donc 10 passes. Ainsi, les lignes non corrigées qui constituent l'immense majorité du programme, seront examinées 10 fois alors qu'une seule fois suffit L'invention consiste à effectuer un "pré-assemblage" des lignes. Les informations issues de ce pré-assemblage sont stockées dans une structure appropriée (au sens du langage C) afin d'être exploitées ultérieurement par l'assembleur. Dans un environnement intégré, l'éditeur est généralement constitué d'une mémoire de stockage et d'un tableau de structures. A chaque ligne correspond une structure qui comprend en général trois éléments: un pointeur vers le début de la chaîne de caractères, le nombre de caractères de la chaîne et un indicateur d'erreur. Dans tous les éditeurs, ce tableau de structures existe mais peut revêtir des formes diverses. Par exemple, le nombre de caractères peut être remplacé par la présence du caractère NUL en fin de chaque chaîne. L'invention consiste à adjoindre à chaque structure quelques champs supplémentaires qui contiennent des informations de pré-assemblage. Ci-dessous figure un exemple d'application qui fera très bien comprendre le principe. Des noms symboliques sont affectés à chaque élément de la structure. Ces éléments constitutifs de chaque structure peuvent ainsi être par exemple: "Address" : Variable du type Pointeur sur char. Il s'agit de l'adresse de chaque chaîne de caractères dans la mémoire principale. "Count" :Variable du type char. Nombre de caractères de chaque chaîne. "Error": Variable du type char. Etat de la chaîne de caractères (ligne d'instruction). Contient éventuellement le numéro de l'erreur, ou O si la ligne est correcte. "Window~Number1 : Variable du type char. Cette variable indique le numéro de fenêtre ou de fichier lorsque l'éditeur travaille en mode multi-fichiers multi-fenêtres (cas d'un environnement Windows 3.1 par exemple) "Status" :Variable du type int. Cette variable contient différentes informations. Par exemple, un bit pourra être mis à 1 si la ligne-source est un commentaire et ne nécessite aucun assemblage. 1Byte#Count11: Variable du type char. Contient le nombre d'octets de l'instruction après pré-assemblage. Contient la valeur -1 si le nombre d'octets n'a pu être déterminé. "Hash Variable du type char. Contient le code Hash de l'instruction ou de la directive. "Opcode [ 0 ] ", "Opcode [ 1 ] ", "Opcode [ 2 ] ", '1Opcode [ 3 ] 11, '1opcode [ 4j11 :Variables du type unsigned int (tableau). Contiennent éventuellement le code binaire de l'instruction après pré-assemblage. Le nombre d'octets ou de mots ainsi pré-assemblés pourra être mis dans la variable "Status" évoquée plus haut. "Address~Mode":Variable du type char. Contient éventuellement le type d'adressage (0=implicite, 1 immédiat, 2=étendu etc...). Dans certains microprocesseurs tel que le 68000, il peut y avoir deux types d'adressages différents par ligne. Dans ce cas, il faut évidemment prévoir, en plus, une ou plusieurs autres variables du même type. "Cycle Count":Variable du type unsigned int. Contient le nombre de cycles de l'instruction. "Pc" : Variable du type unsigned long int. Contient le Pc de l'instruction. La présence de cet élément se justifie pour les directives du type ORG. Le Pc peut être également très utile pour la suite de l'assemblage, notamment lorsqu'il faut éditer un listage des instructions ou construire des trames "Hex", "S" ou autres. "Label~Index" : Variable du type int. Index du symbole spécifié en étiquette ou opérande dans la table des symboles. Lorsque l'instruction contient un symbole, cet index permet de retrouver immédiatement l'emplacement de ce symbole dans la table des symboles. "Opcode Offset", "Operand Offset", "Comment~Offset" : Variables du type char. Emplacement de chaque champ de l'instruction dans la ligne source. Ces variables sont utiles non seulement pour accélérer le formattage des lignes lors du listing, mais permettent de retrouver immédiatement chaque champ pour certains cas particuliers lors de l'assemblage final. "Check Sum": : Variable du type char. Effectue une somme de vérification (check-sum) de la ligne source et de tous les champs. Puisqu'un programme est pré-assemblé une fois pour toutes, il pourra résider plusieurs heures en mémoire. Il est important d'avoir une sécurité optimale. Aussi, il est judicieux de réaliser un check-sum de chaque ligne périodiquement. Les quelques millisecondes perdues se retrouvent en sécurité. Une option et une commande indépendante permettent ou non de faire cette vérification par check sum. Note : Les microprocesseurs et leurs instructions sont parfois très différents les uns des autres. Il en résulte que l'exemple de structure donnée ici (adaptée au 68000) pourra être modifié dans de grandes proportions. La structure qui vient d'être décrite s'écrira donc en langage C: struct {char *Address; char Count; char Error; char Window Number; int Status ; char Count; char Code; unsigned int Opcode [ 5 ] ; char Address~Mode; unsigned int Cycle Count; unsigned long int Pc; intLabel~Index; char Opcode Offset; char Operand Offset; char Comment Offset; char Checksum; } Table [ 1000 ] ; Ici, l'on suppose que le programme peut faire 1000 lignes au maximum (une structure par ligne). Cette structure fait environ 25 octets de plus qu'une structure traditionnelle. li en résulte une augmentation de 25000 octets pour 1000 lignes. Cet inconvénient d'accroissement de mémoire (au demeurant négligeable) est largement compensé par le gain considérable de vitesse d'assemblage. Le pré-assemblage évoqué plus haut consiste à examiner chaque ligne-source de programme lors du chargement initial du fichier ou de l'édition. Le pré-assembleur essaie de recueillir un maximum d'informations qui sont alors chargées dans les champs de l'extension de structure qui vient d'être décrite. Par ailleurs, lorsqu'une étiquette est trouvée, celle-ci est stockée automatiquement dans la table des symboles et son index mis également dans la structure à "Label~Index". Enfin, le pré-assembleur essaie si possible de résoudre les symboles qui peuvent se trouver dans l'opérande. Si un symbole ne peut être résolu, un bit est mis à un dans le Status. Par la suite, l'assembleur ira tout simplement puiser dans cette structure les informations dont il a besoin. Si la ligne source n'est pas modifiée, la structure ne le sera pas non plus et il n'y a pas lieu de refaire un assemblage inutile. Ce pré-assemblage pourra s'effectuer de quatre manières différentes: 1. Lors du chargement initial du fichier-source en mémoire à partir du disque. Une option de l'environnement intégré permet alors de pré-assembler les instructions lors de ce chargement ou non. 2. Par une commande ("pré-assemblage" par exemple) que l'utilisateur peut appeler à tout moment. 3. Dans l'éditeur lui-même à chaque fois que l'utilisateur valide une ligne par CR ou effectue des modifications sur le contenu d'une ligne. Une option permet de réaliser ce pré-assemblage ou non à chaque ligne. 4. Automatiquement, lors d'une détection d'un check-sum erroné. Comme indiqué plus haut, cette procédure est conditionnée par une option. Dans les deux premiers cas, le pré-assemblage est réalisé sur la totalité du texte. Dans le troisième cas, il n'est effectué que sur la ligne qui vient d'être éditée. La meilleure méthode consiste à faire un pré-assemblage général, lors du chargement du texte, puis ensuite un pré-assemblage ligne par ligne. Lorsque le pré-assemblage a lieu ligne par ligne (3ème cas), il est possible de corriger immédiatement les erreurs détectées. En effet, l'utilisateur se trouve déjà dans l'éditeur et il suffit de corriger l'erreur. Une amélioration consiste à indiquer à l'utilisateur différentes solutions pour la correction des erreurs. Pour cela, une simple table du genre hypertexte pourra être scrutée. Une fois le texte-source édité et pré-assemblé, celui-ci doit être assemblé pour produire le code final. C'est à ce moment que le gain de temps devient considérable. En effet, avec la présente technique, la passe 1 se limite principalement à examiner le champ Byte Count de la structure associée à chaque ligne. Le PC est incrémenté en conséquence. Si ce Byte Count est à 0xFF (par exemple), cela veut dire qu'il y a une particularité comme par exemple la présence d'une directive ORG ou un symbole non résolu. La passe 1 sera également réduite du fait que les étiquettes sont déjà introduites dans la table des symboles lors du pré-assemblage. Le seul travail qui reste à faire est d'introduire la valeur du PC dans la table des symboles pour les étiquettes enregistrées mais non définies. Enfin, les étiquettes non résolues (appelées généralement "étiquettes forward") font l'objet d'un bit mis à un dans le Status. Il en résulte que la table des symboles n'a pas lieu d'être scrutée dans ce cas précis. Ce bit sert essentiellement à définir le mode d'adressage, en l'occurrence du type "long". La passe 2 sera également réduite dans des proportions considérables. En effet, la structure des lignes contient plus de 95% des éléments recherchés. La passe 2 se contente simplement de lire le Byte Count pour incrémenter le Pc en conséquence. Les quelques instructions ayant des étiquettes non définies seront traitées. Là aussi, le traitement sera très réduit car un grand nombre d'informations sont déjà présentes dans la structure, comme l'index du symbole à traiter dans la table des symboles. Avec un assembleur traditionnel, la passe 2 construit les opcodes de l'instruction. Dans la présente invention, cela n'est pas nécessaire car ces opcodes sont enregistrés dans la structure (Opco de [ 5 ] ) lors du pré-assemblage. Si l'utilisateur désire éditer un listing, là encore il n'y a rien à faire: la structure dispose déjà de tous les éléments. I1 en est de même pour la construction des trames "hex", "S" ou autres. Cette construction pourra être effectuée une fois pour toutes, lorsque le programme est assemblé sans erreur. Là encore, la structure comprend tous les éléments nécessaires à la construction de ces trames. De plus, des trames de structures différentes pourront être créées car les éléments nécessaires à cette création sont à l'état d'origine (Pc et Opcodes principalement). Dans un environnement intégré qui comprend le débogueur, il est intéressant de créer des trames binaires optimisées au lieu de trames "Hex", "S" ou autres. Un transfert en 8 bits purs (binaire) est deux fois plus rapide qu'un encodage sur deux demi-octets comme c'est le cas des trames "Hex" ou "S". Le transfert d'un programme vers une carte d'application s'effectuera ainsi beaucoup plus rapidement. Le principe de l'optimisation n'est pas décrit ici car il relève de la technique pure. Puisque l'assemblage d'un texte déjà pré-assemblé est pratiquement instantané, il devient possible de "sauter" cette phase d'assemblage aux yeux de l'utilisateur. Dans un environnement de développement, le système donnera le contrôle directement au module de téléchargement des trames binaires, "Hex", "S" ou autres puis au débogueur. Ainsi, lorsque le texte est édité, l'utilisateur passe directement au débogage de son programme. En fait, les fonctions de pré-assemblage, d'assemblage, de création de trames binaires, de téléchargement des trames dans la mémoire de la carte en test et de débogage sont regroupées en une seule commande. Cette procédure peut être mise en oeuvre grâce à une commande spécialisée ou, plus simplement, grâce à une touche de fonction du clavier. Dans un environnement intégré qui regroupe à la fois l'éditeur et l'assembleur, une telle technique est relativement simple à mettre en oeuvre. Elle peut également être appliquée aux assembleurs autonomes, mais la structure qui est décrite ci-dessus doit être sauvegardée dans un fichier spécial puis relue à chaque nouvel assemblage. La méthode de stockage préconisée consiste à effectuer la sauvegarde de la structure dans un fichier indépendant du fichier-source de façon à ne pas perturber l'éditeur de l'utilisateur (un éditeur accepterait fort mal ces informations concernant les structures). Pour éviter toute discordance, le nom générique du fichier d'origine, son passage, ses attributs et sa date de création sont également mis dans ce fichier spécial. Lors du chargement d'un fichier texte quelconque en mémoire, l'assembleur essaie de trouver un fichier de même nom générique mais portant une extension spéciale (par exemple .STC comme "structure"). Si ce fichier existe, le nom du fichier texte, ses attributs, son passage et sa date de création sont également lus et vérifiés. Si il y a concordance, les structures sont remplies avec les informations de pré-assemblage. Dans le cas contraire, un pré-assemblage a lieu après chargement du fichier texte. Enfin, pour accélérer encore le pré-assemblage, celui-ci pourra s'effectuer dans une routine d'interruption. Un système d'horloge envoie des tics périodiques provoquant des interruptions pendant l'édition ou n'importe quelle autre fonction (lecture fichier par exemple). Si aucune commande n'est en cours d'exécution, le contrôle est passé au pré-assembleur qui effectue les tâches énoncées précédemment. Le pré-assembleur pourra également effectuer un contrôle permanent d'intégrité par check-sum en tâche de fond. A noter que le contrôle est toujours donné en priorité à l'édition ou à la tâche principale. Ainsi, en fin d'édition, le programme sera déjà assemblé à 90% sans que l'utilisateur ne le sache. REVENDICATIONS 1. Dispositif d'assemblage des programmes caractérisé par le fait qu'il comprend d'une part un pré-assembleur dont l'objet est de remplir une structure avec différentes informations concernant ces instructions, et d'autre part une procédure restreinte d'assemblage du fait que l'instruction est déjà pré-assemblée et qu'il est possible de rechercher très rapidement le résultat de ce pré-assemblage dans ladite structure. 2. Dispositif selon la revendication 1, constitué par un tableau de structures à raison d'une structure par ligne, lequel tableau est chargé par une procédure qui examine chaque ligne, recherche les informations d'assemblage, enregistre les symboles, détermine leur emplacement dans la table des symboles et essaie de résoudre les symboles d'opérande. 3. Dispositif, selon l'une des revendications 1 ou 2, caractérisé par le fait que l'assemblage définitif du programme consiste principalement à rechercher dans la structure les informations de l'instruction qui ont été stockées précédemment par le pré-assemblage. 4. Dispositif, selon l'une des revendications 1 à 3, comprenant une boîte à options indépendantes dans laquelle l'utilisateur peut choisir son mode de pré-assemblage : lors du chargement initial du programme-source, en édition à chaque validation ou modification de lignes, par commande séparée ou automatiquement par détection d'une somme de vérification erronée. 5. Dispositif, selon l'une des revendications 1 à 4, constitué par le fait que le système propose à l'utilisateur une option combinée comprenant le pré-assemblage, l'assemblage, la création de trames binaires, le téléchargement de la trame dans la mémoire de la carte et le débogage. 6. Dispositif, selon l'une des revendications 1 à 5, comprenant un système de création des trames traditionnelles "Hex", "S" ou autres ainsi que des trames rapides en binaire pur à partir des éléments contenus dans la structure. 7. Dispositif, selon l'une des revendications 1 à 6, comprenant un dispositif d'affichage des erreurs lorsque le pré-assemblage ligne à ligne est réalisé ainsi qu'une aide en ligne en hypertexte. 8. Dispositif, selon l'une des revendications 1 à 7, caractérisé en ce qu'il comprend une procédure de création d'un fichier spécialisé comprenant la structure ainsi que les informations du fichier-source, notamment le nom, le passage, la date de création et différents autres attributs de fichier. 9. Dispositif, selon l'une des revendications 1 à 8, caractérisé en ce que, lors de la lecture du fichier spécialisé comprenant la structure, une comparaison est faite avec le fichier source afin d'établir si un pré-assemblage est nécessaire ou non. 10. Dispositif, selon l'une des revendications 1 à 9, constitué par le fait que le pré-assembleur inscrit dans la structure une somme de vérification permettant de voir rapidement si une chaîne de caractères correspond bien aux données de son pré-assemblage précédent et que ladite vérification s'effectue soit par commande spécialisée, soit en tâche de fond sous interruption. 11. Dispositif, selon l'une des revendications 1 à 10, caractérisé en ce qu'une horloge produit périodiquement des interruptions permettant au pré-assemblage de s'effectuer si aucune autre tâche prioritaire n'est en cours.