






















Prepara tus exámenes y mejora tus resultados gracias a la gran cantidad de recursos disponibles en Docsity
Gana puntos ayudando a otros estudiantes o consíguelos activando un Plan Premium
Prepara tus exámenes
Prepara tus exámenes y mejora tus resultados gracias a la gran cantidad de recursos disponibles en Docsity
Prepara tus exámenes con los documentos que comparten otros estudiantes como tú en Docsity
Encuentra los documentos específicos para los exámenes de tu universidad
Estudia con lecciones y exámenes resueltos basados en los programas académicos de las mejores universidades
Responde a preguntas de exámenes reales y pon a prueba tu preparación
Consigue puntos base para descargar
Gana puntos ayudando a otros estudiantes o consíguelos activando un Plan Premium
Comunidad
Pide ayuda a la comunidad y resuelve tus dudas de estudio
Ebooks gratuitos
Descarga nuestras guías gratuitas sobre técnicas de estudio, métodos para controlar la ansiedad y consejos para la tesis preparadas por los tutores de Docsity
Asignatura: Introducció als Computadors, Profesor: , Carrera: Enginyeria Informàtica, Universidad: UPC
Tipo: Ejercicios
Subido el 22/11/2017
1 / 30
Esta página no es visible en la vista previa
¡No te pierdas las partes importantes!























