En este link pueden encontrar un emulador de TOY-8, una computadora super simple pero que ilustra perfectamente como una CPU ejecuta un programa desde la memoria. Todo el crédito de esta computadora es para Robert Sedgewick y Kevin Wayne, autores de Computer Science: An Interdisciplinary Approach, el manual de donde saqué esta computadora ficticia.
El emulador está re crudo todavía, hay bastante para mejorar pero funciona. También les dejo un circuito para el Logisim de la computadora.
TOY-8 es una computadora con lo mínimo indispensable:
El lenguaje máquina de TOY-8 tiene ocho instrucciones que se codifican usando los primeros 4 bits (0-3) para indicar una dirección de memoria y los últimos 3 bits (5-7) para indicar el opcode (código de operación). Los bits están numerados de derecha a izquierda, el cuarto bit no se usa y decimos que siempre es cero.
campos: opcode|x|address
101|0|0000
bits: 7 4 0
La instrucción de arriba corresponde a un load word 0
o lw 0
en algo similar a un lenguaje ensamblador. Lo que hace esa instrucción es cargar el contenido de la dirección de memoria cero en el registro R. Eso mismo escrito en pseudocódigo sería R = M[0]
o lo que es lo mismo R = 0
porque la dirección de memoria cero siempre vale cero. La instrucción de arriba, que en lenguaje máquina es 10100000
(en binario) es mucho más fácil de leer en hexadecimal: A0
.
Las ocho instrucciones de TOY-8 se resumen en la siguiente tabla.
Opcode (bin) | Opcode (hex) | Assembler | Pseudocódigo |
---|---|---|---|
0000 | 0 | halt |
|
0010 | 2 | add |
R = R + M[addr] |
0100 | 4 | and |
R = R & M[addr] |
0110 | 6 | xor |
R = R ^ M[addr] |
1000 | 8 | la |
R = addr |
1010 | A | lw |
R = M[addr] |
1100 | C | sw |
M[addr] = R |
1110 | E | bze |
if (r == 0) PC = addr |
Las instrucciones en assembler significan:
halt
para la CPU.add
, and
y xor
las operaciones de la ALU, suma aritmética y AND y XOR bit a bit.la
load address (cargar dirección).lw
load word (cargar palabra).sw
store word (guardar palabra).bze
branch if zero (ramificar si R es cero).Para implementar estas ocho instrucciones no necesitamos demasiado, ese es el punto justamente de esta computadora. Tenemos 5 elementos dentro de la CPU:
También son necesarios algunos multiplexores dentro de la CPU para enrutar algunas entradas que tienen más de un origen posible.
Fuera o dentro de la CPU, marcando el ritmo de la unidad de control tenemos un reloj. El ciclo de instrucción de esta computadora es simple:
Todas las instrucciones ocupan un solo ciclo de reloj. Dejo fuera de la siguiente discusión el sistema de E/S. La arquitectura de TOY-8 especifica que la dirección de memoria 0xF (15) está mapeada a la E/S y basta con escribir o leer de esta dirección de memoria para leer de o imprimir datos a un periférico, un byte a la vez.
La ALU opera sobre números de 8 bits. Tiene dos entradas A y B, la primera conectada a R y la segunda a la memoria. El resultado de la operación entre A y B es su única salida y va conectada a R. Cuando tenemos este tipo de esquema con un solo registro de propósito general en la CPU decimos que tenemos una arquitectura de acumulador. El acumulador sería el registro R.
Los otros dos registros son el contador de programa que indica la dirección de la próxima instrucción del programa, y el registro IR (instruction register) que guarda la instrucción que se está ejecutando para que la unidad de control la decodifique y ejecute. Parte de IR va conectado al bus de direcciones para indicar direcciones de memoria y los últimos 3 bits (contando de izquierda a derecha) van conectados a la unidad de control ya que indican el opcode. El PC va conectado también al bus de direcciones durante la fase de fetch. Un multiplexor elige el valor correcto para el bus de direcciones de IR o del PC según la fase del ciclo de instrucción.
El otro multiplexor de la CPU está ubicado antes de la entrada de R, porque hay tres fuentes posibles para R: la ALU, IR (en load address
) y la memoria (en load word
).
La unidad de control tiene tres entradas y ocho salidas.
bze
.halt
que se usa para parar el reloj y toda la computadora.La entrada de tres bits del opcode va conectada internamente a un decodificador 3:8 y sumado a la entrada de reloj formando un demultiplexor se activan las señales correctas en las dos fases del ciclo de instrucción. La unidad de control es un circuito combinacional.
Veamos un ejemplo, tenemos el siguiente programa que suma los números en M[5]
y M[6]
y pone el resultado en M[7]
. La primer instrucción está en M[1]
Entre paréntesis traduzco a ensamblador.
a5 (lw 5)
26 (add 6)
c7 (sw 7)
00 (halt)
03 (dato)
02 (dato)
00 (dato)
a5
en ese registro.M[5]
se guarda en R.26
en IR.add 6
, por lo tanto la unidad de control indica a la ALU que realice una suma con lo que está en R y en M[6]
. El resultado se guarda en R.C7
en IR.sw 7
, la unidad de control indica a la memoria que guarde el dato que se encuentra en R en la dirección de memoria 7.00
en IR.halt
, la unidad de control enciende la señal que frena el reloj y la CPU se detiene. Si examinamos la memoria tenemos un 5 en la dirección de memoria 7 como es de esperarse.Les dejo un programa para que prueben en la computadora en el Logisim, recuerden que el código arranca en la dirección de memoria 0x1, porque la 0x0 siempre vale cero por diseño.
a0
ce
af
e9
2e
ce
a0
e3
ae
cf
00
El programa suma los números en la entrada estándar hasta que se ingrese un cero. Luego muestra la suma en la salida.
Escrito el 22 de Junio de 2020 por Santiago Trini