Está en la página 1de 9

xComputerLab 3: subrutinas

UNA SUBRUTINA ES UN CONJUNTO DE INSTRUCCIONES para realizar alguna tarea,


fragmentada y pensada como una unidad. Al igual que los bucles y las decisiones, las subrutinas
son tiles en la construccin de programas complejos. El lenguaje de mquina para xComputer no
proporciona soporte directo para subrutinas. Pero, de nuevo, en realidad no proporciona soporte
directo para bucles y decisiones, que deben ser implementadas por el programador con
instrucciones de salto y salto condicional. De forma similar, es posible implementar subrutinas
usando instrucciones de salto. No son tan fciles, legibles o seguras como las subrutinas en un
lenguaje de alto nivel, pero an pueden ser una herramienta til. Adems, al trabajar con
subrutinas en xComputer, podr ver algunos de los detalles de cmo las subrutinas se pueden
implementar en un nivel muy bajo. (Debe comprender, sin embargo, que los lenguajes de mquina
de las computadoras reales ofrecen ms soporte para las subrutinas de lo que se trata aqu).

Antes de realizar esta prctica de laboratorio, debe estar muy familiarizado con el applet
xComputer y con la programacin en lenguaje ensamblador para xComputer, tal como se describe
en xComputer Lab 1 y xComputer Lab 2. El material de este laboratorio no est cubierto en The
Most Complex Machine.

Este laboratorio incluye las siguientes secciones:

1. Ida y Retorno
2. Parmetros y nombres locales
3. Pasando punteros
4. Verificacin de realidad
5. Ejercicios (talleres).
1. Ida y Retorno

La idea de las subrutinas es bastante simple. Una subrutina es solo una secuencia de
instrucciones que realiza una tarea especfica. Cuando un programa necesita realizar esa tarea,
puede llamar a la subrutina para hacerlo. La subrutina solo debe escribirse una vez, y una vez
escrita, puede olvidarse de los detalles de cmo funciona. Si la misma tarea necesita realizarse en
otro programa, simplemente se puede copiar de un programa a otro usando cortar y pegar. Por lo
tanto, el trabajo realizado al escribir la subrutina no tiene que repetirse una y otra vez. La subrutina
se puede reutilizar. De hecho, las computadoras reales tienen grandes bibliotecas de subrutinas
que estn disponibles para su uso por los programas. Los programas complejos que se usan en
las computadoras modernas seran extremadamente difciles de escribir, si estas bibliotecas de
subrutinas pre-escritas no estuvieran disponibles.

En el lenguaje ensamblador de xComputer, "llamar" a una subrutina significa saltar a la primera


instruccin en la subrutina, usando una instruccin JMP. La ejecucin de la subrutina finalizar con
un salto al mismo punto en el programa desde el que se llam a la subrutina, para que el programa
pueda continuar donde lo dej antes de llamar a la subrutina. Esto se conoce como regresar de la
subrutina. (Otras computadoras proporcionan comandos especiales para llamar y regresar de
subrutinas).

Aunque hay ms que unas pocas instrucciones de salto. Por un lado, si la subrutina debe ser
reutilizable en un sentido significativo, debe ser posible llamar a la subrutina desde diferentes
lugares en un programa. Si este es el caso, cmo sabe la computadora a qu punto del programa
volver cuando termina la subrutina? La respuesta es que el punto de retorno debe registrarse en
algn lugar antes de llamar a la subrutina. La direccin en la que se supone que debe regresar el
equipo una vez que finaliza la subrutina se denomina direccin de retorno. Antes de saltar al inicio
de la subrutina, el programa debe almacenar la direccin de retorno en un lugar donde la subrutina
pueda encontrarla. Cuando la subrutina ha terminado de realizar su tarea asignada, finaliza con un
salto de regreso a la direccin de retorno. Si, por ejemplo, la direccin de devolucin se ha
almacenado en una ubicacin de memoria con la etiqueta "RetAddr", la subrutina puede finalizar
con la instruccin:

JMP-I RetAddr

En el lenguaje de xComputer, JMP-I es una instruccin de salto indirecto, que utiliza


