Docsity
Docsity

Prepara tus exámenes
Prepara tus exámenes

Prepara tus exámenes y mejora tus resultados gracias a la gran cantidad de recursos disponibles en Docsity


Consigue puntos base para descargar
Consigue puntos base para descargar

Gana puntos ayudando a otros estudiantes o consíguelos activando un Plan Premium


Orientación Universidad
Orientación Universidad


Practica 5 ic, Ejercicios de Introducción a los Ordenadores

Asignatura: Introducció als Computadors, Profesor: , Carrera: Enginyeria Informàtica, Universidad: UPC

Tipo: Ejercicios

2016/2017

Subido el 22/11/2017

usuario desconocido
usuario desconocido 🇪🇸

1 / 30

Toggle sidebar

Esta página no es visible en la vista previa

¡No te pierdas las partes importantes!

bg1
1
PRÁCTICA 5
Introducción al lenguaje máquina y ensamblador SISA.
Implementación de algoritmos de multiplicación en el
computador SISC.
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 p ara 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:
1) Crear y ejecutar programas en el computador SISC, que es una implementación Von Neuman (y multi-
ciclo) en LogicWorks de la arquitectura SISA:
Cargar un programa en la memoria RAM del SISC en LogicWorks que contenga un programa
SISA,
Ejecutar el programa (tanto ciclo a ciclo como todo seguido).
2) Escribir en lenguaje ensamblador y lenguaje máquina SISA los códigos MUL16, MUL y
KEY_MUL_PRINT para la multiplicación de dos números naturales. MUL16 realiza la multiplicación en
16 iteraciones del bucle que multiplica el multiplicando por un bit del multiplicador y acumula el
resultado parcial. MUL es un algoritmo de terminación temprana, en el que el número de iteraciones
es igual a 16 menos el número de ceros consecutivos que tiene el multiplicador en sus bits de más
peso. Tanto MUL16 como MUL presuponen que los operandos están almacenados en dos registros
del procesador y el resultado de la multiplicación se deja en otro registro. El algoritmo
KEY_MUL_PRINT se obtiene añadido instrucciones para entrar los operandos por un teclado y para
escribir el resultado en una impresora. La lectura/escritura del puerto de datos del controlador del
teclado/impresora tiene un efecto lateral: pone a cero el puerto de estado del controlador del
teclado/impresora, para ahorrarnos parte del protocolo de handshaking de cuatro pasos.
3) Calcular el número de ciclos de ejecución de un algoritmo codificado en SISA y ejecutado en el SISC
Directorio de la práctica
Aularios en módulo A5 y C6: Mi PC\I:\ic\Prac5
Aularios en el módulo D6: Mi PC\R:\Logic\Ver_4.1\Ic\Prac5
6.1 Introducción.
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.
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16
pf17
pf18
pf19
pf1a
pf1b
pf1c
pf1d
pf1e

Vista previa parcial del texto

¡Descarga Practica 5 ic y más Ejercicios en PDF de Introducción a los Ordenadores solo en Docsity!

PRÁCTICA 5

Introducción al lenguaje máquina y ensamblador SISA.

Implementación de algoritmos de multiplicación en el

computador SISC.

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:

  1. Crear y ejecutar programas en el computador SISC, que es una implementación Von Neuman (y multi- ciclo) en LogicWorks de la arquitectura SISA:  Cargar un programa en la memoria RAM del SISC en LogicWorks que contenga un programa SISA,  Ejecutar el programa (tanto ciclo a ciclo como todo seguido).
  2. Escribir en lenguaje ensamblador y lenguaje máquina SISA los códigos MUL16, MUL y KEY_MUL_PRINT para la multiplicación de dos números naturales. MUL16 realiza la multiplicación en 16 iteraciones del bucle que multiplica el multiplicando por un bit del multiplicador y acumula el resultado parcial. MUL es un algoritmo de terminación temprana, en el que el número de iteraciones es igual a 16 menos el número de ceros consecutivos que tiene el multiplicador en sus bits de más peso. Tanto MUL16 como MUL presuponen que los operandos están almacenados en dos registros del procesador y el resultado de la multiplicación se deja en otro registro. El algoritmo KEY_MUL_PRINT se obtiene añadido instrucciones para entrar los operandos por un teclado y para escribir el resultado en una impresora. La lectura/escritura del puerto de datos del controlador del teclado/impresora tiene un efecto lateral: pone a cero el puerto de estado del controlador del teclado/impresora, para ahorrarnos parte del protocolo de handshaking de cuatro pasos.
  3. Calcular el número de ciclos de ejecución de un algoritmo codificado en SISA y ejecutado en el SISC

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

