En la lección de hoy vamos
a implementar el último de los bloques de nuestro procesador.
Se trata del bloque secuencial go to que es el encargado de
calcular el número de la instrucción siguiente a ejecutar.
Este código de aquí de la izquierda corresponde
a la especificación funcional de este bloque, donde el valor de number se
almacenará internamente dentro del propio bloque.
Por lo tanto, se trata de un módulo o circuito con memoria,
luego es un circuito secuencial.
Una vez más el comportamiento de este módulo depende de
la instrucción en curso de ejecución.
Y las instrucciones que en este caso hay que tener que cuenta,
que afectan a este módulo son las instrucciones de bifurcación o salto
you sea incondicional como el jump o condicional si positivo o si negativo.
Definiremos una señal num sel de cuatro bits tal como se indica en esta tabla.
Los dos primeros bits tomaran el valor uno,
uno cuando la instrucción en curso sea una de estas instrucciones
de salto condicional o incondicional que tenemos aquí.
El tercer bit tomará el valor uno solo cuando la instrucción sea
un salto incondicional y en los otros casos tomará el valor cero.
Y por último el cuarto bit se utilizará para distinguir entre
las dos posibles condiciones de salto, cero para un salto si
se cumple la condición de positivo y un uno para
saltar si se cumple la condición de que un determinado dato es negativo.
Ahora con la definición de esta nueva señal de control de cuatro bits num sel,
tanto las entradas y salidas de nuestro bloque go to que vemos
aquí como la descripción funcional del mismo han cambiado ligeramente.
A nivel de las entradas del bloque go to también tenemos la señal de control
num sel, tenemos el valor N que viene de la propia instrucción,
la señal data que trae información del banco de registros y una señal llamada
reset que permite poner el valor inicial de number a cero.
Y finalmente la única salida de este bloque que es el
número o number de la próxima instrucción a ejecutar.
Veamos ahora la descripción funcional modificada.
Además de esta primera instrucción para fijar el valor inicial de number en
función del valor que tenga la función inicial que acabamos de llamar reset,
vemos que el resto del algoritmo se basa en un case que
pregunta por el valor de la señal de control num sel.
Si esta señal es igual a uno, uno, uno,
cero es decir, se trata de una instrucción de salto incondicional,
de tipo jump entonces el nuevo valor
de number será N, saltamos a la instrucción que está en la posición
N de memoria que viene dado por la propia instrucción en curso.
Si el num sel toma el valor o tiene como valor uno,
uno, cero, cero entonces se trata de un salto condicional si positivo.
Y en ese caso hay que preguntar si data es positivo, y entonces el valor
que tomará number será el valor de N que venía en la propia instrucción,
sino se cumple la condición de que data sea positivo,
entonces number sencillamente se incrementará en uno.
Y algo parecido cuando el num sel tiene el valor uno,
uno, cero, uno que corresponde a una
bifurcación condicional si el valor de data es negativo.
Tenemos el mismo caso que antes, pero ahora la condición es que si data es
negativo entonces number toma el valor N y si no number se incrementa en uno.
En cualquier otro caso, es decir para cualquier otra instrucción el valor de
number será su valor actual incrementado en uno.
Aquí en la parte superior izquierda de la
transparencia hay una posible implementación directa de
este bloque basada en tres sub módulos o sub circuitos.
El principal sub módulo es este contador programable con una entrada
de reset para inicializar el valor de number a cero,
una entrada de load para habilitar la carga del contador
con el valor que viene desde N y finalmente la propia
entrada N que trae el valor que contenía la propia instrucción.
La única salida de este contador programable es la salida number.
Los otros dos bloques,
tenemos el bloque sign que es un circuito combinacional cuya
funcionalidad queda definida por esta tabla de aquí de la izquierda.
Y donde vemos que genera el valor
pos igual a uno cuando el valor de data es mayor que cero, es decir es positivo.
O bien genera el neg igual a uno
cuando el valor de data es negativo o menor que cero.
Y finalmente en caso de que el valor de data sea igual a cero,
ambas señales pos y neg toman el valor cero.
Por último el bloque load, este que tenemos aquí,
que también queda definido por esta tabla de aquí abajo y su salida
load se hará uno si y solo si num sel
tiene este valor que corresponde a un salto incondicional.
En ese caso siempre load tomará el valor uno.
En ese caso siempre hay que cargar el valor N en el contador.
Y también tomará el valor uno cuando se trate de un salto condicional
si positivo y el valor del signo sea positivo, es decir pos sea igual a uno.
Y también tomará el valor uno cuando se trate de un salto
condicional si negativo y la señal neg que viene del,
del bloque anterior es igual a uno, es decir si el bloque anterior ha
determinado que el dato por el que preguntamos es negativo.
Y en cualquier otro caso tomará el valor cero.
A modo de ejercicio, trata ahora de escribir el bloque go to en VHDL.
Y para ello asociaremos un proceso VHDL a cada uno de estos tres bloques,
luego nuestra arquitectura VHDL constará de tres procesos.
Y definiremos un puerto de tipo input output in out,
el puerto va a ser el puerto correspondiente a number,
para que de esta forma podamos escribir sentencias del estilo number
igual a number más uno, como las que habíamos visto anteriormente.
Para esta sentencia primero hay que leer el valor de number y después de realizada
esta operación hay que escribir en number, para que ello sea
posible se necesita que number esté declarado como un puerto de tipo in out.
Y aquí tenemos una posible solución.
Una vez hemos hecho visibles y accesibles las librerías del i e cubo y la nuestra
propia, pasamos a declarar la entidad de nuestro bloque go to.
Donde tenemos que definimos sus puertos de entrada salida.
N y data son vectores de m bits,
clk y reset son señales de entrada de un solo bit,
num sel es la señal de control de entrada de cuatro
bits y finalmente number es la salida de este de este bloque,
pero que lo declaramos como in out como habíamos dicho y también es de m bits.
Una vez tenemos declarada la entidad,
podemos empezar a describir nuestra arquitectura.
Recordemos que en la implementación directa que hemos hecho,
había tres señales internas, pos, neg y load que no
están declaradas obviamente en las entradas y salidas de la entidad.
Y por lo tanto, hay que declararlas como específicas de esta arquitectura.
Una vez declaradas estas señales, empieza la descripción propiamente
dicha de la arquitectura desde este begin hasta este end.
Como hemos dicho, constará de tres procesos.
El primero de estos procesos es el encargado de calcular el valor
del signo de data y asumimos que los valores que vienen por data,
son valores representados en forma de complemento a dos.
Luego, el bit más significativo de data será el bit de signo.
Por lo tanto, para saber el signo de data sólo es
necesario preguntar por ese bit y eso es lo que hacemos aquí.
Si data de el bit más significativo es decir, data del m
menos uno es igual a uno, significa que data tiene un valor negativo.
Luego ponemos neg a uno y el pos a cero.
Sí, sino se cumple esta condición pero se
cumple que data sea igual a cero, entonces ambos pos y
neg tienen que tomar el valor cero según la tabla que tenemos aquí al lado.
Y en caso de que no se cumpla ninguna de estas dos condiciones,
eso significa que data es positivo, estaríamos en este
caso y por lo tanto, tenemos que poner el pos a uno y el neg a cero.
Este proceso por lo tanto,
ha materializado directamente esta tabla que teníamos aquí.
El segundo proceso, modela el bloque
log mediante una descripción directa de su tabla de funcionamiento,
que tenemos aquí utilizando una sentencia case sobre la señal num sel.
Cuando num sel sea igual a uno, uno,
uno cero, la señal de load tomará el valor uno.
Recordaremos uno, uno,
uno, cero era el código que habíamos asociado al salto incondicional.
Por el contrario, si esa señal toma el valor uno, uno, cero,
cero que recordemos corresponde al salto condicional sí positivo,
load tomará el valor de la señal pos que viene del bloque de computación de signo.
Si el código num sel es uno, uno, cero,
uno es el correspondiente al salto condicional sí negativo,
en ese caso load toma el valor de la señal neg evaluado por el bloque
de signo y en cualquier otro caso load toma el valor cero.
Y el tercer proceso, que describe al contador programable.
Si reset está activo, lo que hacemos es inicializar number al valor cero.
Y en caso contrario, es decir,
cuando reset no esté activo miramos con esta condición de aquí,
miramos si hay un flanco positivo de la señal clk.
En el caso de que haya un flanco positivo de la señal clk es cuando se
ejecuta esta parte del código y en ese caso, si load está a uno
entonces number tomará el valor que venga por la entrada N.
Y en caso contrario, es decir, si load está a cero,
number toma el valor de number más uno, se incrementa en uno.
De este proceso que tenemos aquí, se infiere un
registro para guardar el valor de number después de ser actualizado.
Y dada la operativa descrita por este proceso, dicho registro actúa
según el valor de load o bien como un contador number igual a number
más uno o bien como un registro de carga paralela number igual a n.
Y como resumen, decir que hemos implementado el bloque secuencial go to,
para el que también hemos generado su correspondiente modelo VHDL.
Completando así, la implementación y modelado VHDL de
los cinco bloques que componen nuestro proceso de hoy.
Gracias y hasta la próxima.