home *** CD-ROM | disk | FTP | other *** search
- *cX Curso de programación en assembler (y III)
-
- *cR El primer programa
- *c^
- Hoy, por fin, abordaremos el primer ejemplo
- práctico en assembler. El primer programa que
- haremos será (como no) el *c hola mundo*c^. Pero
- antes de poder darle caña al ensamblador ne-
- cesitamos tener alguno... la verdad es que
- todos teneis uno en vuestro PC, el Debug, pe-
- ro cuando hay que hacer cosas complicadas se
- hace imposible y por eso a lo largo del curso
- pasaremos un poco de él (excepto en este
- artículo) y nos centraremos en el Turbo
- Assembler y el A86 que al ser shareware y
- tener una sintaxis simplificada os ayudará
- a empezar.
- El Debug del DOS se invoca escribiendo
- *cvDEBUG*c^ en la linea de comandos y si quieres
- puedes poner detrás el nombre del programa a
- debuggear o a crear. Para hacer el *c hola
- mundo*c^ entraremos escribiendo:
- *cH
- DEBUG hola.com
- *c^
- lo primero que el programa nos dirá es que
- hemos cometido un error porque el fichero
- *c hola.com*c^ no existe (si no nos da el error
- es que si existe y lo sobre-escribiremos).
- Ahora nos encontramos con un prompt que es
- una rallita *cj-*c^ y ahí es donde deberemos
- entrar los comandos, por ejemplo *cj?*c^ te
- mostrará todos los posibles. El que más nos
- va a interesar de momento es *cja*c^ que nos
- permite ensamblar directamente las intruc-
- ciones que entremos.
- La primera instrucción que veremos hoy (y
- la que es más usada) será MOV. Con ella con-
- seguimos copiar el contenido de una variable,
- registro, constante en otro. Su prototipo es
- bastante sencillo:
- *cH
- MOV <destino>, <origen>
- *c^
-
- donde <origen> será el valor que copiaremos
- en <destino>. En general, en el ensamblador
- estandard de los 80X86 se especifica primero
- el destino y luego el origen como veremos en
- siguientes instrucciones. Un registro es una
- especie de variable que se guarda muy cer-
- quita del procesador y por ello se accede a
- ella de forma muy rápida. Una variable la
- consideraremos una porción de memoria de
- tamaño BYTE, WORD... que podrá tomar distin-
- tos valores según lo que queramos hacer. Una
- constante será un valor que definiremos cuan-
- do creemos el código fuente y que no se podrá
- cambiar bajo ningún concepto.
- Los registros son una parte fundamental de
- la arquitectura de un ordenador que ayudan al
- programador a acelerar los programas. Existen
- 4 registros llamados "de uso general" que son
- AX, BX, CX y DX de 16bits cada uno y dividi-
- dos en dos partes de 8bits (parte alta-high
- y parte baja-low):
- *cH
- AX --> AH - AL
- BX --> BH - BL
- CX --> CH - CL
- DX --> DH - DL
- *c^
- Existen tambien otros registros no impor-
- tantes de momento como son CS, SS, SP, DI...
- Simplemente mencionar el registro DS que es
- un registro de segmento que lo que hace es
- apuntar al segmento de memoria sobre el que
- se opera (recordad lo que deciamos de la me-
- moria segmentada del PC). Por ejemplo, si
- decimos que DS:DX apunta a una cadena de
- texto, lo que queremos decir es que en el
- segmento DS si nos desplazamos DX posiciones
- nos encontraremos con una ristra de bytes
- que definen una cadena de texto; a DS se le
- llamaria segmento y a DX se le llamaria off-
- set o desplazamiento.
- Bueno veamos como queda el programa y se-
- guimos explicando cosas a partir del mismo:
- *cH
- mov ax, cs *cO [1]
- *cH mov ds, ax *cO [2]
- *cH mov dx, 110 *cO [3]
- *cH mov ah, 9 *cO [4]
- *cH int 21 *cO [5]
- *cH mov ax, 4c00 *cO [6]
- *cH int 21 *cO [7]
- *cH db 'Hola mundo!!$'*cO [8]
- *c^
- para guardarlo debemos presionar ENTER, es-
- cribir *c RCX*c^, pulsar ENTER, escribir la lon-
- gitud del programa a guardar y ENTER y escri-
- bir *c w*c^ (y ENTER :). Si te dice que hay algún
- error es que no has hecho algo bien. En este
- caso el tamaño del programa a almacenar es 1D
- (habrás observado que en el Debug todos los
- números se deben escribir en hexadecimal.
- Vamos con el comentario línea por línea del
- programa (supongo que te darás cuenta de que
- no debes escribir los numeros entre corche-
- tes ;). En la primera linea vemos una de las
- asignaciones MOV de las que hablabamos antes,
- el registro CS (que apunta al trozo de có-
- digo) se cópia en AX. La segunda instrucción
- hace algo parecido, pero esta vez cópia en
- un registro de segmento lo que habia en AX
- (que mira tu por donde es lo mismo que lo
- que hay en CS). En la linea 3 se asigna una
- constante a un registro, DX pasará a valer
- 110h. Lo mismo que antes se hace en la cuarta
- línea solo que ahora se trata de un registro
- de 8bits (la mitad de arriba de AX). Las ins-
- trucciones 5 y 7 son llamadas a interrupcio-
- nes y las veremos ahora enseguida. La ins-
- trucción 6 es otra vez una asignación de una
- constante a un registro (observa lo frecuen-
- tes que son las instrucciones MOV). Y por úl-
- timo, la palabra clave *c db*c^ no se trata de
- una instrucción própiamente dicha, sino que
- sirve para definir una espécie de matriz o
- array de BYTES (como en los lenguajes de alto
- nivel).
- Todo esto está muy bien, ¿pero donde está
- el análisis semántico? Pues aquí mismo... Si
- miramos lo que hace el programa en las 2 pri-
- meras líneas es meter en *c ds*c^ el contenido de
- *c cs*c^, entonces ¿por que no hacer *c MOV DS,CS*c^
- directamente? Sencillo, porque no se puede:
- los registros de segmento no pueden asignarse
- a otros registros de segmento, por tanto,
- cada vez que queramos hacer algo así, tendre-
- mos que copiar a un registro auxiliar el con-
- tenido del origen. Las dos siguientes líneas
- (3 y 4) son una simple preparación para la
- interrupción que se lanzará en la línea 5
- (tambien forman parte de esa "preparación"
- las instrucciones 1 y 2). Las interrupciones
- las veremos más a fondo ahora mismo, pero
- baste decir que la interrupción que llamamos
- primero nos permite ver una cadena en panta-
- lla y la segunda hace que regresemos al
- sistema operativo.
- *cR
- Las interrupciones
- *c^
- Las interrupciones son un método de sim-
- plificar la tarea al programador ya son como
- pequeñas funciones o procedimientos que de-
- vuelven valores valiosos o simplemente hacen
- algo que resultaria difícil de programar ma-
- nualmente. Los "parámetros" se le pasan en
- los registros y los valores nos los devuelve
- en registros tambien. En el PC hay exacta-
- mente 256 servicios de interrupción (del 00h
- al FFh) que se dividen en centenares de sub-
- servicios por lo que para programar en assem-
- bler se hace necesaria una lista suficiente-
- mente completa de todas las interrupciones
- como la de *cRalf Brown*c^ (que podeis encontrar
- en muchos CD-ROMs de share).
- Si comprendemos apróximadamente este
- funcionamiento ya estamos en disposición de
- ver que es exactamente lo que se hacia en el
- programa de ejemplo. La INT 21h es la inter-
- rupción que lleva el grueso de los servicios
- del sistema operativo (DOS), tiene unos 200
- subservicios y debe identificar a cual de
- ellos se va a llamar en cada momento. Para
- ello, en el registro AH debemos guardar el
- número de subservicio (en nuestro caso el 09)
- y llamar a los servicios con los parámetros
- correspondientes. La lista de Ralf Brown para
- este caso indica lo siguiente:
- *c9
- --------D-2109------------------------------
- INT 21 - DOS 1+ - WRITE STRING TO STANDARD
- OUTPUT
- AH = 09h
- DS:DX -> '$'-terminated string
- Return: AL = 24h (the '$' terminating the
- string, despite official docs
- which state that nothing is
- returned) (at least DOS 3.3-5.0)
- Notes: ^C/^Break are checked, and INT 23 is
- called if either pressed standard
- output is always the screen under DOS
- 1.x, but may be redirected under DOS
- 2+ under the FlashTek X-32 DOS exten-
- der, the pointer is in DS:EDX
- SeeAlso: AH=02h,AH=06h"OUTPUT"
- *c^
- Lo primero que se indica es el número, ser-
- vicio y nombre de la interrupción para poder
- localizarla. Luego están los parámetros de
- entrada que en nuestro caso son AH=09h (lógi-
- camente!!) y DS:DX=<Cadena terminada con '$'>
- Observa el código fuente del programa y verás
- como comienzas a ligar cabos sueltos. Según
- esto, en AL devolverá el valor 24h que cor-
- responde al valor ASCII de *c $*c^ (hace tambien
- una observación de que esto no está documen-
- tado). Como observaciones nos dice que pul-
- sando CTRL-C o CTRL-PAUSA haremos saltar la
- interrupción 23h (esto lo veremos en un ejem-
- plo de otro número) que hace que se interrum-
- pa el programa. Tambien nos dice que es con-
- veniente ver los subservicios 02h y 06h.
- Veamos nuestro programa como asigna a DS:DX
- la cadena terminada en *c $*c^ que aparece al final
- del código: primero, como ya habiamos visto,
- cópia el segmento de código en DS y luego en-
- tra el valor constante 110h en DX. Si en el
- Debug escribimos:
- *cH
- u 100
- *c^
- veremos lo que hemos introducido y podremos
- observar que al principio de cada línea
- aparece una cosa así:
- *cH
- XXXX:YYYY
- *c^
- eso no es ni más ni menos que la dirección
- segmentada donde estamos guardando el código
- del programa; *cHXXXX*c^ es el segmento e *cHYYYY*c^ es
- el desplazamiento u offset dentro de ese
- segmento. Por tanto, la dirección que yo he
- de pasar es el segmento donde reside la
- cadena (que resulta ser el del código) y el
- offset dentro de ese segmento que es 110h y
- que si miras el programa desensamblado
- (despues de usar el comando 'u' del debug)
- es 0110 precisamente.
- Un posible pero a todo esto es: pero, ¿por-
- que has entrado el offset como constante y el
- segmento lo has sacado del registro CS? La
- respuesta a esto la entenderás mejor cuando
- veamos los programas COM y EXE, aunque es
- sencilla (a priori); cuando el sistema opera-
- tivo carga un programa (COM en este caso)
- lo que hace es buscar un segmento de memoria
- libre (los TSR ocupan memoria y el própio SO)
- y lo carga a partir de la dirección 0100h,
- por tanto podemos saber el offset pero no el
- segmento donde se cargará.
- *cR
- El Debug
- *c^
- A parte de ensamblar y desensamblar pro-
- gramas, el debug (y esa es su razón de ser)
- se usa para ejecutar programas paso por paso
- como se hace en los IDEs de los lenguajes de
- alto nivel. Para ejecutar un paso (step) de
- un trozo de código usaremos *c p*c^ y para tra-
- zar usaremos *c t*c^. La diferencia entre una
- instrucción y otra es simplemente que con
- *c t*c^ si encontramos una INT (o algunas
- instrucciones que veremos para hacer llamadas
- a subprocedimientos) entraremos dentro de
- ella, mientras que con *c p*c^ ejecutaremos el
- código linealmente. Para lo que sabemos
- ahora es suficiente con *c p*c^ (no usar *c t*c^
- delante de INT!!).
- La utilidad de todo esto cuando se está
- comenzando es increible, así podrás ver como
- las instrucciones e interrupciones modifican
- los registros. Hablando de registros, el
- registro IP es un registro que apunta a la
- instrucción que está siendo ejecutada en cada
- momento dentro del segmento CS del que ya
- sabiamos algo. Vamos a ver un ejemplo de
- trazeado de un programa (el "hola mundo")
- y observaremos como cambian los registros:
- *cA
- AX=109FBX=0000CX=001DDX=0000SP=FFFE
- -->BP=0000SI=0000DI=0000
- DS=109FES=109FSS=109FCS=109FIP=0102
- -->NV UP EI PL NZ NA PO NC
- 109F:0102 8ED8 MOV DS,AX
- *c^
- Al ejecutarse la primera instrucción AX
- ha adquirido el valor de CS. Podemos observar
- tambien que DS es igual a CS y que no es ne-
- cesario copiarlo, pero siempre es mejor ase-
- gurarse de hacer las cosas bien. La instruc-
- ción 'p' nos muestra tambien cual será la si-
- guiente instrucción a ejecutar (MOV DS,AX).
- Observa el valor de CS:IP y la dirección de
- la siguiente instrucción a ser
- ejecutada y fíjate que es el mismo.
- *cA
- AX=109FBX=0000CX=001DDX=0000SP=FFFE
- -->BP=0000SI=0000DI=0000
- DS=109FES=109FSS=109FCS=109FIP=0104
- -->NV UP EI PL NZ NA PO NC
- 109F:0104 BA1001 MOV DX,0110
- *c^
- Trás esta instrucción no podemos observar
- nada nuevo en DS ya que el valor era
- el mismo que tenia anteriormente. Lo que
- si podemos ver es que CS:IP sigue
- apuntando a la siguiente instrucción a
- ejecutar y esto será así siempre.
- *cA
- AX=109FBX=0000CX=001DDX=0110SP=FFFE
- -->BP=0000SI=0000DI=0000
- DS=109FES=109FSS=109FCS=109FIP=0107
- -->NV UP EI PL NZ NA PO NC
- 109F:0107 B409 MOV AH,09
- *c^
- Podemos ver como ha cambiado DX, pasando
- del valor 0000h al 0110h que es el
- offset de la cadena.
- *cA
- AX=099FBX=0000CX=001DDX=0110SP=FFFE
- -->BP=0000SI=0000DI=0000
- DS=109FES=109FSS=109FCS=109FIP=0109
- -->NV UP EI PL NZ NA PO NC
- 109F:0109 CD21 INT 21
- *c^
- Observa la parte alta de AX que ha pasado
- a valer 09h. Por si todavia no tenias
- claro eso de la parte alta y la baja mira
- el valor que tenia AX antes (AX=109F)
- y mira el que tiene ahora (AX=099F) lo que
- ha cambiado es la parte de mayor peso del
- registro. Si hubiesemos actuado sobre AL en
- lugar de AH, el 9Fh de AX hubiese pasado a
- 09h.
- *cR
- Hola mundo!!*cA
- AX=0924BX=0000CX=001DDX=0110SP=FFFE
- -->BP=0000SI=0000DI=0000
- DS=109FES=109FSS=109FCS=109FIP=010B
- -->NV UP EI PL NZ NA PO NC
- 109F:010B B8004C MOV AX,4C00
- *c^
- En este paso se ejecuta la interrupción y
- por tanto se muestra el mensaje en pantalla.
- Como se decia en la lista de Ralf Brown, AL
- tiene ahora el valor 24h y los demás regis-
- tros permanecen inalterados (a excepción de
- IP, claro!!).
- *cA
- AX=4C00BX=0000CX=001DDX=0110SP=FFFE
- -->BP=0000SI=0000DI=0000
- DS=109FES=109FSS=109FCS=109FIP=010E
- -->NV UP EI PL NZ NA PO NC
- 109F:010E CD21 INT 21
- *c^
- Vemos como AX ha adquirido el valor 4C00h
- para llamar a la interrupción 21h. Este sub-
- servicio es el que nos permite regresar al
- prompt del DOS pasandole en AH el valor 4Ch
- (que indica el número de subservicio) y en
- AL el llamado *cferrorlevel*c^ que devuelve el
- programa (en este caso 00h). Si volvemos a
- teclear el comando 'p' saldremos al DOS ya
- que se ejecutará la interrución (como podemos
- ver en el campo "siguiente instrucción").
- Tal vez, si escribes *cvu 100*c^ para ver el
- programa que has hecho, te sorprenda ver que
- la cadena *cvhola mundo!!$*c^ no aparece por nin-
- gún sítio. Ello es porque cuando le dices al
- debug que desensamble un trozo de código,
- interpreta que ese trozo es de intrucciones
- y por ello trata de dar un significado a la
- ristra de bytes que componen la cadena. Para
- ver las cadenas que definamos en nuestro
- programa, deberemos escribir la instrucción
- *cvd 100*c^ que significa "dump" (volcar) y que
- hace un caracteristico listado hexadecimal.
- Si todavia no te has dado cuenta de que
- significado tiene ese 100 que ponemos detrás
- de las instrucciones *c d*c^ y *c u*c^, deberias de
- haberte dado cuenta de que se trata de la
- dirección (sólo offset, se supone que el seg-
- mento es CS) donde el debug debe empezar a
- volcar o desensamblar. Opcionalmente tambien
- puedes poner detrás otro offset para decirle
- cuando debe acabar, aunque si no lo haces no
- pasa nada ya que entiende que quieres un
- trozito.
- La instrucción *c w*c^ (write) sirve para alma-
- cenar en disco el programa (recuerda que ya
- la has usado para salvar el programa) desde
- la posición CS:0100h hasta el offset dentro
- de CS almacenado en CX más 100h. En realidad
- en CX lo que debes guardar es la longitud del
- programa (en el "hola mundo" era 1Dh porque
- despues de introducir la última instrucción
- [la del mensaje] apareció como siguiente
- dirección para ensamblar la XXXX:01D1h;
- vuelve a reescribir el programa para obser-
- varlo). Para poner un valor en un registro,
- debemos usar la instrucción *c r*c^ que usado sin
- parámetros devuelve el valor de los registros
- y con un registro como parámetro permite su
- modificación (*c rcx*c^ en este caso).
- Otra instrucción interesante es *c g*c^ (go)
- que permitirá que un programa que estamos
- trazando con *c t*c^ o *c p*c^ pueda ser ejecutado
- hasta su finalización. Si entramos al pro-
- grama sin especificar un nombre para el ar-
- chivo que queremos almacenar en disco o que-
- remos poner otro usaremos la intrucción *c n*c^
- pasandole como parámetro el nombre del fi-
- chero de salida con extensión COM (no se pue-
- den hacer EXEs con el debug).
- *cR
- Instrucciones aritméticas
- *c^
- Las instrucciones aritméticas son las que
- permiten operar con los registros y hacer
- sencillos cálculo en complemento a dos (ver
- anteriores artículos). Podemos sumar, restar,
- multiplicar y dividir directamente y podemos
- realizar operaciones más complicadas a base
- de estas más simples. Los prototipos de las
- instrucciones son estos:
- *cH
- ADD <destino>, <origen>
- SUB <destino>, <origen>
- MUL <multipl>
- IMUL <multipl>
- DIV <divisor>
- IDIV <divisor>
- *c^
- Lo primero que se observa es que hay 2
- instrucciones para multiplicar y 2 más para
- dividir. Las instrucciones MUL y DIV consi-
- deran números sin signo, mientras IMUL e IDIV
- los consideran con signo. Para sumar 2 regis-
- tros lo que hacemos es poner el destino de-
- lante y lo que le sumaremos detrás. Es equi-
- valente a la instrucción de C "+=". Veamos
- un par de ejemplos:
- *cH
- MOV AX, 25*cO
- ; AX pasa a valer 25*cH
- MOV BX, 35*cO
- ; BX pasa a valer 35*cH
- ADD AX, BX*cO
- ; BX se mantiene y AX
- ; valdrá 25+35=60*cH
-
- MOV AX, 100*cO
- ; AX = 100*cH
- MOV BX, 50*cO
- ; BX = 50*c├
- ·····
- *cO ; Queremos que AX y BX
- ; no cambien, usamos*cH
- MOV CX, AX*cO
- ; otro registro para
- ; almacenar el resultado.*cH
- ADD CX, BX*cO
- ; CX = 150, AX = 100,
- ; BX = 50*c^
-
- Tambien podemos operar con memoria, pero
- recordando siempre que el 80x86 no nos per-
- mite operaciones de memoria a memoria (es
- incorrecto MOV [v1], [v2]). Para la resta
- lo mismo, se restará el "origen" al "des-
- tino", es decir, como si hiciesemos en un
- HLL "destino=destino-origen". Algunos
- ejemplos:
- *cH
- MOV AX, 100 *cO ; AX vale 100
- *cH SUB AX, 10 *cO ; AX valdrá 90
- *cH MOV BX, 90 *cO ; BX = 90
- *cH SUB AX, BX *cO ; AX se hace 0
-
- *cH MOV AX, 25 *cO ; AX = 25
- *cH MOV BX, 15 *cO ; BX = 15
- *c├ ····· *cO ; Supongamos que
- ; queremos guardar en memoria
- *cH MOV DS:[130h], AX*cO ; AX - BX
- *cH SUB DS:[130h], BX*cO ; En memoria 10
- *c^
- Despues de ver este último ejemplo tengo
- que aclarar un par de cosas. Lo primero,
- cuando no escriba una *c h*c^ o una *c o*c^ al final
- del número, estaré escribiendo los números
- en decimal (a no ser que el código este dise-
- ñado explícitamente para ser usado en el
- debug). Lo segundo, que cuando queramos
- almacenar en memoria un valor, deberemos
- haber definido una zona para el almacena-
- miento de memoria (con las instrucciones
- DB, DW o DD que hemos visto superficial-
- mente) y luego recordar la dirección donde
- están definidas para acceder a ellas escri-
- biendo su dirección entre corchetes. Este
- sistema tan arcaico es sólo necesario con
- el debug, ya que todos los ensambladores
- modernos incorporan etiquetas (en el pró-
- ximo número). Por ejemplo, tomemos del debug
- un trozo de código que haga uso de esta
- caracteristica:
-
- *cH10BB:0100 8CC8 MOV AX,CS
- *cO ; Primero metemos el segmento
- *cH10BB:0102 8ED8 MOV DS,AX
- *cO ; correcto.
- *cH10BB:0104 B85000 MOV AX,0050
- *cH10BB:0107 BB3000 MOV BX,0030
- *cO ; Los datos a restar.
- *cH10BB:010A A31601 MOV [0116],AX
- *cO ; Escribimos a memoria.
- *cH10BB:010D 291E1601 SUB [0116],BX
- *cO ; Restamos de memoria.
- *cH10BB:0111 B8004C MOV AX,4C00
- *cO ; Función de salir al DOS
- *cH10BB:0114 CD21 INT 21
- *cO ; Hasta luego lucas!
- *cH10BB:0116 0000 DW 0
- *cO ; Aquí es donde definimos la WORD que
- ; almacenará los numeritos.
- *c^
- Las instrucciones multiplicativas tienen un
- aspecto más complicado, sólo tienen 1 pará-
- metro. Para hacer una multiplicación se coge
- el acumulador y se opera con el registro o
- posición de memoria que le pasemos como pa-
- rámetro. Pero, ¿que es eso del acumulador?
- Pues depende, puede ser AL o AX. Como sabrás
- (si prestaste atención en los anteriores
- números) cuando multiplicamos dos números
- de n-bits, la mayor de las cifrás que ten-
- dremos será de 2n-bits. Así, pues, se estan-
- dariza la operación de multiplicación y si
- se quiere multiplicar 2 números deberán te-
- ner los mismos bits (8 o 16) y el resultado
- se almacenará en un registro de 2n-bits. En
- definitiva, si queremos multiplicar un nú-
- mero de 8-bits el acumulador será AL y si
- es de 16 será AX. Para almacenar el resul-
- tado de los de 8-bits usaremos AX y para
- los de 16 usaremos el par DX-AX donde DX
- serán los 16-bits de mayor peso y AX los
- 16 de menor. Ejemplos:
-
- *cH MOV AX, 10 *cO ; AX = 10
- *cH MOV BX, 50 *cO ; BX = 50
- *cH MUL BX *cO ; DX-AX = AX x BX,
- ; y como 500 cabe en
- ; 16 bits
- ; AX valdrá 500 y DX
- ; será 0.
-
- *cH MOV AL, 120 *cO ; AL = 120
- *cH MOV CL, 40 *cO ; CL = 40
- *cH MUL CL *cO ; AX = AL x CL =
- ; 120 x 40 = 4800
- *c^
- La división es lo contrario de la multipli-
- cación, cuando uso el divisor de 8-bits, el
- acumulador es de 16 y cuando lo uso de
- 16-bits, el acumulador será el de 32 (DX-AX).
- Vamos directamente con un ejemplo:
-
- *cH MOV CL, 100 *cO ; CL = 100
- *cH MOV BL, 10 *cO ; BL = 10.
- ; Queremos dividir CL/BL:
- *cH MOV AL, CL *cO ; Tenemos un
- ; problema, AH puede contener un
- *cH MOV AH, 0 *cO ; valor distinto de
- ; 0, pues lo "borramos".
- *cH DIV BL *cO ; AL = 100 / 10 = 10
- *c^
- El cociente de esta operación de división
- se almacena en AL y el resto lo hace en AH.
- Como el acumulador para divisores de 8-bits
- es de 16, hemos copiado a AX el dividendo,
- haciendo 0 la parte de arriba (más adelante
- veremos como hacer esto en una sóla instruc-
- ción). Si usasemos un registro de 16-bits
- tendriamos que hacer DX=0.
-
- Creo que ya ha habido bastante por hoy,
- ¿no? En el próximo número veremos las ins-
- trucciones lógicas, los saltos, comparacio-
- nes y si hay tiempo las entradas y salidas,
- además de un especial interrupciones. Os
- dejo unos deberes para casa: determinad que
- valores contendrán los registros de uso ge-
- neral (AX, BX, CX y DX) al terminar el pro-
- grama o decid si no es posible ensamblarlos
- por contener algún error (se deben hacer sin
- usar el PC):
- *cH
- 1) MOV AX, 100
- MOV BX, 200
- ADD AX, BX
- MUL BX
-
- 2) MOV AL, 500
- MOV BL, 100
- SUB AL, BL
- MUL 10
-
- 3) MOV AX, 30
- MOV BX, 10
- MUL BX
- DIV BX
- ADD AL, BX
-
- *cG Navi Dj.
-