6.1 Introducción.

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

6.2.2 Desensamblar. Del lenguaje máquina al lenguaje ensamblador

 Informe previo

Pregunta 2

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

6.2.3 Ejecución. Modificación del estado del computador

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.

 Informe previo

Pregunta 3

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 .

 El contenido del registro general Rk vale k%2 (el resto de dividir el número natural k entre

  1. para 0   7

k

. Así, R0, R2, R4 y R6 contienen 0x0000 y R1 y R3, R5 y R7 contienen

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

6.2.4 Programación. Del grafo de estados al programa SISA

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.

 Informe previo

Pregunta 4

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.

Fragmento de grafo

con mnemotécnicos para la

palabra de control

Fragmento de programa

en lenguaje ensamblador

SISA

a)

 Informe previo

Pregunta 5

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.

6.3 Un algoritmo de multiplicación con n iteraciones

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.

6.3.1 Algoritmo en lenguaje de alto nivel

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

R7<0> es el bit 0, el de menor peso, de R7.

Algoritmo MUL16 en alto nivel

R5 = 0;

for (j = 0; j < 16; j = j + 1) {

if (R7<0> == 1) R5 = R5 + R6; R6 = R6 * 2; R7 = R7 / 2;

6.3.2 Grafo de la UC para la ejecución de MUL16 en la UPG

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

número de iteraciones del bucle, se ha implementado con el registro R2 de la UPG. Como el bucle se

ejecuta más de una vez, de hecho se ejecuta 16 veces, se ha implementado el algoritmo inicializando R

a 16, entrando en el bucle sin preguntar si hay que ejecutarlo, haciendo el cuerpo del bucle,

decrementando en una unidad R2 y preguntando si hay que volver a ejecutar el bucle una vez más. Esta

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;

do {

if (R7<0> == 1) R5 = R5 + R6; R6 = R6 * 2; R7 = R7 / 2; R2 = R2 – 1;

} while (R2 > 0);

Grafo de estados para ejecutar en la UPG el algoritmo MUL

6.3.3 Obtención del algoritmo MUL16 en SISA

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.

 Informe previo

Pregunta 6

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?

6.4 Un algoritmo de multiplicación con terminación temprana

 Informe previo

Pregunta 8

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

 Informe previo

Pregunta 9

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?

6.5 El subsistema de Entrada/Salida: teclado e impresora

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

MOVI R0, 0 1001 000 0 00000000 9000
WHILE-1: CMPLTU R2, R0, R1 0001 000 001 010 100 1054
BZ R2, FI-WHILE-1 1000 010 0 00000110 8406
POLLING-2: IN R3, KEY-STATUS 1010 011 0 00000001 A
BZ R3, POLLING-2 1000 011 0 11111110 86FE
IN R3, KEY-DATA 1010 011 0 00000000 A
STB 32(R0), R3 0110 000 011 100000 60E
ADDI R0, R0, 1 0010 000 000 000001 2001
BNZ R2, WHILE-1 1000 010 1 11111000 85F
FI-WHILE-1:
MOVI R0, 0 1001 000 0 00000000 9000
WHILE-2: CMPLTU R2, R0, R1 0001 000 001 010 100 1054
BZ R2, FI-WHILE-2 1000 010 0 00000110 8406
LDB R3, 32(R0) 0101 000 011 100000 50E
POLLING-3: IN R4, PRINT-STATUS 1010 100 0 00000010 A
BZ R4, POLLING-3 1000 100 0 11111110 88FE
OUT PRINT-DATA, R3 1010 011 1 00000000 A
ADDI R0, R0, 1 0010 000 000 000001 2001
BNZ R2, WHILE-2 1000 010 1 11111000 85F
FI-WHILE-2:
BZ R2, BEGIN 1000 010 0 11101010 84EA

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:

  1. Abrid el circuito SISC-w-Display-wo-Prog.cct y la librería LibPrac5.clf que habréis copiado previamente en vuestro escritorio para poder escribir en ellos con el programa LogicWorks versión 4.1.
  2. Doble clic en el bloque 64K bytes MEMORY, para abrirlo. Aparecerá su circuito interno formado, básicamente, por dos bloques: 32K bytes MEMORY (1) y (0).
  3. Doble clic en el bloque 32K bytes MEMORY (0) para abrirlo y ver el dispositivo RAM que lo forma.
  4. Seleccionar el bloque RAM-32KB-
  5. Clic en el botón PLA/PROM/RAM Construction Wizard de la barra de herramientas,. Se abre una ventana donde aparece seleccionado Edit Selected Device.
  6. Clic en Siguiente. Aparece un nuevo contenido en la ventana.
  7. Seleccionar (clic) en “Read data from a raw hex file” y clic en Siguiente.
  8. Clic en “Select Raw Hex File”. Navegar hasta seleccionar el fichero Byte-0-KEY-MEM-PRINT.hex que se encuentra en el escritorio. Clic en Abrir del navegador. Clic en Finalizar de la ventana.
  9. Salvar el circuito (Clic en el icono “Save” de la barra o en File>Save).
  10. Cerrar el circuito abierto.
  11. Hacer lo mismo que los pasos 3 a 9 anteriores pero ahora entrando en 32K bytes MEMORY (1) para escribir Byte-1-KEY-MEM-PRINT.hex en el bloque el bloque RAM-32KB-1.

 Informe final

Pregunta 1:

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)

