2016-01-30 1 views
2

J'essaie de résoudre ces opérations simples de multiplication et de division dans l'assemblage.Empêcher l'alignement du registre AX par l'instruction DIV

5*4 + 35/7 

Je l'ai fait

mov al,5 
mov bl,4 
mul bl 

mov ax,35 
mov bl,7 
div bl 

Ma valeur précédente pour la multiplication dans le registre AX est remplacé par un nouveau résultat de la division. Comment puis-je réparer ça?

+0

Êtes-vous écrit 8086 code 16 bits ciblant DOS ou EMU8086? –

+0

J'écris ceci pour emu8086 ..yes 16bit –

Répondre

1

Vous devrez multiplier 5 * 4 et ensuite pousser la valeur sur la pile. Ensuite, faites votre deuxième calcul, la division. Ensuite, supprimez la première valeur de la pile et ajoutez les valeurs ensemble.

+0

En fait, maintenant que je pense à ce sujet, et il a été un certain temps, mais je crois que le problème peut être que al est la moitié de la hache. Donc, quand vous déplacez une valeur dans Axe, il écrase al. En d'autres termes, al et ah sont les bits hauts et bas d'ax. –

+0

Il n'est pas nécessaire d'utiliser la pile, mais votre point général est correct: l'OP clobffe le résultat mul (qui fait ax = al * src) avec 'mov ax, 35'. x86 a 7 registres à usage général (sans compter le pointeur de pile, qui peut être utilisé comme usage général, mais ne l'est jamais). Ceci n'est pas marqué comme 8086 non plus, donc il n'y a aucune raison de ne pas utiliser l'opérande 2 ou 3 ('imul dest, src, imm') pour sauvegarder les choses en dehors de eax/edx (utilisé implicitement par' mul' et ' div'). –

+0

Je suis d'accord. Une fois que j'ai réalisé que al et ah sont les plus bas et les plus élevés de la hache alors la solution est évidemment simplement d'utiliser un autre registre. –

1

Pour répondre à la question principale: Vous pouvez utiliser imul reg, reg, imm pour effectuer votre multiplication dans un registre différent. Ou vous pouvez simplement mov ecx, eax enregistrer votre résultat dans un registre dont vous n'avez pas besoin pour div.


Puisque vous n'avez pas indiqué d'où proviennent les données, il est évident que vous devez effectuer le calcul au moment de l'assemblage.

mov eax, 5*4 + 35/7 

Si vous vouliez encore calculer au moment de l'exécution, vous devez commencer par les valeurs constantes immédiates, dans des registres, ou dans la mémoire. Il est pratique d'illustrer un mélange de ceux-ci (puisque div n'a pas de forme d'opérande immédiate)

Il est généralement préférable d'utiliser la taille d'opérande par défaut, qui est 32 bits en mode 32 et 64 bits. Cependant, les opérations 8bit ne sont généralement pas plus lentes.

mov eax, 35 
div byte [seven]  ; al = ax/7, ah=ax%7. wider operand sizes divide edx:eax by the src. 

mov cl, 5 
lea eax, [ecx*4 + eax] ; al = cl*4 + al. Ignore the garbage in the high bits. 
; result in al 

section .rodata 
seven: db 7 

div est lent, donc compilers replace divides by constants with multiplies by funky constants, and shift the result, parce que ce qui est possible avec le débordement du complément de 2. Voir Which 2's complement integer operations can be used without zeroing high bits in the inputs, if only the low part of the result is wanted? pour justifier l'utilisation de lea pour multiplier par 4 et ajouter, sans effacer les bits hauts.

+0

Je tiens à souligner que ma modifier ne modifiait pas la question tout.L'ajout du tag x86 ne dit pas explicitement s'il s'agit d'un code 16 bits, 32 bits ou 64 bits. L'étiquette elle-même est formulée pour englober les trois. J'ajouterais une étiquette de processeur spécifique une fois que l'OP répondra à la question que j'ai posée sous la question. Toujours possible, ils ciblent le code 16 bits. Je soupçonne que c'est un code de 16 bits basé sur son université et une partie du programme d'études. –

+0

@MichaelPetch: J'ai réalisé cela après avoir regardé le montage plus attentivement. Je n'avais pas compris à partir de l'original brouillé que l'OP savait que le problème était la hache. Aussi, ouais je me suis dit qu'il écrivait probablement du code 16bit, mais 16bit est bête donc j'ai délibérément évité de l'encourager. Je n'ai pas regardé sa page d'utilisateur pour essayer de comprendre à quelle université il assistait. multi-opérande 'imul' est toujours disponible en mode 16 bits sur les processeurs normaux, et j'avais deviné que c'était une question DOS, pas merdique 8086 sans fonctionnalités 386. –

+0