direccionamiento indirecto. Le dice a la computadora que salte a la ubicacin cuya direccin est
almacenada en RetAddr. En este caso, esa ser la direccin de retorno para la subrutina.
Todas las subrutinas con las que trabajar en esta prctica de laboratorio usan direcciones de
retorno de la misma manera. Una ubicacin de memoria en la subrutina est reservada para
contener la direccin de retorno. Antes de saltar al principio de la subrutina, el programa guardar
la direccin apropiada en esa ubicacin de memoria. La subrutina termina con una instruccin de
salto indirecto a la direccin de retorno.

Como primer ejemplo, mire el programa de ejemplo "MultiplyBySeven.txt" Este programa usa una
subrutina muy simple cuya tarea es multiplicar un nmero por siete. La subrutina, que se denomina
Times7, se encuentra al final del programa. Comienza con las lneas:

RetAddr: datos; La direccin de devolucin para la subrutina debe


; ser almacenado en esta ubicacin antes de la
; llamada a la subrutina.

Times7: STO num_t; PUNTO DE PARTIDA DE SUBROUTINE.

La primera lnea reserva una ubicacin de memoria para contener la direccin de retorno. El
"programa principal", que usa la subrutina, almacena la direccin de retorno en esta ubicacin de
memoria. Luego salta a la ubicacin "Times7", que es donde comienzan las instrucciones para la
subrutina. La ltima instruccin en la subrutina es "JMP-I RetAddr" que devuelve el control al
programa principal.

La direccin de devolucin no es el nico elemento de informacin que el programa debe enviar a


la subrutina. La tarea de la subrutina es multiplicar un nmero por siete. El programa principal tiene
que indicarle a la subrutina qu nmero multiplicar por siete. Se dice que esta informacin es un
parmetro de la subrutina. De manera similar, la subrutina debe obtener su respuesta, el resultado
de multiplicar el valor del parmetro por siete, de vuelta al programa principal. Esta respuesta se
llama el valor de retorno de la subrutina. En "MultiplyBySeven.txt", el programa coloca el valor del
parmetro en el acumulador antes de llamar a la subrutina. La subrutina sabe buscarlo all. Antes
de volver al programa principal, la subrutina pone su valor de retorno en el acumulador. El
programa principal sabe buscarlo all. Pasar valores de parmetros y devolver valores en un
registro, como el acumulador, es un mtodo de comunicacin muy simple y eficiente entre una
subrutina y el resto de un programa. En la siguiente seccin, veremos otros mtodos de
comunicacin.

Deberas leer el programa de ejemplo "MultiplyBySeven.txt" y asegurarte de que entiendes:


Carguelo en la memoria con el botn "Traducir" y ejectelo. Es posible que desee ejecutarlo a
mano con el botn "Ciclo" para que pueda seguir en detalle cmo funciona. Modifique el programa
para que calcule 103 * 7 en lugar de 34 * 7. (Habra pensado multiplicar un nmero por siete
usando el mtodo en esta subrutina? Por supuesto, un punto importante acerca de las subrutinas
es que cuando est usando una subrutina que otra persona ha escrito para usted, realmente no le
importa tanto cmo realiza su tarea, siempre que lo haga correctamente. Usas la subrutina como
"caja negra").

2. Parmetros y nombres locales

No siempre es posible pasar valores de parmetros en los registros. En xComputer, por ejemplo,
solo hay un registro (el acumulador) que se puede usar para el paso de parmetros. Pero algunas
subrutinas requieren dos o ms parmetros. La solucin es usar ubicaciones de memoria
reservadas para los valores de parmetros, tal como se hace para la direccin de retorno de la
subrutina. De forma similar, un valor de retorno de una subrutina se puede colocar en una
ubicacin de memoria reservada en lugar de en un registro. Este mtodo es un poco ms difcil
que usar registros, pero tambin es ms flexible.

Mire el programa de ejemplo "MultiplyTwoNumbers.txt". Este programa de ejemplo incluye una