PC R0 R1 R2 R3 R
0 IN R1, KEY-STATUS 0000 0000 0000 0000 0000 0000
3 BZ R1, POLLING-
6 IN R1, KEY-DATA
MOVI R0, 0
CMPLTU R2, R0, R
BZ R2, FI-WHILE-
IN R3 KEY-STATUS
BZ R3 POLLING-
IN R3-KEY-DATA
STB 32(R0), R

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.

  1. Cargad el programa KEY_MUL_PRINT en la memoria del SISC (en el dispositivo 64K bytes MEMORY). Para ello: a. Cread dos ficheros .hex uno para cargar en el módulo-1 de la memoria y otro para el módulo-0. (con el formato “Raw Hex File” de LogicWorks. b. Cargar estos dos ficheros en la memoria siguiendo los mismos pasos que ya habéis seguido para el programa KEY_MEM-PRINT pero ahora para el KEY_MUL_PRINT (ver sección “Cargar la memoria RAM del SISC con el programa en Lenguaje Máquina”. c. Salvar la memoria del SISC (el dispositivo 64K bytes MEMORY con el programa ya cargado) en la librería LibPrac5 nombrando el dispositivo 64KBMEM_KEY_MUL_PRINT. Para ello seguid los mismos pasos que ya habéis seguido con el programa KEY_MEM_PRINT pero ahora para el KEY_MUL_PRINT y que se encuentran explicados en la sección “Crear un dispositivo con la memoria del SISC que contenga el programa cargado”.
  2. Haced las siguientes dos preguntas del informe final, equivalentes a la 2 y 2 pero ahora con el programa KEY_MUL_PRINT.

 Informe final

Pregunta 3:

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?

 Informe final

Pregunta 4:

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.

 Informe final

Pregunta 5:

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.