Construye tu computadora Mínimum.

Parte 2: Diagrama esquemático.

Por: Oscar Toledo Esteva.       Septiembre de 2018.


Registros de programación

Los microprocesadores usan celdas de almacén temporal para guardar sus datos y transferirlos a la memoria principal, además, moverlos a las celdas llamadas registros que manejan hasta 32 bits nombrado "palabra", el microprocesador de Mínimum tiene 16 registros de 32 bits, R0 hasta R12 es para todo uso, y tres registros R13, R14 y R15 para usos especiales. Los registros de R0 hasta R7 son los mas utilizados por las instrucciones, mientras que los registros R8 hasta R12 requieren ciertas condiciones para su uso. El microprocesador usa la arquitectura de cargar y almacenar (Load and Store) en sus registros, al construir programas con el repertorio de instrucciones es conveniente tener el organigrama de la tarea con los datos, que posteriormente se almacena en la memoria, en el proceso mueve el valor binario al primer operando del registro. Por ejemplo, la instrucción MOVS R1,#04 cubre solo un rango de 8 bits (1 byte) para cubrir la cuarta parte de 32 bits, Por lo tanto 0 4 = 0000 0100 binario, equivale a dos valores hexadecimales como lo indica la tabla de conversión numérica. Se utilizan 16 registros de 32 bits cada uno, donde los registros 0 y 7 son los registros bajos que usan la instrucción MOVS Rd,n, R8 hasta R12 son los registros superiores para uso general, mientras que R13 hasta R15 son registros especiales del microprocesador.

El registro 13 (R13) es de uso exclusivo del Stack Pointer (SP) que guarda la dirección de la pila de memoria, R13 comparte dos funciones indicadoras; la pila principal (Main Stack MSP) y la pila de procesos alternos (Process Stack PSP). En el arranque inicial, el microprocesador utiliza el puntero de la pila de MSP, un dato que el programador coloca en la primera locación de la memoria para indicar en la parte superior de la memoria SRAM en la región 2xxx:xxxx donde el bit 29 siempre es igual a 1, aquí R13 apila solo datos de 32 bits de la parte superior a la inferior de la memoria de trabajo, para salvar el contenido de un registro este se guarda en la pila de memoria que maneja SP, y en automático se pueden almacenar los retornos de subprogramas o subrutinas con la instrucción apropiada, igual que una cadena de datos de los registros, cada locación de memoria ocupada desciende 32 bits el indicador del registro SP. Al meter y sacar datos en la pila de la memoria se utilizan las instrucciones PUSH y POP, otras instrucciones guardan y obtienen el contenido de multiples registros de la pila de memoria. R14 es el Registro de Enlace (LR) que guarda la dirección de retorno de la memoria al regreso de una subrutina o subprograma. R15 es el Program Counter (PC), que guarda y apunta la dirección de la memoria de la próxima instrucción ejecutable.

Los grupos de instrucciones son para:

Las operaciones con datos siempre utilizan registros, este procesamiento lo utilizan las siguientes instrucciones: desplazamiento de bits, movimiento con registros, aritmética, multiplicación, lógicas booleanas y operaciones con las banderas de estatus. El programa para ensamblar instrucciones tiene un formato para indicar la dirección donde reside el programa, el código máquina, el código de la instrucción o nemónico, además de los comentarios y etiquetas de cada fase del programa escrito por el usuario.

Formato de una instrucción

Código de operación o nemónico, Rd, Rn, OP2:

El registro destinario es Rd
El primer operador que siempre es un registro es Rn
El segundo operador es OP2