subrutina que puede multiplicar dos nmeros. Los nmeros que se multiplicarn son parmetros de
la subrutina, y el producto de los dos nmeros es su valor de retorno. Las ubicaciones de memoria
etiquetadas como N1, N2 y Respuesta se usan para mantener los dos valores de parmetro y el
valor de retorno. Estas ubicaciones se pueden encontrar al principio de la subrutina, junto con una
ubicacin de memoria para guardar la direccin de retorno. Antes de llamar a la subrutina, el
programa principal debe cargar los dos nmeros que quiere multiplicar en N1 y N2. Cuando
termina la subrutina, el programa principal puede obtener la respuesta cargando el contenido de la
ubicacin de la memoria. Respuesta Debe leer el programa, probarlo y asegurarse de comprender
todo esto. El programa contiene una lista de instrucciones detalladas para usar la subrutina.
(Tenga en cuenta que no tiene que entender el mtodo que utiliza la subrutina para multiplicar los
nmeros. De hecho, es un procedimiento bastante complejo).

Por cierto, cuando lea la subrutina "Multiplicar", notar que usa nueve ubicaciones diferentes de
memoria etiquetada. Cinco de estos, ret_addr, N1, N2, Answer y Multiply, se usan para
comunicarse con el programa principal. Los otros cuatro son parte del funcionamiento interno de la
subrutina. Idealmente, el programa principal no debera conocerlos en absoluto, porque el
programa principal solo est interesado en la tarea realizada por la subrutina, no en su
funcionamiento interno. Estas etiquetas se llaman nombres locales, ya que estn destinadas a ser
utilizadas solo "localmente" dentro de la subrutina. Desafortunadamente, en el lenguaje
ensamblador simple de xComputer, no es posible "ocultar" estos nombres del programa principal, y
debe tener cuidado de no usar el mismo nombre para un propsito diferente en el programa
principal. En mis subrutinas de muestra, he tratado de usar nombres locales que probablemente no
ocurran en ningn otro lugar del programa, como loop_m y done_m. En los lenguajes de
programacin reales, los nombres locales son realmente invisibles para el resto del programa, por
lo que no hay posibilidad de conflicto.

3. Pasando punteros

El programa de ejemplo final, "ListSumSubroutine.txt", ilustra un aspecto ms del paso de


parmetros. La subrutina en este ejemplo pretende sumar una lista completa de nmeros. No hay
lmite en la cantidad de elementos en la lista. Cmo es posible pasar un nmero de parmetros
potencialmente ilimitados a la subrutina?

La solucin es que los nmeros en la lista no se pasan a la subrutina en absoluto! En cambio, el


programa principal le dice a la subrutina dnde se encuentra la memoria para buscar la lista. Solo
hay un parmetro: la direccin de la ubicacin de inicio de la lista. Se dice que esta direccin es un
puntero a la lista.

En el ejemplo "ListSumSubroutine.txt", el programa principal almacena un puntero a la lista en la


ubicacin de la memoria con la etiqueta "ListStart". A continuacin, la subrutina accede a los
nmeros en la lista mediante el direccionamiento indirecto (en una instruccin LOD-I). Este es un
buen ejemplo que demuestra una vez ms la utilidad de los punteros y el direccionamiento
indirecto.

4. Verificacin de realidad

De hecho, es una locura intentar escribir subrutinas para xComputer. La variedad limitada de
instrucciones de lenguaje de mquina para xComputer hace que sea muy difcil expresar la idea de
una subrutina en ese idioma. No es de extraar que las computadoras reales tengan instrucciones
de lenguaje de mquina de propsito especial para trabajar con subrutinas.

Lo primero que necesita un lenguaje de mquina es un par de instrucciones para llamar a una
subrutina y regresar desde una subrutina. Estas instrucciones se pueden llamar jump-to-subroutine
y return-from-subroutine. La instruccin de salto a subrutina automticamente guardar una
direccin de retorno y luego saltar al punto de inicio de la subrutina. La computadora podra
averiguar la direccin de retorno por s misma, en lugar de dejarla en manos del programador, al
observar el valor en el registro del contador de programas. (El contador de programa contiene la
direccin de la siguiente instruccin despus de la que se est ejecutando actualmente, y ese es
exactamente el punto al que debe volver la subrutina). La instruccin de retorno de la subrutina
obtendra la direccin de retorno que se guard previamente. por saltar a la subrutina y saltar de
regreso a esa direccin. Estas dos instrucciones haran innecesario que un programador siquiera
piense en las direcciones de devolucin.