Il a ajouté un commentaire, et je ne suis pas surpris qu'il s'agissait d'emu8086, donc la cible est le code 16 bits. En ce qui concerne les versions multi-utilisateurs de Imul n'a pas commencé à apparaître jusqu'à 80286 (certains ont été ajoutés dans le 386). Je ne crois pas que l'une des variantes multi-opérandes fonctionne sur emu8086 car il a été conçu comme un environnement 8086. –

2

EMU8086 est basé sur 8086 des instructions afin que vous avez uniquement les versions d'opérandes uniques de MUL et DIV. Juste pour vous faire connaître, IMUL est la version signée de MUL, et IDIV est la version signée de DIV. En supposant que vous aviez l'intention de faire de l'arithmétique non signé votre code pourrait ressembler à ceci:

mov al,5 
mov bl,4 
mul bl 
mov cx, ax  ; Save AX to CX 

mov ax,35 
mov bl,7 
div bl 

xor ah, ah  ; Result(quotient) of DIV in AL, ensure AH is zero 
add ax, cx  ; AX=AX+CX 

Il n'y a aucun moyen d'empêcher AX d'être détruit avec les instructions spécifiques de 8086 MUL et DIV. Vous devrez déplacer la valeur vers une zone de travail. Nous allons utiliser le registre CX pour cela dans le code ci-dessus. Puisque nous sauvons le résultat de l'instruction MUL -CX nous avons juste besoin d'ajouter au résultat de l'instruction DIV (où le quotient est AL).Nous remettons à zéro le reste stocké dans AH, laissant le quotient dans AL. AX contiendrait maintenant le quotient (en tant que valeur de 16 bits) que nous ajoutons à CX, et le résultat final de l'équation est stocké dans AX. Une simplification pour multiplier par 4 consiste à décaler une valeur à gauche de 2 bits. Ce code:

mov al,5 
mov bl,4 
mul bl 
mov cx, ax  ; Save AX to CX 

peut être réduite à:

mov cx, 5 
shl cx, 2  ; Multiply CX by 4 

Le processeur 8086 ne supporte pas SHL déplacement de plus de 1 bit, sauf par l'intermédiaire du registre CL. L'assembleur EMU8086 traduit automatiquement l'instruction SHL reg, imm en une ou plusieurs instructions SHL, reg, 1. Dans ce cas SHL CX, 2 a été traduit à:

shl cx, 1  ; Multiply CX by 2 
shl cx, 1  ; Multiply CX by 2 again 

La plupart des 8086 assembleurs ne le feront pas la traduction pour vous. En variante, le nombre de bits à décaler peut être spécifié dans le registre CL. Ce (ou l'équivalent) travaillerait avec la plupart des assembleurs 8086:

mov cl, 2  ; Number of bits to shift left by in CL 
mov dx, 5 
shl dx, cl  ; Shift DX to the left by CL(2) is equivalent to multiply by 4 

mov ax,35 
mov bl,7 
div bl 

xor ah, ah  ; Result(quotient) of DIV in AL, ensure AH is zero 
add ax, dx  ; AX=AX+DX 
+0

Le 'shl cx, 2' est __not__ une instruction 8086! Seuls les quarts de travail sont autorisés. – Fifoernik

+1

@Fifoernik Cela est vrai, mais la question est également étiquetée EMU8086 (par le commentaire OPs). Un endroit EMU8086 diverge du 8086 est que l'assembleur supporte SHL par une valeur immédiate (autre que 1), mais produit intérieurement plusieurs SHL par 1 instructions. J'ai modifié ma réponse pour apporter cette précision. –

+0

Donc, quand vous dites "intérieurement", vous voulez dire "assembler le temps"? Si vous étiez à un seul pas votre code, vous verriez des instructions répétées 'shl cx'? Votre formulation donne l'impression qu'elle gère l'encodage du compte 'imm8'. Si c'est juste du sucre syntaxique dans l'assembleur, n'importe quel assembleur pourrait le faire pour les cibles 8086 s'il le voulait. Il peut arriver que emu8086 soit le seul assembleur 8086 à le faire, mais cela fonctionne dans emu8086 à cause de son assembleur, pas parce que ce n'est pas un vrai processeur 8086. –

2

Ma valeur précédente pour la multiplication dans le registre AX est remplacée par un nouveau résultat de la division. Comment puis-je réparer ça?

Assez simple. Mettez le résultat de la multiplication dans un registre supplémentaire (j'ai utilisé DX), calculez le prochain terme de l'expression, enfin ajoutez les deux résultats. Il est important de noter que le quotient est seulement dans le registre AL, donc vous devez effacer le registre AH avant de faire l'addition! (Les chiffres utilisés dans l'exemple « 35/7 » donner un reste de 0 à AH mais vous ne devriez pas compter sur ce lorsqu'on lui a demandé d'écrire un programme!)

mov al,5 
mov bl,4 
mul bl  ; -> Result is in AX 
mov dx, ax 

mov ax,35 
mov bl,7 
div bl  ; -> Result is in AL 

mov ah, 0 
add ax, dx ; -> Final result is in AX