PRÁCTICAS DE COMPUTADORES II

SÉPTIMA SESIÓN


  1. Registros índices

    Continuando con la serie de sesiones que van a desvelar el propósito de cada registro del 6809, le ha llegado el turno a los registros X e Y. Aunque el programador puede usar estos registros como le convenga, su destino inicial es servir como índices, apuntadores o, incluso, siguiendo la nomenclatura de C, como punteros de memoria. Contendrán, pues, una dirección de memoria y otros registros u operaciones de memoria los utilizarán como apoyo para acceder al contenido de la dirección de memoria a la que apuntan:

    Cargamos A con lo apuntado por X

    Hay bastantes variaciones sobre este mismo tema. La primera de ellas es que se puede indicar un desplazamiento sobre la dirección base apuntada por el registro índice. Este desplazamiento puede incluso ser negativo:

    Cargamos A con lo apuntado por X-2

    El desplazamiento puede estar indicado por A, B o D, como en el siguiente ejemplo (recordad que 0xFF es -1 en complemento a 2):

    Cargamos A con lo apuntado por X+B

    Podemos hacer que el registro índice se autoincremente después de haber hecho la carga en una (+) o dos unidades (++):

    Cargamos A con lo apuntado por X e incrementamos

    Podemos, incluso, hacer que el registro índice se autodecremente antes de haber hecho la carga en una (-) o dos unidades (--):

    Cargamos A con lo apuntado por X e incrementamos


    Después de poder hacer tantas cosas, algunas que no es posible hacer:

    Aunque en todos los ejemplos hemos usado la orden LDA, podemos apoyarnos en un registro índice con cualquiera de las otras que hemos visto que acceden a la memoria. Por lo tanto son instrucciones válidas: STD ,Y++; ROL 3,X; CMPU D,X; etc.

    Con esto que ya sabemos, la parte sustancial del misterioso "Hola, mundo" ha quedado desvelada:

            [...]
    cadena: .ascii "Hola, mundo."
            .byte   10      ; 10 es CTRL-J: salto de lInea
            .byte   0       ; 0 es CTRL-@: fin de cadena
    
            .globl programa
    programa:
            ldx #cadena
    bucle:  lda ,x+
            beq acabar
            sta 0xFF00      ; salida por pantalla
            bra bucle
    acabar: clra
            [...]
    

    Para imprimir la cadena, nos apoyamos en el registro índice X que va señalando, uno tras otro, todos los caracteres para que se carguen en A y se impriman o, en el caso de ser el carácter '\0, acabe el programa.

  2. Ejercicio

    Realizad un programa que admita una línea de texto del teclado. Debe sacar por la pantalla los caracteres que aparecen en la línea ordenados de código ASCII menor a mayor. Si algún carácter aparece repetido en la entrada, debe aparecer solamente una vez en la salida. Por ejemplo, si la entrada es: El perro de San Roque no tiene rabo, la salida debe ser ERSabdeilnopqrtu

    Pista: usad un algoritmo sencillo, aunque no sea muy eficiente. Por ejemplo, recorred el array en busca del elemento menor. Una vez encontrado, volved a recorrerlo y marcad todas los caracteres donde aparezca el menor para no contarlos en el futuro. Los podéis marcar activando el bit más significativo, por ejemplo. Cuando estén todos marcados, habréis acabado.

  3. Chaqueterismo

    En el mundo de nuestro procesador, los registros pueden cambiar de bando según convenga. Ya, para empezar, cualquiera de los registros de pila, U o S, puede actuar como registro índice. Son válidas, pues, instrucciones como LDA ,S; STB D,U; etc.

    Una aplicación directa de esto, bastante usada, es que la pila contenga variables temporales. Hasta ahora, si necesitábamos una variable temporal, la declarábamos al principio. Esto no es bueno, por dos razones:
    1. la variable temporal seguía ocupando memoria después de no ser ya necesitada
    2. introducimos en nuestro programa una dependencia respecto a la dirección de memoria donde se colocaba la variable temporal

    El siguiente ejemplo muestra cómo, a falta de registros, se puede usar una variable temporal en la pila U para hacer un bucle de 23 iteraciones:

            ldu #0xF000 ; cargamos U con un valor seguro al principio...
            [...]
            pshu a      ; PILA [A]
            pshu a      ; PILA [A A]
            lda #23
            sta 1,u     ; PILA [A 23]
            pulu a      ; PILA [23] y recuperamos el valor de A
    bucle:  [...]       ; aquI las instrucciones del bucle
            dec ,u
            bne bucle
                        ; PILA [0]
            tst ,u+     ; truco para sacar la variable de la pila sin alterar los
                        ; registros.  Veremos cOmo hacerlo mejor en el futuro
                        ; PILA []
    

    Preocupados X e Y por el intrusismo laboral de U y S deciden contraatacar. Y es que X e Y pueden usarse también para construir de un modo muy fácil una pila. No existen las instrucciones PSHX y PULX, pero no importa porque se pueden simular fácilmente. Por ejemplo:

    Con UCon X
    PSHU A   STA ,-X
    PSHU D   STD ,--X
    PULU D   LDD ,X++
    PULU A   LDA ,X+
    PSHU A,B,Y   STY ,--X; STD ,--X
    PULU A,B,Y   LDD ,X++; LDY ,X++

    Bien es verdad que no es tan fácil meter o sacar CC o DP de una pila construida con X, pero tampoco se usa tanto.

    Los ingenieros de Motorola que diseñaron el 6809 hicieron que la operación de decremento fuera previa y la de incremento posterior cuando se usan índices precisamente para que pudieran ser usados como pilas.

  4. Ejercicio

    Con ayuda de X, Y, U y S funcionando como pilas, vamos a solucionar el problema de las Torres de Hanoi. Se trata de un famoso puzzle matemático muy sencillo de entender. Se parte de una torre formada por discos situada a la izquierda. Se trata de moverla al completo dos posiciones a la derecha, respetando las siguientes reglas:
    1. Solamente se puede mover un disco cada vez
    2. Se pueden usar tres posiciones únicamente, la inicial y la final y una en el medio
    3. En ningún momento se puede poner un disco mayor sobre uno menor

    Aquí tenéis una solución para cuando se parte de cuatro discos (esperad a que la animación pase por el momento en que está la torre al completo a la izquierda):

    Torre de Hanoi con cuatro discos

    Cada una de las tres torres vendrá representada por una pila construida con los registros X, Y y U. Al principio, meteremos en la pila X, la configuración inicial. Por ejemplo, para cinco discos:

    [12345]X      []Y      []U
    

    Si, por ejemplo, hay que mover un disco de la primera a la tercera torre, haremos una instrucción PULL de la pila X y una instrucción PUSH en la pila U.

     [2345]X      []Y     [1]U
    

    La pila S la usaremos para resolver el algoritmo, del modo siguiente:

    1. Cada elemento que metamos en S representará un movimiento que queremos hacer, bien sea simple y directamente posible por implicar a un solo disco, bien implique mover de golpe una pila de ellos. El movimiento vendrá codificado en un byte con el siguiente formato:

      Órdenes para las torres de Hanoi

      Por ejemplo, si queremos mover los tres discos de arriba de la torre U a la torre Y, el byte sería 000110112
    2. Al principio, metemos en S la operación que soluciona el problema: en el caso de cinco discos consiste en llevar cinco discos de la torre X a la U (representado, según la codificación anterior, por 001010002).
    3. El algoritmo en sí se repite hasta que no queden elementos en la pila S:
      1. Sacar el primer elemento de la pila S (PULL)
      2. Si la operación contiene un único disco, se mueve entre las pilas que corresponda según el código del elemento y se imprime la nueva configuración de las torres
      3. Si la operación contiene más de un disco (p. ej., n discos), se meten las tres operaciones siguientes en la pila, en este orden:
        1. n-1 discos con la operación complementaria (si era, 011, se pone 100)
        2. 1 disco con la operación original
        3. n-1 discos con la operación original con un bit cambiado dependiendo de cuál es el origen de la operación. Si el origen es X, se voltea el primer bit; si es Y, el segundo y si es U, el tercero. Por ejemplo, si la operación era 011 (U->Y), el origen es U, luego hay que voltear el tercer bit y la operación que hay que meter es 010
        Ejemplo completo: operación con 7 discos de U a Y (hemos sacado de la pila 001110112). Hay que meter en la pila, en este orden, tres operaciones: 001101002, 000010112 y 001100102.

    El resultado obtenido para cinco discos es:
    [12345]X      []Y      []U
     [2345]X      []Y     [1]U
      [345]X     [2]Y     [1]U
      [345]X    [12]Y      []U
       [45]X    [12]Y     [3]U
      [145]X     [2]Y     [3]U
      [145]X      []Y    [23]U
       [45]X      []Y   [123]U
        [5]X     [4]Y   [123]U
        [5]X    [14]Y    [23]U
       [25]X    [14]Y     [3]U
      [125]X     [4]Y     [3]U
      [125]X    [34]Y      []U
       [25]X    [34]Y     [1]U
        [5]X   [234]Y     [1]U
        [5]X  [1234]Y      []U
         []X  [1234]Y     [5]U
        [1]X   [234]Y     [5]U
        [1]X    [34]Y    [25]U
         []X    [34]Y   [125]U
        [3]X     [4]Y   [125]U
        [3]X    [14]Y    [25]U
       [23]X    [14]Y     [5]U
      [123]X     [4]Y     [5]U
      [123]X      []Y    [45]U
       [23]X      []Y   [145]U
        [3]X     [2]Y   [145]U
        [3]X    [12]Y    [45]U
         []X    [12]Y   [345]U
        [1]X     [2]Y   [345]U
        [1]X      []Y  [2345]U
         []X      []Y [12345]U
    
    Nota: no se trata en este ejercicio de que entendáis el algoritmo usado, solamente que lo realicéis en ensamblador según se ha explicado y así manejéis pilas, índices, operaciones de bits, etc.
  5. Órdenes de ensamblador vistas.

    ninguna


  6. Órdenes de la shell relacionadas.

    ls
    lista el contenido de un directorio
    cd
    cambia el directorio de trabajo
    rm
    borra un fichero
    man
    muestra la página de manual de una orden
    cat
    muestra el contenido de un fichero
    echo $?
    muestra el código devuelto por el último programa ejecutado


  7. LPEs.


© 2010 Guillermo González Talaván.