Las computadoras reales tambin tienen una forma ms sistemtica de manejar los parmetros.
Un rea de memoria llamada pila se usa para contener los parmetros de todas las subrutinas. De
hecho, la pila tambin contiene direcciones de devolucin y valores de datos utilizados
internamente por subrutinas. La pila es solo una lista de valores. Cuando se llama a una subrutina,
los parmetros y la direccin de retorno para la subrutina se agregan al final de la lista. Cuando
termina la subrutina, la direccin de retorno y los parmetros se eliminan de la pila. La instruccin
de salto a subrutina almacena la direccin de retorno en la pila y la devolucin desde la subrutina
la elimina de la pila cuando llega el momento de finalizar la subrutina. Por lo general, una
computadora tiene un registro llamado Stack Pointer para realizar un seguimiento de cun grande
es actualmente la pila. Y el lenguaje de mquina normalmente incluye instrucciones llamadas push
y pop para agregar elementos de la pila y eliminar elementos del final de la pila.

Cuando una subrutina llama a otra, todos los datos de la segunda subrutina simplemente se
agregan a la pila, en "la parte superior" de los datos que ya estn all. Cuando la segunda subrutina
finaliza, sus datos se eliminan de la pila, pero los datos para la primera subrutina todava estn all,
de modo que la primera subrutina simplemente puede continuar donde la dej. Todo el sistema es
realmente bastante elegante.

Quizs no sea tan loco escribir algunas subrutinas para xComputer despus de todo, ya que hacer
todo a mano puede ayudarlo a comprender lo que realmente sucede cuando se llama a una
subrutina. Y tambin puede ayudarlo a apreciar la elegancia de las computadoras ms sofisticadas
y los lenguajes de programacin.
5. Ejercicios

Ejercicio 1: El programa principal en el programa de ejemplo "MultiplyTwoNumbers.txt" es el


siguiente:
lod-c 13 ; Set up to call the subroutine with
sto N1 ; N1 = 13, N2 = 56, and ret_addr = back.
lod-c 56
sto N2
lod-c back
sto ret_addr
jmp Multiply ; Call the subroutine.

back: lod Answer ; When the subroutine ends, it returns


; control to this location, and the
; product of N1 and N2 is in Answer.
; This LOD instruction puts the answer
; in the accumulator.

hlt ; Terminate the program by halting the computer.

Explica cuidadosamente cada instruccin en este programa. Explique exactamente lo que cada
una de las primeras 8 instrucciones tiene que ver con llamar a la subrutina.

Ejercicio 2: escriba un programa principal que use la subrutina Multiplicar en


"MultiplyTwoNumbers.txt" para calcular el producto 5 * 23 * 17. No modifique la subrutina. El
programa principal debe llamar a la subrutina dos veces.

Ejercicio 3: escriba una subrutina para agregar tres nmeros. (Esto es bastante tonto, pero el
objetivo es demostrar que comprende los conceptos bsicos involucrados). Su subrutina debe
tener tres parmetros y un valor de retorno (los tres nmeros que se sumarn y su suma). Escriba
un programa principal que use su subrutina para agregar 17, 42 y 105. Su programa ser muy
similar al programa de ejemplo "MultiplyTwoNumbers.txt". Asegrate de incluir comentarios en tu
programa!
Ejercicio 4: Lea la seccin Comprobacin de realidad arriba. Por qu no puede expresar las
operaciones de salto a subrutina y regreso de subrutina en el lenguaje de xComputer? Qu
necesitan hacer estas instrucciones que no se pueden expresar en ese idioma? Qu tipo de
modificaciones tendran que hacerse a xComputer para agregarlas al lenguaje de mquina de
xComputer?