El segundo operador OP2 puede ser:

  • Un valor inmediato
  • Un registro
  • Un registro con un valor desplazado
  • Un registro con un valor desplazado en un registro

  • Instrucciones MOV, MOVS, MOVW, MOVT y MOV.W:

    Todas las computadoras están basadas en las instrucciones "Guardar" y "Almacenar" de los primeros microprocesadores, como: LD A,#n guardar un dato en el registro A (Acumulador), su equivalente actual es MOVS R0,#n mover un dato en el registro 0.

    
    08 46           MOV R0,R1          ; R1 es el registro fuente que no pierde el
                                       ; dato y R0 es el registro destinario del dato
    
    FF 20           MOVS R0,#FF        ; MOVS mueve un dato máximo de 8 bits en
                                       ; un registro
    
    41 F2 34 20     MOVW R0,#1234      ; MOVW mueve un dato de 16 bits en R0
    
    C7 F2 54 60     MOVT R0,#7654      ; Guarda un dato de 16 bits en la parte
                                       ; superior (bit 31:16) del registro 0 y
                                       ; preserva los 16 bits inferiores
                                       ; (bit 15:0) de R0
    
    4F F0 00 41     MOV.W R1,#80000000 ; Guarda un valor de 32 bits en un registro
                                       ; (hay restricciones con ciertas cifras)
    
    Instrucción MOV ilegal
    
                    MOVS R1,#80000     ; Aquì hay un error, no es posible guardar
                                       ; este valor en una instrucción que solo
                                       ; maneja 8 bits
    
    Alternativa posible
    
                    MOVS R1,#1         ; Bit 1 de R1 igual a 1
                    LSLS R1,R1,#13     ; 13 hex = 19 decimal. El valor de R1
                                       ; es desplazado a la izquierda 19 veces
                                       ; y R1 = 80000
    
    

    Instrucciones LSL, LSR, ASR y ROR

                    LSL desplazamiento de bits a la izquierda
                    LSR desplazamiento de bits a la derecha
                    ASR desplazamiento aritmético de bits a la derecha
                    ROR rotación de bits a la derecha
    
    Ejemplo:
    
    ADD R0,R1,R5,LSLS,#4 ; El valor de R5 es desplazado a la izquierda con
                         ; 4 bits de su posiciòn original
    
    ROR R2,R2,#1C        ; El dato de 32 bits de R2 es rotado a la derecha
                         ; desde la posición del bit 28
    
    

    Instrucciones ORR, ORSS

    
                    ORR R1,R1,#14   ; Inserta en el bit 14 y bit 2 del registro
                                    ; R1 una lógica 1
    
                    LDR R1,[R3]     ; Obtiene un valor del contenido de R3
                    ORR R1,R1,#10   ; Inserta una lógica 1 al bit 4 de R1
                    STR R1,[R3]     ; Salva el valor modificado al contenido de R3
    
                    ORSS R1,R2      ; Compara una lógica 1 que activa las banderas
    
    

    Instrucciones BIC, BICS

                    BIC R0,R0,#3000    ; Modifica el contenido de R0 borrando
                                       ; los bits 12 y 13 y lo regresa a R0.
                                       ; Por ejemplo: Inicialmente R0 = 40023800
                                       ; el resultado R0 es igual a 40020800
    
                    LDR R1,[R3]        ; Obtiene un valor del contenido de R3
                    BIC, R1,R1,#10     ; Inserta una lógica 0 al bit 4 de R1
                    STR R1,[R3]        ; Salva el valor modificado al contenido de R3
    
                    BICS R1,R2         ; Compara R1 con R2 de acuerdo al resultado
                                       ; se afectan 3 banderas.
    

    Instrucciones para guardar, borrar, intercalar, restar y sumar en los registros 3 y 4.

    Hay dos pseudoinstrucciones que maneja el programa ensamblador Familia Toledo, y sirven para guardar datos de 32 bits en registros:

    
    LDR R0,=76543210        ; Este valor se obtiene de una locación
                            ; prefijada de la memoria
    ADR R1,=2000:2000       ; Este dato indica la locación directa
                            ; de una memoria del sistema
    
    
    Registros y locaciones de memoria

    En la programación Mínimum solo se puede utilizar el repertorio de instrucciones del microprocesador, cada instrucción binaria de 16 o 32 bits es un código exclusivo para ser leído, codificado y ejecutado por el microprocesador, el conjunto de códigos o claves forman el programa o software de la computadora. Al desarrollar un programa se busca un procedimiento directo o algoritmo, que conduzca a la solución de un problema, este método no es nada nuevo, hace más de 2000 años Euclides observó paso a paso como solucionar problemas con matemáticas, ya en el siglo IX, del nombre del matemático persa Al-Khwarizmi derivó la palabra algoritmo, que suele ser un método definido para desarrollar programas de computadoras, desde un programa que suma dos números enteros hasta rutinas complejas con coma flotante. Un algoritmo se representa mediante un diagrama de flujo u organigrama, para bosquejos visualizados y complicados, el algoritmo se puede expresar en una secuencia de instrucciones llamado código, al escribir el programa se utiliza un lenguaje estructurado de alto nivel -hay docenas de lenguajes de programación- que traduce literalmente del lenguaje cercano al programador las cifras binarias de las claves o códigos máquina que utilizan las instrucciones del microprocesador.



    Un programa es un grupo de instrucciones para un proposito, se guarda a partir de una locación de la memoria estática, la dirección la define el usuario que lee y corrige su programa, que al ejecutarse en el microprocesador busca y codifica sus instrucciones para ofrecer el resultado esperado.

    Registros de estatus para programas

    Los programas se ejecutan de forma secuencial, hasta que una instrucción de salto condicional lo bifurca a otra dirección, una llamada va a una subrutina o se produzca una interrupción, de esto se ocupa el registro especializado de 32 bits (PSR. Program Status Register) que indica el estatus de las operaciones de las instrucciones condicionantes, y el el tipo de operación lo indican las banderas principales N, Z, C y V, con las instrucciones condicionantes. El estatus de las banderas del registro PSR señala cuando el programa salta a otra dirección, al guardar u obtener un dato de forma automática. Para esto, PSR activa los bits binarios de las banderas localizados en los bits 31, 30, 29, 28 y 27, el bit 31 es la bandera N (Negative), subsecuentemente Z (Zero), C (Carry), V (Overflow) y Q (Saturation). Las instrucciones de un programa corren de forma secuencial en una dirección señalada, de acuerdo a la lista del programa, el contador del programa se incrementa a la longitud del código de la instrucción, hasta que la secuencia cambia la ruta del programa. Esto sucede con una instrucción de salto, una ejecución condicional, una llamada a un subprograma y a través de una operación con interruptores, todo tiene que ver con las banderas del registro de estatus, para realizar el enunciado SI-ENTONCES-DE LO CONTRARIO (IF-THEN-ELSE), que expone la teoría de la información de Claude Shannon (1916-2001) cuya función es separar lo previsible de lo imprevisible, el acuño el término "bit" para una unidad de información utilizando hasta cuatro valores binarios similar a las cuatro letras del código del ADN, codificando la información verdadera como imprevisible o igual que uno, y lo previsible no es información, lo que equivale a cero, mientras que la transferencia de la comunicación se calcula en bits por segundo.


    La bandera N es 1 si el resultado es un número negativo, y cero si es un número positivo.
    La bandera Z es 1 si el resultado de una cifra es 0, de lo contrario Z = 0.
    La bandera C es 1 si ocurre un acarreo en un resultado aritmético, de lo contrario C = 0.
    La bandera V es 1 si ocurre un desborde aritmético en la frontera del bit 31, de lo contrario V = 0.
    La bandera Q = 1 indica saturación con las instrucciones SSAT o USAT, también indica un desbordamiento de una cifra con DSP.

    El registro XPSR tiene una franja de bits para examinar cinco banderas: Bit 31 = N, bit 30 = Z, bit 29 = C, bit 28 = V y bit 27 = Q. Bit 19:16 son banderas de GE (Greater-Equal) que indican: igual o mayor que, para instrucciones DSP (Digital Signal Processing), bit 8:0 indica con número hexadecimal mas de 256 errores de programación, que pueden ocurrir al realizar programas con interruptor. Es necesario crear un programa depurador que con la ayuda de los registros que muestra las banderas condicionantes, el programador pueda ver cómodamente donde y por qué ocurren errores de programación.

    Ejemplo:
    
    MOVS R1,#01     ; R1 = 1
    SUBS R1,#01     ; R1 = R1 - 1
                    ; R1 = 0
    N Z C V
    0 1 1 0 ; Z = 1 por el resultado igual a 0
    
    MOVS R1,#02     ; R1 = 2
    SUBS R1,#01     ; R1 = R1 - 1
                    ; R1 = 1
    N Z C V
    0 0 1 0 ; Z = 0 por el resultado que no es 0
    
    

    El resultado de una operación con aritmética, lógica, comparaciones de datos, desplazamiento y rotaciones de bits, activan las banderas de XPSR que deciden las bifurcaciones hacia otra dirección de las instrucciones de los saltos condicionantes. Además, los datos con signo positivo y signo negativo siempre activan las banderas.

    Rango de números de 32 bits negativos y positivos
    con notación hexadecimal.
    
    Un número negativo es igual a bit 31 = 1 y el positivo es igual a bit 31 = 0
    
    De 0000:0000 hasta 7FFF:FFFF son datos positivos
    De 8000:0000 hasta FFFF:FFFF son datos negativos
    
    

    Instrucción CMP

    Se utiliza al comparar un registro con el segundo operando, que puede ser una constante (CMP R1,#n) o con otro registro (CMP R1,R2)

    CMP R0,#4       ; Compara R0 con 4
    BEQ X           ; Si R0 = 4 salta a la dirección X
    
    CMP R0,R1       ; Compara los valores de R0 con R1
    BNE X           ; Si R0 = R1 no salta a la dirección X
    
    CMP.W R0,#80000000 ; El valor de R0 se compara con 8000:0000.
                       ; El resultado es V=1 que indica un desbordamiento
                       ; de la cifra de 32 bits, y N=1 por el bit 31 = 1 que
                       ; indica que es un número negativo
    
    

    Instrucción ITE (If then else)

    X CMP R0,R1       ; Compara los valores de R0 con R1
      ITE GT          ; IT con la condición E y el operando GT "mayor que"
      SUBGT R0,R0,R1  ; Si "mayor que" resta en R0
      SUBLT R1,R1,R0  ; Si "menor que" resta en R1
      BNE X           ; Si R0 no es igual a R1 compara nuevamente R0 con R1
    
    

    ITE (If then else) a continuación puede condicionar hasta cuatro instrucciones con ciertas restricciones.

    Programa para obtener el máximo divisor común

    El siguiente programa es el algoritmo de Euclides para determinar el máximo divisor común (MDC) implementado con las instrucciones de Mínimum, se utilizan dos enteros positivos: El MDC de (A 152) y (B 57) = 19.

    Comprobación de A y B después de un número finito de pasos.
    
    A 152 57 MOD = 38    Primera etapa
    B 57  38 MOD = 19    Segunda etapa
    R 38  19 MOD = 0     Tercera etapa, si final es = 0 el resultado de MDC es 19
    
    
      MOVS R0,#98     ; A = 152 decimal                        Etapa para fijar
      MOVS R1,#39     ; B = 57 decimal                         parámetros
    
    X CMP R0,R1       ; Compara el valor de A y B              Etapa para continuar
                                                               o terminar
    
      ITE GT          ; GT (Great Then) condiciona N Z C V     Etapa del bucle
      SUBGT R0,R0,R1  ; Si A es mayor que B: A = A - B         principal
      SUBLT R1,R1,R0  ; Si B es mayor que A: B = B - A
      BNE X           ; Si A = B, finaliza
    
      MOVW R2,#0100   ; R2 = 00000100 dato de 16 bits en R2   Etapa final
      MOVT R2,#2001   ; R2 = 20010100 locación de la memoria (32 bits)
      STR R0,[R2]     ; El resultado se almacena en la
                      ; dirección de R2
    
            Resultado: registro 0 = 13 hexadecimal = 19 decimal
                       registro 1 = 0
                       registro de estatus XPSR N=0 No hubo número negativo
                                                Z=1 Hubo cero
                                                C=1 Hubo acarreo
                                                V=0 No hubo desbordamiento
    
    

    El microprocesador maneja códigos de 16 y 32 bits para las instrucciones, estas consumen tiempo para su ejecución, la mayoría de ellas se ejecutan en un ciclo de reloj, y cada ciclo es un periodo de tiempo de 62.5 nanosegundos con la frecuencia de 16 MHZ. También a cada ciclo de una instrucción se le conoce como ciclo máquina, solo algunas instrucciones requieren mas tiempo para su ejecución, como la instrucción VDIV.F32 S0,S0,S1 que se ejecuta en 14 ciclos del reloj del microprocesador. Con la frecuencia del reloj a 16 MHZ se obtiene el ciclo de trabajo cuando comienza el proceso y la búsqueda de instrucciones, por ejemplo: la instrucción SUBS R1,#1 resta una unidad del valor que contiene el registro 1 y toma un ciclo para ser ejecutada, la instrucción LSLS R1,R1,#13 desplaza 19 veces a la izquierda el valor del registro 1 y toma dos ciclos en ser ejecutada, en cambio la instrucción BNE se ejecuta en 5 ciclos y 3 ciclos si no hay un salto, en algunas instrucciones interviene el conducto de espera de instrucciones (pipeline) que afecta las instrucciones de saltos condicionales, a continuación algunos ejemplos de retardo con su código máquina de 16 bits y 32 bits y la instrucción ensamblada:

    
            01 21   MOVS R1,#01             ; R1 = 1 se ejecuta en 1 ciclo
            C9 04   LSLS R1,R1,#13          ; Valor desplazado 19 veces a la izquierda
                                            ; para que R1 = 80000 = 524288 decimal
                                            ; sea el contador, se ejecuta en 2 ciclos
     salto  01 39   SUBS R1,#1              ; Resta una unidad al contador,
                                            ; se ejecuta en 1 ciclo
            FD D1   BNE salto               ; Repite la resta hasta que el contador
                                            ; es igual a cero. Se ejecuta en 5 ciclos
                                            ; en cada salto y 2 ciclos si no hay saltos
    
    
    Resultado = 1 + 2 + (contador - 1) x (1 + 5) + (1 + 2) = 3145728 ciclos
    
           4F F0 00 51     MOV.W R1,#20000000      ; R1 = 536870912 como contador para
                                                   ; obtener los ciclos del retardo
                                                   ; se ejecuta en 1 ciclo
    salto  01 39           SUBS R1,#1              ; Se ejecuta en 1 ciclo
           FD D1           BNE salto               ; Se ejecuta en 5 ciclos, con
                                                   ; un resultado de 3221225470
                                                   ; ciclos totales que da un
                                                   ; retardo de 3.22 minutos
    
    

    La cifra FFFFFFFF hexadecimal es el valor màximo de 32 bits que R1 como contador puede manejar, y obtener el máximo retardo con 16 MHZ.

    El resultado en ciclos del contador es el mismo si la frecuencia de trabajo es de 16 MHZ o 168 MHZ.

    Registros especiales

    Para accesar a los registros especiales se utilizan las instrucciones MRS y MSR:

    MRS Rg,Re       ; Mueve el dato de un registro especial a un registro
                    , de uso general
    
    MSR Re,Rg       ; Mueve el dato de un registro de uso general a un
                    ; registro especial
    
    

    Por ejemplo:

    MRS R0,XPSR ; Lectura en R0 del registro especial del estatus del microprocesador
    
    MSR CONTROL, R0 ; Escribe el valor de R0 al registro control
    
    


    Programación de la aritmética, desplazamiento o rotación de bits y lógicas.

    Lenguajes de programación

    Un modo de programar el microprocesador es utilizar un programa que maneja lenguaje ensamblador, con resultados ventajosos por su ejecución directa y rápida. Otra alternativa es trabajar con el lenguaje C o C++, por su escritura y el mantenimiento fácil de sus programas, sencillo de implementar en microprocesadores, aunque los compiladores de lenguajes como el C no son amistosos, su compilador puede trasladar el programa a microclaves poco óptimas, con errores de redondeo en cifras con coma flotante y generan programas que ocupan mucho espacio de memoria, además aleja al usuario del lenguaje original del microprocesador, similar a un compilador-traductor del diidxazá al inglés que traduce frases equivocadas o con redundancias de palabras. Solo con el lenguaje ensamblador se logra optimizar las instrucciones del microprocesador, aunque en la práctica puede ser un trabajo laborioso que puede extender el tiempo para concluir el desarrollo del programa.

    La mayoría de los programas para los sistemas computarizados se escriben con C, y su compilador traslada la edición del programador a código binario del microprocesador, las literaturas de los fabricantes de chips ponen de ejemplo la programación C para sus productos, dejando relegado el lenguaje ensamblador que maneja directamente las instrucciones del microprocesador, este ultimo se edita con una sintaxis rígida para las etiquetas del programa, bifurcación y la tabla de parámetros de sus instrucciones, principalmente los comentarios, nemónicos y los códigos de cada instrucción, para ilustrar las cifras de las direcciones que se utilizan en el ensamblador y ordenador de códigos.

    El lenguaje ensamblador no es fácil de manipular, pero tiene la ventaja de manejar rápido y directo los códigos del microprocesador, en cambio el lenguaje C usa librerías predefinidas para cada microprocesador, que excluye instrucciones especializadas como números de puertas de entradas y salidas, interrupciones para multitareas o el manejo del tiempo de ejecución de un sistema operativo. Aunque manejar directamente los códigos del microprocesador es arduo, suele ser efectivo, mas cuando la velocidad del programa es crítica. Al ejecutar el programa escrito, toda la sintaxis pasa por un filtro del lenguaje para extraer solo las cifras binarias del conjunto de instrucciones que se almacena en la dirección de la memoria de tareas, listo para ser ejecutado por el microprocesador.

    Al memorizar gradualmente los nemónicos de las instrucciones el iniciado en lenguaje ensamblador descubre que hay diferentes formas de aplicarlos en los algoritmos clásicos. A la luz de la necesidad de encontrar una mejor solución al procesamiento digital, si realmente se busca rapidez u optimizar un programa, hay que descender hasta el nivel del lenguaje máquina del procesador con el lenguaje ensamblador.

    Todos los registros usan las memorias internas del microprocesador, principalmente el registro 13 que siempre indica la dirección de la pila de memoria (Stack Pointer = SP).

    Comunicación con Mínimum

    Para enlazar Minimum a la computadora anfitrión se utiliza un cable serializado para transmitir y recibir datos del microprocesador, un programa de comunicaciones de creación propia le incluímos un editor, ensamblador y ordenador, además guarda, enlista y ejecuta todas las ordenes que suministra el monitor o debug que se incluye en el microprocesador. Los fabricantes de microprocesadores instalan su firmware exclusivo de comunicación, algunos los nombran bootloader o ISP (In-System-Programming). Particularmente, el microprocesador de Mínimum tiene un depurador con 12 ordenes: para examinar y escribir en la memoria, ejecutar programas del usuario, listar las ordenes incluidas, además de borrar y programar la memoria flash de 1,048,576 bytes, en 12 sectores que comienzan en la dirección 0800:0000 hexadecimal.

    Nuestra plataforma con conectores USB y DB9 232C, es el anfitrión de la computadora Minimum y del curso anual de la Familia Toledo "Construye y programa tu computadora". Un software de creación propia comunica ordenes e instrucciones de programas, para depurar, listar, ensamblar instrucciones y ejecutar programas de cualquier tipo; mecatrónica, memoria SD, usos educativos, autoaprendizaje, calculadora científica, comunicación cableada, sensores o grabar una tarea definitiva en la memoria flash del microprocesador.

    El microprocesador tiene seis UART (Universal Asynchronous Receiver And Transmitter), para un enlace cableado serializado, en una comunicación con el debug este examina cada UART hasta seleccionar el que está activado con la computadora anfitrión, y desconecta todos los periféricos restantes de comunicación. Se elige un UART y se fija la velocidad de transmisión de la computadora anfitrión a 115200 baudios, y envía la clave 7F hexadecimal para activar Mínimum, cuando el debug del microprocesador sincroniza la velocidad en baudios del UART anfitrión, la computadora responde al anfitrión con la clave 79 hexadecimal como señal de reconocimiento indicando que el enlace está establecido y el microprocesador preparado para recibir programas del anfitrión.

    Interfaz serializado RS232C para comunicar al microprocesador con la computadora anfitrión. El switch de botón momentaneo reinicia Mínimum desde una locación prefijada para ejecutar el programa del usuario.

    En el depurador WRITE (W) es la orden de escritura, pide al usuario teclear la dirección de la locación donde comienza el volcado de los datos e instrucciones para escribir el programa correspondiente. La orden GO (G) es para ejecutar en una dirección el programa correspondiente. El comienzo de cualquier programa inicia con dos datos de 32 bits, uno para fijar espacios de la memoria (SP) del microprocesador, y en la siguiente el apuntador de la locación donde se van a ejecutar las instrucciones del usuario.

    ¡Mi laptop solo tiene conector USB y no RS232C! No hay problema, coloque en el circuito impreso un cristal de cuarzo de 8 MHZ y dos condensadores de 20 picofaradios para que el microprocesador sea preciso en 20 PPM (Partes por millones) que requiere el interfaz USB. O también usar un convertidor comercial de USB a UART RS232C.

    Circuitos adicionales para mejorar la computadora Minimum.

     

    Artículo anterior Artículo anterior Siguiente artículo Siguiente articulo