Hola de nuevo. Durante la última semana iniciamos las especificaciones de nuestro procesador sencillo utilizando para ello dos ejemplos de sistemas digitales, el controlador de temperatura y el cronómetro. Esta semana daremos una especificación más formal y más precisa de dicho procesador. Y para ello empezaremos por una especificación funcional de nuestro procesador. Veamos en primer lugar los tipos de instrucción. Se han definido ocho tipos de instrucción u ocho instrucciones distintas y para cada instrucción se ha definido un código que la identifica y la lista de parámetros necesarios para la ejecución e interpretación de dicha instrucción. El código de instrucción será una palabra o un par de palabras que identifican a cada instrucción con lo que esa instrucción hace o ejecuta. Así por ejemplo la primera instrucción de la lista es la "assign_value, k, A" assign_value es el código, k y A son los parámetros y lo que hace esta instrucción es asignar el valor de la constante A al elemento de memoria X_k. La siguiente es "data_input, k, j" y lo que hace es que el valor que entra por el puerto j, puerto de entrada j se asigna al elemento de memoria k. La siguiente es "data_output, i, j" y lo que hacemos en este caso es el contenido de un elemento de memoria lo llevamos hacia el puerto de salida en este caso el elemento j de memoria al puerto i de salida. La instrucción "output_value, i, A" hace lo mismo pero ahora lo que enviamos al puerto i de salida es una constante A. y en la siguiente que es "operation i, j, k, f" significa que se debe realizar una operación, la operación es calcular la función f cuyos, cuyos parámetros o cuyas entradas son X_i, X_j y el resultado lo dejaremos sobre X_k. Este es el significado de esta instrucción "operación, i, j, k, f". En este caso f es un identificador de la operación por ejemplo, una suma, una diferencia, una multiplicación, entre otras. De hecho es una operación que algunos de los recursos de cálculo de nuestro procesador puede ejecutar tal como explicaremos más adelante. La instrucción siguiente es el "jump N", significa que la instrucción siguiente a evaluar o a ejecutar es la que está en la posición N. Por lo tanto es como un "go_to N" de las descripciones funcionales que habíamos hecho hasta ahora. La siguiente el "jump POS, i, N" es un salto, el anterior era un salto incondicional, este es un salto condicional y la condición es si el elemento de memoria X_i es positivo, es mayor que cero entonces saltamos a la instrucción, vamos a ejecutar como la instrucción siguiente la que está en la posición N de memoria. Y en caso contrario seguimos en secuencia. Y la otra instrucción de salto condicional es el "JUMP NEG", si el valor de la posición de memoria o del elemento de memoria X_i es negativo, es menor que cero entonces saltamos a la instrucción que está en la posición N. En caso contrario seguimos en secuencia. Y con estas instrucciones intentaremos hacer programas. A modo de ejemplo con estas nuevas instrucciones o tipos de instrucción, este algoritmo de control de temperatura que teníamos aquí, que habíamos visto, descrito de esta manera lo podemos reescribir de esta otra que tenemos aquí utilizando las instrucciones que acabamos de ver. Así por ejemplo, en lugar de X5 igual a 10 que significa poner en la posición de memoria X5, en el elemento de memoria X5 la constante 10. lo que haríamos es utilizar la instrucción "assign_value, 5, 10", ¿de acuerdo? O por ejemplo en la instrucción condicional que tenemos aquí "if X4 menor que 0 go to 7", la reescribiríamos ahora con nuestro nuevo conjunto de instrucciones como un salto si negativo, si X4 menor que 0, si negativo, si X4 es menor que 0 saltamos a la posición 7 y la posición 7 sería saltar a esta instrucción que tenemos aquí. Si no seguiríamos en secuencia por la 5. Y así sucesivamente podríamos ir trasladando todas estas operaciones o instrucciones funcionales a traducirlas a instrucciones de este conjunto que acabamos de definir. El sistema digital que queremos implementar tiene ocho puertos de entrada de datos, el IN0, IN1 hasta IN7, cada uno de ellos de ocho bits, tiene ocho salidas u ocho puertos de salidas de datos, desde el OUT0 hasta el OUT7, también de ocho bits, tiene una entrada instruction, esta que tenemos aquí, cuyo valor corresponde a uno de los ocho tipos de instrucciones que acabamos de ver y sus correspondientes parámetros, es decir, tanto el nombre de la instrucción, el código de la instrucción como los parámetros necesarios entran por esta señal de instruction. Y tiene una salida número o number que selecciona la siguiente instrucción a ejecutar de este programa que tenemos aquí abajo. Un comentario importante. Hasta ahora hemos asumido que nuestro procesador recibía instrucciones desde un dispositivo externo que contenía el programa y que dicho dispositivo externo recibía información en forma de condiciones desde nuestro procesador. Estas condiciones eran indicaciones como por ejemplo X_i es menor que 0 o un determinado elemento de memoria X_k es positivo, mayor que 0. Condiciones de este estilo y similares. Entonces el dispositivo externo o programador tomaba decisiones sobre el siguiente número de instruccione a ejecutar en función de este tipo de condiciones. En la nueva especificación de nuestro procesador se asume que el número de la instrucción siguiente a ejecutar se computa internamente en el propio procesador, es decir, aquí dentro. Luego el procesador recibirá instrucciones, ejecutará, aquí dentro ejecutará dichas instrucciones, y calculará el número de la instrucción siguiente a ejecutar y es el que sacará por esta salida que tenemos aquí. Con esta nueva especificación, el conjunto de instrucciones que constituyen un programa está almacenado en algún tipo de memoria. Y este tipo de arquitecturas capaces de ejecutar programas almacenados en memoria se llaman las arquitecturas von Neumann. A continuación veremos una especificación funcional de nuestro procesador en forma de algoritmo. En primer lugar, ponemos el valor de number a 0, lo que significa es que la primera instrucción que se va a ejecutar será la instrucción número 0, es decir la que está en la posición 0 de la memoria donde almacenamos nuestro programa. Después de esto, el procesador ejecuta un bucle infinito indicado por este loop que tenemos aquí, que realiza las acciones siguientes: lee la instrucción indicada por nuestro número, el number, de nuestro programa leemos la instrucción indicada por number en este caso la primera vez sería la instrucción que está en la posición 0 y esa instrucción es la que entra por la señal de instrucción a nuestro procesador. Y entonces el procesador determina de qué instrucción se trata de forma que si la instrucción es una instrucción de tipo "assign_value, k, A", lo que hace es que sobre el elemento de memoria X_k pone el valor de la constante A, la constante A venía especificada en la propia instrucción. Y a continuación incrementa en uno el valor de "number" de forma que apuntamos a la instrucción siguiente en secuencia para ser ejecutada. En el caso de que esa instrucción que hemos leído de nuestro programa aquí arriba sea una instrucción de tipo "data_input, k, j", lo que hacemos es que el valor del puerto de entrada IN_j se instala en el elemento de memoria X_k. Y de nuevo incrementamos en uno el "number". Si esa instrucción era un "data_output, i, j", lo que se hace sobre el puerto de salida i out_i ponemos el valor del elemento de memoria X_j, y una vez más incrementamos en uno nuestro "number". Cuando la instrucción leida o en curso de ejecución es "output_value, i, A", es el valor de la constante A que viene en la propia instrucción quien se transmite al puerto de salida out_i, y de nuevo incrementamos en uno nuestro "number" para que apunte a la instrucción siguiente en secuencia. Cuando se trata de una instrucción "operation, i, j, k, f", lo que debemos, lo que debe hacer el procesador es realizar esa operación indicada por f utilizando como operandos el valor contenido en la memoria X_i y el valor contenido en la memoria X_j y el resultado de esa operación f lo depositamos en el elemento de memoria X_k, y una vez más incrementamos en uno el number. Y ahora vendrían las tres instrucciones de salto condicional o incondicional que son las que permiten romper la ejecución secuencial de un programa. Tenemos el "jump N", si se trata de una instrucción "jump N" es una instrucción de salto incondicional y significa que hay que ir a ejecutar la instrucción que está en la posición N de memoria. Luego lo único que hay que hacer para ejecutar esta instrucción es poner en number no el number más uno que poníamos habitualmente en las anteriores sino este valor de N que viene en la propia instrucción, de forma que la siguiente instrucción a ejecutar será la de la posición N. Si en cambio se trata de un salto condicional a que un elemento de memoria, el elemento X_i sea positivo, lo que estamos haciendo en esta instrucción es si el valor contenido en el elemento de memoria X_i es mayor que 0, es positivo, entonces hay que ir a ejecutar la instrucción que está en la posición N que venía indicada en la propia instrucción que estamos ejecutando. Luego en ese caso si se cumple la condición lo que hay que hacer es poner N sobre el valor de number. Si no, si no se cumple esta condición, sencillamente seguimos en secuencia, por lo tanto incrementamos number en una unidad. Y lo mismo para la siguiente que es un salto condicional si negativo, si la posición de memoria X_i tiene un valor negativo menor que cero, entonces saltamos a la instrucción N y si no seguimos en secuencia. Y con esto hemos visto un modelo funcional en forma de algoritmo muy simple, este es el algoritmo de nuestro procesador. Pasemos ahora a realizar un ejercicio. Para ello partimos de los supuestos siguientes: que el conjunto de elementos de memoria X está formado por 16 elementos o 16 componentes y cada uno de ellos puede almacenar números de ocho bits, estos son los X0 a X15. Que hay ocho puertos de entrada y ocho puertos de salida y también todos y cada uno de ellos de ocho bits. Que el número máximo de instrucciones de un programa será de 256 y que la operación f solo hay dos posibilidades en cuanto a operaciones que son: la suma y la resta. Bien, pues en base a estos supuestos, la pregunta es, ¿cuántas instrucciones distintas se pueden llegar a definir? Veamos cual es la solución. Para cada tipo de instrucción posible calculamos el número de valores que cada uno de sus parámetros puede tomar. Luego calculamos cuantas combinaciones posibles hay de todos esos parámetros y sus valores, y ese resultado es el número de instrucciones distintas para cada tipo de instrucción disponible. Veamos un ejemplo. En el caso de el primer tipo de instrucción, el "assign value, k, A" k es el número de elementos de memoria, que ya hemos fijado en 16. 16. A es un valor constante de ocho bits, luego el número máximo de valores distintos es dos a la ocho, o sea 256. Por lo tanto, el número total de posibles instrucciones de ese tipo, del assign, es el resultado de multiplicar el número de elementos de memoria 16 por el número máximo de posibles valores de A que eran 256 y esto nos da un total de 4096 posibles instrucciones. Si repetimos estos mismos cálculos para todos los tipos de instrucción considerados y sumamos estos valores resultantes, lo que obtendremos al final es el valor de 23040 instrucciones distintas. Una observación interesante que podemos hacer ya en este momento, es que el número total de instrucciones, estas 23040, está comprendido entre dos a la 14 y dos a la 15. Luego más adelante cuando necesitemos codificar todas estas instrucciones distintas en códigos binarios, ya sabremos de antemano que el número mínimo de bits que necesitamos para ello es 15, este 15 que tenemos aquí. Esto ya nos da una pista de cual será precisamente el número necesario de bits para codificar nuestras instrucciones. Y como resumen de esta lección diremos que hemos definido un conjunto de instrucciones que nuestro procesador sencillo es capaz de ejecutar. Se ha introducido el concepto de arquitectura von Neumann, arquitectura basada en la idea de ejecutar programas almacenados en memoria y se ha propuesto una especificación funcional en forma de algoritmo sencillo para nuestro procesador. Y con esto finalizamos la sesión. Gracias y hasta la próxima.