Ejercicio 5: el programa de ejemplo "ListSumSubroutine.txt" utiliza una subrutina para agregar una
lista de nmeros. Supongamos que le gustara multiplicar los nmeros en su lugar. Para ello, copie
la subrutina de multiplicacin del programa de ejemplo "MultiplyTwoNumbers.txt" y pguelo al final
de "ListSumSubroutine.txt". Modifique la subrutina ListSum para que en lugar de agregar dos
nmeros, utilice la subrutina Multiplicar para multiplicar. Debe reemplazar la instruccin "agregar
suma" con varias instrucciones que configuran una llamada a la subrutina Multiplicar. Y deber
crear una etiqueta de direccin de devolucin para que la subrutina regrese a. Una vez que haya
realizado esta modificacin, el programa calcular el producto 1 * 2 * 3 * 4 * 5 * 6 * 7 en lugar de la
suma 1 + 2 + 3 + 4 + 5 + 6 + 7. (Es posible que desee cambiar el nombre de la subrutina de
ListSum a ListMul, y cambie el nombre de la ubicacin de la memoria Sum por Product. Esto
requerir que tambin cambie los nombres en el programa principal).

Ejercicio 6: el archivo de muestra "PrimesAndRemainders.txt" define dos subrutinas. Una de las


subrutinas puede usarse para encontrar el resto cuando un entero se divide en otro. La otra
subrutina se puede usar para determinar si un nmero es primo. El archivo no contiene un
programa principal. Si desea utilizar una o ambas subrutinas, puede agregar un programa principal
al principio del archivo.

Debera leer los comentarios en las dos subrutinas para descubrir cmo usarlos. Luego escribe dos
programas que usan las subrutinas. El primer programa debe usar la subrutina "Remanente" para
calcular el resto cuando 609 se divide por 81. El segundo programa debe usar la subrutina
"PrimeTest" para determinar si 51 es primo o no. Tenga en cuenta que no tiene que entender cmo
funcionan las subrutinas. Solo necesita saber cmo llamarlos y pasarles los parmetros
adecuados.

Ejercicio 7: Este ejercicio, como el anterior, implica escribir un programa principal para el ejemplo
"PrimesAndRemainders.txt". Sin embargo, este ejercicio es mucho ms desafiante. Escribe un
programa principal que haga una lista de nmeros primos. El programa debe usar la subrutina
"PrimeTest" para probar si cada uno de los nmeros 2, 3, 4, 5, 6, etc., es primo. Cada nmero que
se encuentre como principal debe agregarse a una lista. Puedes escribir un programa que se
ejecuta en un ciclo infinito.
Use una ubicacin llamada "p" para almacenar el nmero que est verificando. Comience
almacenando un 2 en p. En un bucle, debe llamar a PrimeTest para ver si p es primo. Si p es
primordial, agrguelo a la lista. En cualquier caso, debe agregar 1 a py saltar al inicio del ciclo para
probar el siguiente valor de p.

Hacer una lista de nmeros primos significa almacenar nmeros primos en ubicaciones de
memoria consecutivas. Use una ubicacin llamada "lista" para sealar el final de la lista. Es decir,
el valor de la lista es la ubicacin donde desea almacenar el siguiente primo que encuentre.
Digamos que desea que la lista de nmeros primos comience en la ubicacin 50. Al comienzo del
programa, debe almacenar una lista de 50 en la lista. Cuando encuentre un nmero primo, puede
agregarlo al final de la lista con un comando de lista STO-I. Luego debe agregar 1 al valor de la
lista para prepararse para el prximo nmero.

Si ejecuta su programa a alta velocidad, puede verlo almacenar los nmeros 2, 3, 5, 7, 11, 13, y as
sucesivamente en la memoria. Es posible que desee ver el programa en modo de grficos para
que pueda ver la actividad en el programa principal y en las dos subrutinas.

Ejercicio 8: escriba un breve ensayo sobre cmo las subrutinas pueden facilitar el diseo y la
escritura de programas complejos. (Su respuesta debe mostrar que comprende que pueden hacer
ms que ahorrarle mecanografa!) En su ensayo, use parte del trabajo que hizo en esta prctica de
laboratorio para ver ejemplos.

También podría gustarte