Antes de realizar la práctica Antes de preparar esta práctica se deben haber estudiado las secciones de la documentación señaladas.
Secciones de la documentación a estudiar antes de preparar la práctica
Capítulo 9 completo. Entrada/salida Capítulo 10 completo. Unidad de control general Capítulo 11 completo. Memoria Capítulo 13 completo. Computador SISC Von Neumann Capítulo 14 completo. Lenguaje máquina y ensamblador SISA
Algunos objetivos implícitos en estos capítulos de la documentación serán evaluados en el informe previo que debéis entregar al inicio de la sesión de laboratorio y en la prueba previa individual que se hará al inicio de la sesión. Aunque las cinco primeras preguntas del informe previo sirven para repasar lo que se preguntará en la prueba previa, dejamos a vuestro criterio el número de apartados a contestar en cada pregunta. Sin embargo, sí que exigiremos que respondáis a las preguntas 6 a 10 del informe previo para poder realizar la práctica en el lab ya que es imprescindible para poder realizar el informe final, aunque sobre esto no preguntaremos nada directamente en la prueba previa.
Objetivos que se deben alcanzar al realizar la práctica Después de realizar esta práctica, además de haber mejorado el nivel de consecución de los objetivos necesarios para preparar la práctica y de los objetivos de la práctica anterior relativos al manejo del programa LogicWorks, el alumno será capaz de:
Directorio de la práctica Aularios en módulo A5 y C6: Mi PC\I:\ic\Prac Aularios en el módulo D6: Mi PC\R:\Logic\Ver_4.1\Ic\Prac
Ya hemos trabajado con la multiplicación durante las prácticas anteriores: En la práctica 3 realizasteis en hardware (con el simulador LogicWorks) un Procesador de Propósito Específico para multiplicar dos números naturales codificados en binario con 16 bits, En la práctica 4 realizasteis el multiplicador usando la unidad de proceso general, UPG, y diseñasteis la unidad de control específica para que funcionara como en la práctica 3.
En esta práctica os damos construido el computador SISC. Es un computador Von Neumann: tanto las instrucciones del programa a ejecutar como los datos están almacenados en una única memoria RAM. Ejecuta programas en lenguaje máquina SISA (la versión completa del lenguaje con sus 25 instrucciones de 16 bits). El computador es multiciclo, las instrucciones de acceso a memoria tardan 4 ciclos en ejecutarse mientras que el resto tardan 3 ciclos, con un tiempo de ciclo de 1.400 u.t.
En el lenguaje máquina SISA no hay ninguna instrucción para multiplicar dos números naturales. Las únicas operaciones aritméticas que se pueden realizar directamente ejecutando una sola instrucción son suma, resta, multiplicación y división por potencias de 2 y algunas comparaciones. Así pues, si se desea multiplicar dos números tenemos dos posibilidades: añadirle al computador un co-procesador hardware para multiplicar (podría ser el PPE de las prácticas 3 o 4 con un controlador para conectarlo al SISC), o lo que es más económico, escribir un pequeño programa, que usando las instrucciones disponibles en SISA, calcule la multiplicación de dos números. Esta segunda solución es la que desarrollamos en esta práctica.
Como objetivo principal de esta práctica escribiréis, en el informe previo, un algoritmo equivalente al que ya diseñasteis dibujando un grafo de estados e implementasteis en hardware formando la unidad de control específica del PPE de la práctica 3 (con una unidad de proceso específica) y en la primera parte de la práctica 4 (con la unidad de proceso general). Luego, escribiréis y ejecutaréis en el laboratorio un algoritmo que es una optimización del primero que consigue, en muchos casos, multiplicar en menos ciclos. Este algoritmo, de terminación temprana, es el que usasteis para implementarlo en la UPG en la segunda parte de la práctica 4. Como veis, esta práctica es muy parecida a la 4 y muchos de los ejercicios son parecidos a los de la práctica 4, pero en vez de diseñar un grafo de estados para una unidad de control específica para la UPG, escribiremos un programa en el lenguaje SISA que luego cargaremos en la memoria del computador SISC para su ejecución. La siguiente figura muestra el esquema a bloques del computador SISC.
Simple Instrucction Set Computer SISC
MUX
10
1, 700,
REGFILE
D
A
@B B
@D
@A
WrD
MUX
10
REG REG
OUTPUT
INPUT/
Wr-Out
ADDR-IO
WR-OUT
RD-IN
(Key-Print)
Rd-In
Ld REG
MUX
10
(^0) MUX 1
Ld REG
0 0 0 0
8 2 F E
0 0 0 0
0 0 0 9
0 0 0 0
0 0 0 0
0 0 0 0
A 2 0 0
F E
0 7 0 0 0 2 F E
0 0 0 0
REG
03210 b1 (^1) MUX
b
(^1 3 1 0 40 0 0 0 0 1 10 1 )
1
X (^) Y
ALU
OP z
F
@A@BRy/NF @DWrD I
SISC CONTROL UNIT
Rd-InWr-Mem
z
Pc/RxOPP/I/L/AWr-OutLdIrLdPcByteAlu/R@R@/PcNADDR-IO
Wr-Mem
ADDR-MEM
WR-MEM
RD-MEM
Byte
64K bytes MEMORY
0
1
z
z
z
Pc/Rx
Pc/Rx
Pc/Rx
WrD
WrD
WrD
Wr-Out
Wr-Out
Wr-Out
Wr-Mem
Wr-Mem
Wr-Mem
Rd-In
Rd-In
Rd-In
Clk
Clk
Clk
Clk
Clk Clk
Clk
Clk
Alu/R@
Alu/R@
Alu/R@
Ry/N
Ry/N
Ry/N
R@/Pc
R@/Pc
R@/Pc
LdPc
LdPc
LdPc
Byte
Byte
0 0 00 0 00 0 Byte
LdIr
LdIr
LdIr
RD-IN
RD-IN
ALU ALU
RX
RX
R@
R@
ADDR-MEM
N
N
N
@B
@B
@B
F
F
F
OP
OP
OP
P/I/L/A
P/I/L/A
P/I/L/A
@A
@A
@A
@D
@D
@D
RD-MEM
RD-MEM
PC+
PC+
PC
PC
IR IR
RY
RY
ADDR-IO
ADDR-IO
ADDR-IO
ADDR-IO
Especificad en lenguaje ensamblador cada una de las siguientes instrucciones que os damos en lenguaje máquina SISA (notación hexadecimal). Indicad como “instrucción no válida” las instrucciones cuyo código no corresponda con ninguna instrucción del SISA (os damos ya contestadas las dos primeras filas de la tabla):
Lenguaje máquina (hexa)
Lenguaje máquina (L.M.) (binario)
Lenguaje ensamblador
0x20C3 0010000011000011 ADDI R3, R0, 3 0x1052 0001000001010010 Instrucción no válida 0x0FCF 0x 0x 0x 0xA4B 0x9DF 0x80AF 0x1FF
Se define el estado del computador como el contenido de todas las posiciones de la memoria (de datos e instrucciones en el SISC), de los 8 registros generales del computador (R0…, R7), de todos los puertos (registros) de entrada/salida y del contador de programa, PC. El estado del computador es la “memoria” del computador. La ejecución de una instrucción produce una modificación del estado del computador. La ejecución de un programa puede verse como una secuencia de modificaciones del estado del computador.
Con esta definición queda claro que no forman parte del estado del computador los registros intermedios que mantienen información entre ciclos/fases de la ejecución de una instrucción en el computador SISC. Así, el contenido de IR, RX, RY o R@ no forman parte del estado del computador ya que cuando empieza la ejecución de una nueva instrucción, al inicio de la fase F, no importa el valor que tengan estos registros: no pasan información de una instrucción a otra.
Suponemos que el estado del computador antes de iniciar la ejecución de cada una de las instrucciones (cada uno de los apartados) de esta pregunta es el siguiente: La palabra (16 bits) de memoria cuya dirección del byte de menos peso es k contiene el valor k, MEM w[k] = k, para 0 2 1
15
k .
k
0x0001. El contenido del registro PC vale 0x00AE. El valor de los puertos de entrada/salida no lo especificamos, pues no es necesario en el ejercicio que vamos a hacer.
Suponiendo que la instrucción que aparece en cada uno de los apartados de este ejercicio se encuentra en la dirección 0x00AE de la memoria y que el estado del computador antes de la ejecución de la instrucción es el que se ha especificado anteriormente, ¿cuánto vale el estado del computador después de la ejecución de la instrucción? Sólo tenéis que especificar los cambios ocurridos en el estado del computador tras la ejecución de la instrucción. Los registros y posiciones de memoria que no se modifiquen no deben especificarse. (Los dos primeros apartados los hemos completado nosotros, como muestra). Para especificar el valor del byte de memoria cuya dirección es k usad al notación MEM b [k] = ….
a) ADDI R3, R1, 7 Respuesta: R3 = 8 // PC = 0x00B b) ADD R3, R4, R Respuesta: R3 = 1 // PC = 0x00B c) BNZ R3, - d) SHL R7, R7, R e) SHA R7, R7, R f) CMPLEU R5, R7, R g) CMPEQ R5, R7, R h) BZ R1, - i) ADDI R3, R3, - j) AND R5, R1, R k) LD R2, 30(R5) l) STB 3(R0), R m) ST -26(R5), R
En la práctica 5 os acostumbrasteis a especificar la unidad de control de propósito específico que gestiona las acciones sobre la UPG mediante un grafo de estados. En este grafo el estado siguiente (secuenciamiento) se indica con los arcos que salen de cada nodo y la palabra de control mediante mnemotécnicos.
En el tema 10 creamos la unidad de control general, que ejecuta instrucciones SISA, de 16 bits cada una. Después creamos los computadores Harvard uniciclo y multiciclo y ahora el SISC Von Neumann. La única forma de especificar lo que debe hacer nuestro computador es mediante un programa en lenguaje máquina SISA. La unidad de control del SISC se encargará de generar en cada uno de los ciclos de ejecución de cada instrucción la palabra de control a partir de la instrucción SISA que se está ejecutando.
El hecho de haber tenido que compactar la información de cada nodo del grafo de estados (secuenciamiento y palabra de control) en sólo 16 bits hace que lo que antes se podía hacer en un solo ciclo, en un nodo, ahora requiera, en algunos casos, más de una instrucción SISA (y más de tres o cuatro ciclos que es lo que tarda en ejecutarse una instrucción SISA en el SISC). Es muy importante que tengáis claro esto, ya que para implementar el algoritmo de multiplicación en esta práctica, vamos a partir del grafo que hicisteis en al práctica anterior. Vamos a ejercitar, en general, este paso, antes de programar la multiplicación.
Escribid en lenguaje ensamblador SISA, para cada apartado/fila de la siguiente tabla, un pequeño fragmento de programa que realice la misma funcionalidad que el fragmento de grafo que se especifica. El grafo es el grafo de estados de la unidad de control de propósito específico que genera la palabra de control para la UPG + IO (^) key-Print + Mem. El grafo se especifica mediante nodos y arcos (para el secuenciamiento) y mnemotécnicos (para la palabra de control que indica las acciones sobre la UPG + IO (^) key-Print + Mem). A la derecha de cada fila de la tabla se han reservado unas líneas (sombreadas) para poner las instrucciones SISA, pero esto no quiere decir que cada fragmento de programa deba ocupar todas las líneas reservadas.
a)
Escribid un fragmento de código ensamblador SISA que implemente cada una de las sentencias siguientes, que se especifican en pseudo C (considerad que los tipos de datos que hay en los registros y memoria son números enteros codificados en complemento a 2 con 16 bits) y que el vector de números enteros V está almacenado a partir de la dirección de memoria 0x1000. Recordad que cada índice i del vector V hace referencia a un elemento del vector y cada elemento ocupa dos bytes en direcciones consecutivas de memoria y formato Little Endian. Así, el byte de menor peso de V[3] está almacenado en la dirección de memoria 0x1006 y el de más peso en la 0x1007.
a) R4 = 0; b) V[R2] = R3 * 2; c) V[10] = V[R2 + 3]; d) if (R3 <= R1) R3 = R1 – 1; e) if (R1 >= 320) R2 = R2 + R2; else R5 = R2 + R5; f) for (R2 = 3; R2 <= R5; R2 = R2 + 1) { V[R1 + R2 + 25] = 0; } g) for (R3 = 0; R3 < 16; R3 = R3 + 1) { V[R3 + R2] = 0; }
Ahora que ya hemos practicado el lenguaje SISA, vamos a programar el computador basado en el SISC, con un algoritmo para multiplicar dos números naturales.
Enunciado del problema
Suponiendo que el vector de bits X que representa al multiplicando X (^) u se encuentra inicialmente en el
registro R6 del procesador y que el vector de bits Y que representa al multiplicador Yu se encuentra en
R7, escribir un programa en ensamblador del SISA que deje los 16 bits de menor peso del resultado de la
multiplicación de X (^) u por Yu en el registro R5. No hay que detectar el caso de desbordamiento, esto es,
el caso en el que el resultado de la multiplicación no puede representarse correctamente en 16 bits.
En la práctica 3 obtuvimos un algoritmo que calcula en 16 ciclos la multiplicación de los números
naturales X (^) u e Yu y lo implementamos en LogicWorks como un procesador de propósito específico.
Este algoritmo, expresado en un lenguaje de alto nivel, suponiendo que los operandos X (^) u e Yu se
encuentran almacenados en los registros R6 y R7 respectivamente y el resultado se obtiene en R5 se muestra a continuación. Se han omitido los subíndices u en los registros que indicarían que interpretamos los vectores de bits en ellos contenidos como números naturales codificados en binario. Recordad que
Algoritmo MUL16 en alto nivel
R5 = 0;
if (R7<0> == 1) R5 = R5 + R6; R6 = R6 * 2; R7 = R7 / 2;
En la práctica 5, a partir del algoritmo anterior, diseñamos la unidad de control de propósito específico para que la UPG ejecutara el algoritmo MUL16. El grafo de estados resultante se muestra a continuación. La palabra de control que genera en cada ciclo la unidad de control para que la UPG realice las acciones pertinentes se especifica con mnemotécnicos. La variable j del algoritmo, que hace de contador del
a 16, entrando en el bucle sin preguntar si hay que ejecutarlo, haciendo el cuerpo del bucle,
forma de hacer es un poco más eficiente, y se puede escribir en un lenguaje de alto nivel así:
Algoritmo MUL16 en alto nivel con do_while R5 = 0; R2 = 16;
if (R7<0> == 1) R5 = R5 + R6; R6 = R6 * 2; R7 = R7 / 2; R2 = R2 – 1;
Grafo de estados para ejecutar en la UPG el algoritmo MUL
Ahora con la experiencia de los ejercicios que hemos hecho hasta ahora en el informe previo, podemos escribir el algoritmo MUL16 en el lenguaje ensamblador SISA. Para ello, podemos partir del algoritmo en alto nivel o del grafo de estados que hemos visto en los apartados anteriores.
Completad el siguiente código escrito en lenguaje ensamblador SISA para que implemente el algoritmo MUL16. Se muestran algunas instrucciones o parte de ellas así como los comentarios, para ayudar en el proceso.
Además de rellenar la tabla, responded a las siguientes preguntas: a) ¿Cuántos ciclos tarda en ejecutarse el código completo en el computador SISC?
b) ¿Cuál es el estado del computador (el valor de los registros del procesador que se han modificado) después de ejecutarse el código completo?
Modificad adecuadamente el algoritmo MUL16 en SISA que obtuvimos en la sección 6.3.3 para que no tengan que ejecutarse siempre 16 iteraciones del bucle. Cuando Y, la representación en binario del multiplicador, tenga k ceros en las posiciones de mayor peso, debemos ahorrarnos las últimas k iteraciones del algoritmo. Esto es posible porque el resultado parcial de la multiplicación que se encuentra en R5 al final de la iteración n-1-k ya es el definitivo (numerando las iteraciones de 0 a n -1 con n = 16). Si continuáramos con el algoritmo sumariamos un 0 a R5 en cada nueva iteración y esto no modifica R5. El algoritmo resultante lo denominamos “ con terminación temprana ” y lo denotamos como MUL. Es equivalente al grafo de estados de la unidad de control de propósito específico que obtuvimos en la práctica 5 para multiplicar con la UPG. Completad el siguiente código escrito en lenguaje ensamblador SISA para que implemente el algoritmo MUL. Se muestran algunas instrucciones o parte de ellas así como los comentarios o parte de ellos, para ayudar en el proceso.
Algoritmo MUL en ensamblador SISA
Seguid la ejecución del algoritmo MUL con las mismas suposiciones usadas en la pregunta 7 del informe previo para el algoritmo MUL16 excepto que ahora en el ciclo 0 el registro R6 contiene el vector de bits 0x0081 y R7 el 0x0005. En este caso nosotros hemos rellenado completamente solo la primera fila.
Ciclo Fetch
Instrucción en ensamblador que se va a ejecutar
Estado de los registros, en el ciclo en que se hace el Fetch de la instrucción (en hexadecimal) PC R0 R1 R2 R3 R4 R5 R6 R 0 MOVI R5, 0 000C XXXX XXXX XXXX XXXX XXXX XXXX 0081 0005 3 MOVI R1, 1
Además de rellenar la tabla, responded a las siguientes preguntas: a) ¿Cuántos ciclos tarda en ejecutarse el código completo en el SISC?
b) ¿Cuál es el estado del computador (el valor de los registros del procesador) después de ejecutarse el código completo?
El algoritmo de multiplicación que hemos diseñado podría incrustarse en un programa más complejo. Cada vez que se deseara multiplicar dos números, sólo habría que cargar los números en R6 y R7, copiar el código de la multiplicación y saber que tenemos el resultado en R5.
No obstante, en esta práctica vamos a usar el computador como una máquina de multiplicar, que siempre hace lo mismo. Como dispositivo de entrada de datos al computador tenemos un teclado que el computador ve a través del registro de datos KEY-DATA (puerto 0 de entrada) y del registro de estado KEY-STATUS (puerto 1 de entrada). Como dispositivo de salida tenemos una impresora cuyo controlador
dispone de los puertos PRINT-DATA (puerto 0 de salida) y PRINT-STATUS (puerto 2 de entrada). Una lectura por parte del procesador sobre el puerto KEY-DATA (con la instrucción IN R5, KEY-DATA, por ejemplo) tiene un efecto lateral que hace que se ponga a cero el registro de estado del controlador del teclado, KEY-STATUS. De forma equivalente, una escritura sobre PRINT-DATA (con OUT PRINT-DATA, R5, por ejemplo) pone a cero PRINT-STATUS. El subsistema de entrada/salida del computador implementado en LogicWorks, con el teclado y la impresora, se muestran en la siguiente figura.
Antes de completar nuestro algoritmo de multiplicación con la entrada de operandos por el teclado y la salida del resultado por la impresora, repasemos el funcionamiento de estos dispositivos mediante un programa de ejemplo, que nada tiene que ver con la multiplicación de dos números. Además, con este programa de ejemplo, aprenderemos a cargarlo en la memoria del SISC y a ejecutarlo paso a paso.
Programa de ejemplo: KEY_MEM_PRINT
El programa KEY_MEM_PRINT, que presentamos codificado en SISA, hace lo siguiente. Lee del teclado N datos (con N menor de 32), donde cada dato es un byte, los guarda en memoria en un vector y luego los imprime y esto se repite indefinidamente. Para que el computador sepa el valor de N, el primer dato que se entra por el teclado es el número N, y a continuación se entran los N datos que queremos imprimir. Los N datos se almacenan en un vector que comienza en la dirección 0xFFE0 de memoria (podría ser cualquier otra dirección, con un pequeño cambio del código). Una vez entrados todos los datos se imprimen en el mismo orden en que se entraron. Se considera que N es un número entero y cada uno de los N datos son enteros codificados en 8 bits. En el display de la impresora se verá cada dato (byte) en 16 bits, previa extensión del bit de signo (bit 7). Terminada la impresión el programa vuelve al inicio repitiéndose el proceso indefinidamente.
WHILE-1: CMPLTU R2, R0, R1 ; while (r0 < r1) { BZ R2, FI-WHILE-
POLLING-2: IN R3, KEY-STATUS BZ R3, POLLING- IN R3, KEY-DATA ; dato leido del teclado
STB -32(R0), R3 ; almacena a partir de la dir. 0xFFE
ADDI R0, R0, 1 ; incrementa indice BNZ R2, WHILE-1 ; } ; Comienza la lectura de datos de FI-WHILE-1: ; memoria y su impresión MOVI R0, 0 ; inicializa indice de bucle y vector
WHILE-2: CMPLTU R2, R0, R1 ; while (r0 < r1) { BZ R2, FI-WHILE-
LDB R3, -32(R0) ; lee dato de memoria
POLLING-3: IN R4, PRINT-STATUS ; Input port 2 BZ R4, POLLING-3 ; espera a printer lista OUT PRINT-DATA, R3 ; Output port 0
ADDI R0, R0, 1 ; incrementa indice BNZ R2, WHILE-2 ; } FI-WHILE-2: BZ R2, BEGIN ; ir a BEGIN, bucle infinito
Como vamos a ejecutar este código en el SISC implementado en LogicWorks, tenemos que pasarlo a lenguaje máquina SISA. Esto lo hemos hecho nosotros pero es muy conveniente que lo hagáis vosotros a modo de ejercicio. Mostramos en tres columnas: el código ensamblador, el código binario (en lenguaje máquina) pero separando los campos de la instrucción según su formato (3R, 2R o 1R) para ver con más claridad su codificación y el código en hexadecimal.
Ensamblador SISA binario SISA Hexa POLLING-1: IN R1, KEY-STATUS 1010 001 0 00000001 A BZ R1, POLLING-1 1000 001 0 11111110 82FE IN R1, KEY-DATA 1010 001 0 00000000 A
Cargar la memoria RAM del SISC con el programa en lenguaje máquina
Ahora, en el laboratorio, vais a escribir en la memoria RAM del SISC el programa en lenguaje máquina para pasar luego a ejecutarlo ciclo a ciclo.
Resumiendo y simplificando la realidad, lo que ocurre cuando un usuario quiere ejecutar un programa, que está escrito en lenguaje máquina en un fichero en el disco del computador es lo siguiente. El sistema operativo (un programa que está ya cargado en memoria ejecutándose, o al menos parte de él) se encarga de leer el programa del disco y copiarlo, cargarlo, en una zona de memoria que no esté ocupada por el sistema operativo y acto seguido pasar a ejecutar la primera instrucción del programa (cargando en el PC la dirección de memoria a partir de la que el sistema operativo cargó el programa en lenguaje máquina). Pero nuestro computador no tiene sistema operativo ni disco donde está el programa en lenguaje máquina. Por ello, lo que vamos a hacer a continuación para cargar el programa en memoria no es lo usual: usaremos las facilidades del simulador de circuitos, LogicWorks, que nos permite hacerlo con cierta comodidad.
Para cargar el programa en la memoria del SISC tenemos que tener el programa en lenguaje maquina (más en concreto, en formato “raw hex file” para que lo entienda el LogicWorks) repartido en dos ficheros con extensión .hex. Cada fichero se escribirá en uno de los dos módulos de memoria de 32KB que forman la memoria del computador. El fichero que contiene la secuencia de los bytes de menor peso de cada instrucción del programa (cada byte expresado por dos dígitos hexadecimanles) se llama Byte-0-KEY- MEM-PRINT.hex y su contenido en hexadecimal es:
01 FE 00 00 54 06 01 FE 00 E0 01 F8 00 54 06 E0 02 FE 00 01 F8 EA
El fichero que contiene los bytes de mayor peso se llama Byte-1-KEY-MEM-PRINT.hex y su contenido es: A2 82 A2 90 10 84 A6 86 A6 60 20 85 90 10 84 50 A8 88 A7 20 85 84
La separación entre cada pareja de dígitos hexadecimales puede ser un espacio, como se muestra, una coma, un cambio de línea…
Ambos ficheros se encuentran en la carpeta de esta práctica (así no tenéis que crearlos vosotros y hay menos probabilidades de error).
Observad que cada instrucción se almacena en memoria en formato Little endian. Por ejemplo, la primera instrucción del programa (16 bits = 2 bytes), 1010001000000001 o A201 en hexadecimal, que se ha de cargar en la dirección 0 de la memoria, tiene el byte de menor peso, 01, en la primera posición del fichero cuyo contenido se deberá grabar en el módulo 0 de la memoria y el byte de más peso, A2, en la primera posición del fichero que ha de escribirse en el módulo 1.
Para escribir el programa en el bloque de memoria (MEM-64KB-32KW.cct) que se encuentra en el SISC, en el circuito LogicWorks denominado SISC-w-Display-wo-Prog.cct (SISC con diaplays y sin programa almacenado en la memoria) que está en la carpeta de esta práctica, se tiene que tener el circuito SISC y la librería LibPrac5, que también está en la carpeta, copiados en el escritorio para que se puedan modificar ya que el disco donde está la carpeta está protegido contra la escritura.
El procedimiento para escribir el programa en la memoria RAM del computador es:
Vamos a ir ejecutando ciclo a ciclo el programa KEY_MEM_PRINT haciendo clic en el binary switch que hace de reloj y además vamos a teclear los datos en el teclado y a hacer manualmente la parte del protocolo del controlador del teclado y la impresora. Rellenad la siguiente tabla con el resultado de la ejecución del código instrucción a instrucción, para las 10 primeras instrucciones que se ejecutan. Solo hay que apuntar en la tabla el contenido de los registros en el ciclo de Fetch de cada instrucción (al estilo de lo que hicisteis en las preguntas 7 y 9 del informe previo). Aunque esté código sí que modifica algunos puertos de E/S y algunos bytes de memoria no incluimos estos elementos del estado del computador dentro de la tabla que deberéis rellenar. Explicamos, a continuación, los primeros ciclos de ejecución del programa que se encuentra almacenado a partir de la dirección 0x0000 de memoria.
Ciclo 0. Haced reset del sistema, pues es necesario ya que hemos cambiado la memoria de instrucciones. Poned a correr la simulación a máxima velocidad. Observad que el contenido de todos los registros se ha puesto a 0 debido al reset. Además, en los displays del SISC podemos ver que el PC vale 0 y que efectivamente se está leyendo la instrucción 0 de nuestro programa, 0xA201 (IN R1, 1 ), lo que se ve en el display del bus RD-MEM. Este es el ciclo de Fetch, F (se ve en la ventana de la unidad de control en el visualizador del estado E=00), de la primera instrucción del programa, por lo que deberíais apuntar los contenidos de los registros en la primera fila de la tabla, pero en este caso no hace falta porque ya lo hemos hecho nosotros. Podéis aprovechar esta ejecución ciclo a ciclo para ver otras cosas que no hay que anotar en la tabla pero que ocurren en cada ciclo de la ejecución de cada instrucción. Por ejemplo, como este es el ciclo de Fetch de una instrucción, sea cual sea, pues todavía no está decodificada, en la ALU se calcula PC+2 y por eso la salida de la ALU vale 0x0002, cosa que se ve en el visor del bus ALU.
Ciclo 1. Este es el ciclo de decodificación de la instrucción 0xA201 (E=01, D). No hay que escribir nada en la tabla. En este ciclo ya se ve en el IR la instrucción que estaba en RD-MEM en el ciclo anterior. IMPORTANTE para este ejercicio : para no perder tiempo en el primer bucle de la encuesta del teclado debéis cargar el valor de N en el registro de datos de la impresora en este momento para que cuando se lea el registro de estado en el ciclo siguiente ya esté a 1 y salgamos del bucle del polling a la primera iteración. Para ello, poned en el teclado hexadecimal del bloque de E/S 0x0001 (entraremos una secuencia de un dato, para tardar poco en ejecutar todo el programa) y haced clic en el switch del teclado para se consiga cargar 0x0001 en el puerto 0 (KEY- DATA) y poner a 1 uno el puerto 1 (KEY-STATUS). El bit de menor peso de la salida de KEY- STATUS se ve en el visor, y ahora ya se ve a 1. Volved a hacer clic en el switch para dejarlo a 0. Podéis ver, aunque no hay que apuntarlo todavía en la tabla, que en este ciclo ya se ve que el PC vale 0x0002 ya que al final del ciclo anterior se cargó el PC con este valor que había calculado la ALU. También se ve que en este ciclo el IR contiene la primera instrucción del programa (0x A201) que se fue a buscar a memoria en el ciclo anterior.
Ciclo 2. En este ciclo se ejecuta propiamente la instrucción IN R1, KEY STATUS (Estado E=0F, In). Ya puede verse el 0x0001 del KEY-STATUS que se está leyendo en este ciclo en el display del bus RD-IN, que al final del ciclo se cargará en R Podéis ver que como en todos los ciclos de decodificación se calcula en la ALU el valor PC+SE(N8)*2 que se almacenará al final de este ciclo e R@, para ser usado solo si estamos ejecutando una instrucción de salto y el salto es tomado. Este valor calculado, que se muestra en el visor del bus ALU no se usará al ciclo siguiente porque no se está ejecutando una instrucción de salto. No obstante podéis comprobar que el cálculo que hace la ALU es el correcto.
Ciclo 3. Ciclo de búsqueda (E=00, F) de la segunda instrucción del programa (0x82FE, BZ R1, POLLING-1). Ya se ve el 0x0001 en R1 que cargo la instrucción anterior al final del ciclo anterior. Como es un ciclo de Fetch hay que apuntar en la tabla el valor de los registros en la tabla: PC = 0x0002 y R1 = 0x0001.
Ciclo 4. Ciclo de decodificación (E=01, D) de la instrucción de salto. No hay que anotar nada. Ahora sí que podría usarse al ciclo siguiente lo que calcula la ALU, que se cargará al final del ciclo en R@, ya que sí que se está ejecutando una instrucción de salto.
Ciclo 5. Ciclo de ejecución del BZ R1, POLLING-1 (E=0B, Bz). No hay que apuntar nada en la tabla. Pasando a pantalla completa la ventana del SISC se ve, en la parte inferior encima de los visores de la palabra de control que z vale 1 en este ciclo. Esto es así porque R1 no vale cero y la ALU deja pasar R que vale 0x0001 y esto hace que z valga 0 y por tanto LdPc vale 0 (como se ve en la palabra de control, en la parte inferior del circuito SISC) para que no se cargue el PC al final de este ciclo con la dirección de salto tomado que se encuentra en R@ (que como se ve es 0x000) si no que se vaya a buscar al ciclo siguiente la que indica el PC en este ciclo, que como puede verse es la 0x0004: No se rompe la secuencia, por lo que PC = 0x0004, como muestra el visor.
Ciclo 6. Búsqueda de la instrucción que indica el PC. La instrucción que está en la dirección contenida en el PC, 0x0004, ya se ve en el bus RD-MEM y es la 0xA200. ….
Continuad vosotros solos ciclo a ciclo, anotando solo el contenido del PC y del registro modificado por la instrucción anterior (si se modifica alguno) en cada ciclo de Fetch de cada instrucción. Cuando se ejecute una instrucción IN Rd, KEY-STATUS, escribid el dato en el teclado hexadecimal y haced clic en el binary switch (para producir un flanco ascendente, cargar el dato en el KEY-DATA y poner a 1 KEY-STATUS) en el ciclo de Decodificación de la instrucción IN, como se hizo en el ciclo 1, para que el bucle de la encuesta se pase en la primera iteración. Entrad como primer dato 0x000F.
Ciclo Fetch
Instrucción en ensamblador que se va a ejecutar
Estado de los registros, en el ciclo en que se hace el Fetch de la instrucción (en hexadecimal)
Aunque sólo hay que apuntar hasta las 10 primeras instrucciones en la tabla, podéis seguir ejecutando paso a paso el algoritmo completo, hasta sacar por la impresora al menos el primer dato entrado y almacenado en memoria.
Para comprobar el funcionamiento del programa KEY_MUL_PRINT vamos a ejecutar ciclo a ciclo del código cargado en memoria y a anotar, en cada ciclo de Fetch de las 20 primeras instrucciones que se ejecuten, la parte del estado del computador que nos piden en la siguiente tabla, como hicisteis con el código KEY_MEM_PRINT en la pregunta 1 del informe final.
Teclead el valor 0x0081 y cargadlo en el registro KEY-DATA lo antes posible y lo mismo para el valor 0x0005 con el objetivo de que en los dos bucles de encuesta del teclado se lea el dato en la primera iteración. Lo mismo para la salida del resultado por la impresora: cuando se haga ejecute la instrucción IN del registro de estado esté valga 1.
Si el código no funciona correctamente a la primera, con este seguimiento podéis detectar los errores. Posiblemente hayáis codificado mal alguna instrucción. El paso de ensamblador a lenguaje máquina es muy engorroso y es fácil cometer errores. Arreglad el error en los ficheros .hex, volver a cargar el programa en la memoria y volvedlo a intentar.
Muy importante : como la memoria del SISC es RAM si hay algún error en el código puede escribirse la memoria en posiciones indeseadas y puede modificarse el programa (puede que se llene el computador de X). Si se os llena de X sin saber el motivo no podréis reproducir la situación haciendo Reset , ya que la memoria, el programa almacenado, se ha podido borrar, llenar de X, modificar…). La única forma de reproducir la situación consiste en cambiar la memoria actual del SISC (que se ha podido llenar de X) por el dispositivo que guardasteis con el código almacenado, 64KBMEM_KEY_MUL_PRINT, hacer Reset y empezar el ejercicio otra vez.
Ciclo Fetch
Instrucción en ensamblador que se va a ejecutar
Estado de los registros, en el ciclo en que se hace el Fetch de la instrucción (en hexadecimal) PC R0 R1 R2 R3 R4 R5 R6 R 0 0000 3
Además de rellenar la tabla, responded a la siguiente pregunta: ¿En qué ciclo se ve el resultado de la multiplicación en PRINT-DATA para los operandos que hemos entrado y para los ciclos en los que los hemos entrado?
Cuando estéis seguros del correcto funcionamiento del programa KeyPrintMUL , avisad al profesor de laboratorio y pedidle que revise vuestro trabajo y firme en el informe final.
Indicad si realizasteis correctamente el programa KeyPrintMUL de la pregunta 10 del informe previo. En caso de, al ejecutar en el laboratorio el programa PrintKeyMUL hayáis detectado algo incorrecto en vuestra respuesta a la pregunta 10 del informe previo, aunque en el lab el profesor os haya cambiado los registros R5, R6 y R7 por otros, decid qué es incorrecto en vuestra respuesta a la pregunta 10 del informe previo, y por qué es incorrecto.