Skip to content

Latest commit

 

History

History
1132 lines (807 loc) · 23.6 KB

File metadata and controls

1132 lines (807 loc) · 23.6 KB

💻RISC

Indice

Instrucciones

Veamos cómo nos manejamos con variables.

  • Para empezar, todas las operaciones aritméticas-lógicas deben hacerse con registros
  • Si quiero usar variables, debo cargarlas antes en un registro
  • Las variables se definen en un bloque .data y arrancan en la dirección 0
  • Para tomar una variable se usa LD "DESTINO", "VARIABLE" (DESPLAZAMIENTO).
.data                     ; LD R1, A (R0)
  A: .word 5              ; R1 = variable en dir. de A + 0
  B: .word 8
.code
  LD R1, A(R0)
  • Para guardar un valor en memoria se utiliza el mismo mecanismo de desplazamiento
  • La sintaxis es SD "REGISTRO ORIGEN", "VARIABLE" (DESPLAZAMIENTO)
.data                     ; SD R1, A (R0)
  A: .word 0              ; RES = VALOR DE R1 EN VARIABLE EN DIR. DE A + 0
.code
  DADDI R1, R0, 5
  SD R1, A(R0)

Atascos

Se pueden dar en situaciones que impiden a la siguiente instruccion que se ejecute en el ciclo que le corresponde.

Los queremos evitar a toda costa. Si tenemos atascos significa que una instruccion esta estancada esperando algo de una instruccion anterior.

Estructurales

Provocados por conflicto de recursos.

En el MIPS sucede cuando dos instrucciones intentan acceder a la etapa MEM simultáneamente.

Imagen1

Dos instrucciones listas para pasar a la etapa de memoria.

Se produce un atasco estructural y solo pasa una de ellas

Tiene prioridad la primera instruccion que entró en el cause

Dependencia_de_Datos

RAW

Significa: Read After Write.

  • Se produce cuando una instrucción necesita leer un dato que todavía no esta disponible.
  • Si no nos queda de otra, podemos usar un NOP
Por software Con NOPS Ordenando Sentencias
.data
    NUM1: .word 15

.code
    DADDI R1, R0, 8
    DADDI R2, R1, 10
    LD R7, NUM1 (R0)
HALT
.data
    NUM1: .word 15

.code
    DADDI R1, R0, 8
    NOP
    NOP
    DADDI R2, R1, 10
    LD R7, NUM1 (R0)
HALT
.data
    NUM1: .word 15

.code
    DADDI R1, R0, 8
    LD R7, NUM1 (R0)
    DADDI R2, R1, 10
HALT
  
  • WAR Write After Read y WAW Write After Write (estan pero tengo idea del para que)

Forwarding

POR HARDWARE Si ya tenemos los valores necesarios, podemos "adelantarlos"

bufer

En estos buffers se almacena los valores para que los puedan usar en las próximas instrucciones. De esta manera no hace falta esperar a las etapas MEM y WB para usar los valores!. Este adelantamiento de operando lo llamamos Forwarding. Los buffers no se pueden ver en el simulador. Una ventaja que tiene esta técnica es que nos permite postergar la "necesidad" de los operandos.

¿Cuando conviente tenerlo activado? Siempre es conveniente tenerlo activado (en la mayoria de los casos)

WAR_Y_WAW

Se producen cuando:

  • Hay dependencia de datos entre dos instrucciones (igual que RAW)
  • Una instrucción puede sobrepasar a una instrucción anterior, queriendo escribir un registro pendiente de lectura (WAR) o escritura (WAW)
  • El simulador produce atascos cuando detecta una situación potencial (Puede que realmente no suceda) de dependencia WAR o WAW.
Ejemplo 1 Ejemplo 2
.data
    n1:    .double 	9.13 
    n2:    .double 	6.58 
    res1:  .double 	0.0 
    res2:  .double 	0.0 

.code 
    L.D F1, n1 (R0)     ; F1 = n1
    L.D F2, n2 (R0)     ; F2 = n2
    ADD.D F3, F2, F1    ; F3 = F2 + F1
    MUL.D F4, F2, F1    ; F4 = F2 * F1
    S.D F3, res1 (R0)   ; Guarda la suma en res1
    S.D F4, res2 (R0)   ; Guarda la mult en res2
HALT
.data
    n1:    .double 	9.13 
    n2:    .double 	6.58 
    res1:  .double 	0.0 
    res2:  .double 	0.0 

.code 
    L.D F1, n1 (R0)     ; F1 = n1
    L.D F2, n2 (R0)     ; F2 = n2
    ADD.D F3, F2, F1    ; F3 = F2 + F1
    MUL.D F2, F2, F1    ; F2 = F2 * F1
    MUL.D F4, F2, F1    ; F4 = F2 * F1
    S.D F3, res1 (R0)   ; Guarda la suma en res1
    S.D F4, res2 (R0)   ; Guarda la mult en res2
HALT

Dependencia_de_Control

Provocados al esperar la decisión de otra instrucción anterior (por ejemplo: si se realiza o no un salto).

Tenemos dos tipos de saltos

  • Incondicionales: Salta siempre.
  • Condicionales: Salta dependiendo de que se cumpla una condición.

Branch_Taken_Stall

Definicion: Atasco de salto, es un salto que tuvimos que haber hecho y no lo hicimos. (Empezamos a ejecutar una instrucción que no debiamos ejecutar). El programa se da cuenta, corta la ejecución y abajo comienza la sentencia que tendria que haber ejecutado.

Ejemplo:

Ejemplo Estadisticas
.data
B: .word 5

.code
    DADDI R1, R0, 1
    LD R2, B (R0)
    LOOP: DSLL R1, R1, 1    ; Desplazo a la izquierda
        DADDI R2, R2, -1    ; Cant. de desplazamientos que faltan
        BNEZ R2, LOOP       ; Si no es 0 salto a LOOP
HALT

image

Branch_Target_Buffer

Al igual que los atascos de dependencia de datos, tenemos diferentes técnicas para evitar los atascos por saltos.

La primera se denomina Branch Target Buffer que consiste en tener un flag que indica que si se debe saltar incondicionalmente o no dependiendo de qué hizo antes (es decir, predice).

Cada vez que ese flag/buffer se actualiza cuenta como un atasco de salto! Cada vez que le erramos a la predicción cuenta como atasco.

Misprediction (nuevo atasco): Es un atasco que me va a contabilizar cuando el BTB este equivocado

Ejemplo:

gifPro

¿Cuando conviene activar el BTB?

Como solo fallamos al principio y al final de loop, conviene usarlo cuando tenemos bucles muy grandes. (sin condiciones de por medio)

Buenoooo Maloooo
for i:=1 to 100000000 do
begin
  // Hace algo                          
end;

Vamos a tener dos atascos al principio y dos atascos al final

for i:=1 to 100000000 do
begin
  if i es par then
    // Hace algo
  else
    // Hace otro algo
end;

Vamos a tener dos atascos en cada interación (porque vamos a fallar la predicción)

Delay_Slot

Es la otra técnica. Simplemente consiste en ejecutar SIEMPRE la siguiente instrucción a un salto

Programa Definicion
DADDI R2, R0, 3
LOOP: DADDI R2, R2, -1
  BNEZ R2, LOOP
HALT

Se terminaría el programa ya que se ejecuta el HALT en la primera interación!

  • Buscamos ubicar instrucciones que no dependen del salto
  • De esta manera aprovechamos una instrucción y no tenemos atascos de salto!
  • Cómo último recurso usar sentencias NOP
Ejemplo Mal Delay Slot Activado
.data
    cant: .word 8
    datos: .word 1, 2, 3, 4, 5, 6, 7, 8
    res: .word 0

.code
    DADD R1, R0, R0          ; Inicializa R1 = 0
    LD R2, cant (R0)         ; R2 = cant
    LOOP: LD R3, datos (R1)  ; R3 = elemento de datos en la posición R1
        DADDI R2, R2, -1     ; Resta 1 a la cantidad de elementos a procesar
        DSLL R3, R3, 1       ; Multiplica por dos el elemento actual
        SD R3, res (R1)      ; Almacena el resultado en la tabla de resultados
        DADDI R1, R1, 8      ; Avanza a la siguiente posición
        BNEZ R2, LOOP        ; Si quedan elementos sigo iterando
    NOP
HALT

image

Ejemplo Bien Delay Slot Activado
.data
    cant: .word 8
    datos: .word 1, 2, 3, 4, 5, 6, 7, 8
    res: .word 0

.code
    DADD R1, R0, R0          ; Inicializa R1 = 0
    LD R2, cant (R0)         ; R2 = ca
    LOOP: LD R3, datos (R1)  ; R3 = elemento de datos en la posición R1
        DADDI R2, R2, -1     ; Resta 1 a la cantidad de elementos a procesar
        DSLL R3, R3, 1       ; Multiplica por dos el elemento actual
        SD R3, res (R1)      ; Almacena el resultado en la tabla de resultados
        BNEZ R2, LOOP        ; Si quedan elementos sigo iterando
    DADDI R1, R1, 8          ; Avanza a la siguiente posición
HALT

image

Punto_Flotante

MIPS utiliza IEE 754 para números en punto flotante.

Contamos con 32 registros: desde F0 (simpre vale 0) hasta F31

Tiene un único tipo de dato que es el .double

Pagina recomendada

NO todas las etapas tardan lo mismo.

  • Generales = 1 ciclo
  • Multiplicar en Pto. F. = 7 ciclos
  • Sumar en Pto. F. = 4 ciclos.
  • Dividir en Pto. F. = 24 Ciclos

Esta arquitectura nos permite tener múltiples instrucciones en la etapa EX

Podemos ejecutar múltiples instrucciones en menos tiempo!

No todo es color de rosas. Introduce los siguientes atascos:

  • Dependencia Estructural
  • Dependencia de datos WAR
  • Dependencia de datos WAW

Subrutinas

IMPORTANTE

  • No hay manejo implícito de la pila!
  • La dirección de retorno siempre estará en R31
    • Esto si se hace implícitamente en el JAL
  • Los registros se pueden sobrescribir , incluído R31
    • Vamos a tener que salvarlos en la pila

CONVENCIONES

Las subrutinas deben garantizar el guardado de los registros que correspondan. De esta manera, una subrutina podrá llamar a otra sabiendo que esta no modificará el valor de estos registros, para poder mantener esta garantía, es necesario guardar los registros en la pila. (PERO MIPS NO TIENE PILA 😧). Pero existe un registro que por convención todas las subrutinas usarán como puntero al tope de la pila. Y ese registro es.........

El registro $sp

PUSH $t1 POP $t1
daddi $sp, $sp, -8 ; "Subo" una celda de memoria
sd $t1, 0 ($sp)    ; Almaceno el dato
ld $t1, 0 ($sp)     ; Extraigo el dato
daddi $sp, $sp, 8   ; "Bajo" una celda de memoria
Como ejemplo Como lo vamos a usar
.data
    NUM1: .word 5
    NUM2: .word 8
    RES: .word 0

.code
    LD R1, NUM1 (R0)
    LD R2, NUM2 (R0)
    JAL SUMAR ; Llama a la subrutina
    SD R3, RES (R0)
HALT

SUMAR: DADD R3, R1, R2 
    JR R31 ; Retorna al punto donde fue llamado
.data
    NUM1: .word 5
    NUM2: .word 8
    RES: .word 0

.code
    LD $a0, NUM1 (R0)
    LD $a1, NUM2 (R0)
    JAL SUMAR ; Llama a la subrutina
    SD $v0, RES (R0)
HALT

SUMAR: DADD $v0, $a0, $a1
    JR $ra ; Retorna al punto donde fue llamado

registros

  • En verde aquellos que, en caso de usarse, deben ser salvados
  • En azul aquellos que podemos sobrescribir sin ningún problema

Entrada_Salida

Existen dos "registros" (es decir, dos celdas de memoria comunes)

  • CONTROL sirve para enviar códigos de operaciones. (0x10000)
  • DATA sirve para enviar o recibir datos. (0x10008)

Como son celdas de memoria se leen y escriben con instrucciones de memoria: LD/L.D/LBU/SD/S.D....

Pantalla_Alfanumerica

IMPRIMIR UN STRING

  • DATA --> Direccion del string
  • CONTROL --> El valor 4

IMPRIMIR UN NÚMERO

  • DATA --> El Dato
  • CONTROL
    • 1 Imprime un entero sin signo
    • 2 Imprime un entero con signo
    • 3 Imprime un flotante

LIMPIAR LA PANTALLA

  • CONTROL -> El valor 6
Imprimir Entero Imprimir Double Imprimir String
.data
    CONTROL: .word 0x10000
    DATA:    .word 0x10008
    NUM:     .word 2

.code
    LD $s0, CONTROL ($0)    
    LD $s1, DATA ($0)      

    LD $t0, NUM ($0)
    SD $t0, 0 ($s1)         
     ; CONTROL = 2
    DADDI $t0, $0, 2
    SD $t0, 0 ($s0)        
    ; LIMPIA LA PANTALLA
    ;DADDI $t0, $0, 6       
    ;SD $t0, 0 ($s0)        
HALT
.data
    CONTROL: .word 0x10000
    DATA:    .word 0x10008
    NUM:     .double 19.5

.code
    LD $s0, CONTROL ($0)    
    LD $s1, DATA ($0)      

    L.D f1, NUM ($0)
    S.D f1, 0 ($s1)        
    ; Control 3
    DADDI $t0, $0, 3
    SD $t0, 0 ($s0)         

    ;DADDI $t0, $0, 6       
    ;SD $t0, 0 ($s0)        
HALT
.data
    CONTROL:  .word 0x10000
    DATA:     .word 0x10008
    TEXTO:    .asciiz "Hola, Mundo!" 

.code
    LD $s0, CONTROL($0)  
    LD $s1, DATA($0)      
     
    DADDI $t0, $0, TEXTO  
    SD $t0, 0($s1)        
    
    DADDI $t0, $0, 4      
    SD $t0, 0($s0)        
HALT

;(1) $t0 = 4 -> función 4: salida de una cadena ASCII
;(2) CONTROL recibe 4 y produce la salida del mensaje

Pantalla_Grafica

Pantalla de 50x50px

PINTAR UN PÍXEL

  • DATA --> Color y coordenadas
  • CONTROL --> El valor 5

LIMPIAR LA PANTALLA

  • CONTROL -> El valor 7

NUEVOOWO

.data ;Imprimir un pixel
    CONTROL: .word 0x10000
    DATA:    .word 0x10008
    PIXEL:   .byte 0, 185, 135, 0, 23, 10, 0, 0
.code 
    LD $s0, CONTROL ($0)     ; $s0 = CONTROL
    LD $s1, DATA ($0)        ; $s1 = DATA

    LD $t0, PIXEL ($0)
    SD $t0, 0 ($s1)      ; Mando el dato a DATA

    DADDI $t0, $0, 5
    SD $t0, 0 ($s0)             ; CONTROL = 5

HALT
.data
    coorX:   .byte 24 ; X
    coorY:   .byte 24 ; Y
    color:   .byte 255, 0, 255, 0 
    CONTROL: .word 0x10000
    DATA:    .word 0x10008

.code 
    ld $s0, CONTROL ($zero)   ; $s0 = dir de CONTROL
    ld $s1, DATA ($zero)      ; $s1 = dir de DATA

    ; limpia la pantalla

    daddi $t0, $zero, 7			
    sd $t0, 0 ($s0) 				

    lbu $t0, coorX ($zero) 			
    sb $t0, 5 ($s1) 				

    lbu $t1, coorY ($zero)    ; $t1 = valor de coordenada Y
    sb $t1, 4 ($s1) 	      ; DATA + 4 recibe el valor de coordenada Y
    
    lwu $t2, color ($zero)    ; $t2 = color
    sw $t2, 0 ($s1) 	      ; Pongo color en DATA
    daddi $t0, $zero, 5
    sd $t0, 0 ($s0) 	      ; Pinta el píxel
HALT

Teclado

LEER UN NÚMERO (ENTERO O FLOTANTE)

  • CONTROL --> El valor 8
  • DATA -->
    • Muestra el caracter presionado
    • Termina de leer cuando presiona ENTER
    • Si el dato ingresado no es un número se guarda 0. Tomar el valor (HEXADECIMAL) con LD o L.D desde DATA

LEER UN CARACTER

  • CONTROL -> El valor 9
  • DATA ->
    • NO muestra el caracter presionado
    • No espera al ENTER
    • Tomar el valor (ASCII) con LBU desde DATA
Leer Double Leer Infinito
.data ;leer desde teclado
    CONTROL:    .word 0x10000
    DATA:       .word 0x10008
    NUM:        .double 0.0
    CARACTER:   .byte 0

.code
    LWU $s0, CONTROL ($zero) 	; $s0 = CONTROL
    LWU $s1, DATA ($zero) 	   	; $s1 = DATA

    DADDI $t0, $zero, 8
    SD $t0, 0 ($s0)             ; CONTROL = 8
    L.D f1, 0 ($s1)             ; Tomo número en f1
    S.D f1, NUM ($zero)         ; Guardo en variable

    DADDI $t1, $zero, 9
    SD $t1, 0 ($s0)             ; CONTROL = 9
    LBU $t1, 0 ($s1)            ; Tomo caracter en $t1
    SB $t1, CARACTER ($zero)    ; Guardo en variable
HALT
.data
    CONTROL: .word 0x10000
    DATA:    .word 0x10008
    CARACTER: .byte 0
.code
    LWU $s0, CONTROL($0)
    LWU $s1, DATA($0)
    
    DADDI $s4, $0, 13       ; 13 el ascii del enter pá

    LOOP: DADDI $t1, $0, 9
        SD $t1,0 ($s0)      ; CONTROL = 9

        ; *PRESIONA UNA TECLA*
        ; LA CPU GUARDA EL CARACTER EN DATA

        LBU $t1,0 ($s1)

        ; COMPARO CON EL ENTER
        BEQ $t1, $s4, FIN

        ; GUARDO LA VARIABLE
        SB $t1, CARACTER($0)

        ;TOMO LA DIR DE CARACTER
        DADDI $s3, $0, CARACTER

        ; MANDO DIR DE CARACTER
        SD $s3, 0 ($s1)

        ; IMPRIMIR CARACTER
        DADDI $t1, $0, 4
        SD $t1, 0 ($s0) ; CONTROL 4

        J LOOP
FIN: HALT

Fases_de_una_instruccion

Las instrucciones se organizan en fases de manera que esto sea posible

Fases Funcion

if

Instruction Fetch

  • Se accede a memoria por la instrucción
  • Se incrementa el PC (antes conocido como el IP)

ID

Instruction Decoding

  • Se decodifica la instruccion
  • Se accede al banco de registros por los operandos. Se atasca si no están disponibles
  • Se calcula el valor del operando inmediato
  • Si es un salto, se calcula el destino y si se toma o no (requiere acceder al banco de reg)

EX

Execution

  • Si es una instrucción de cómputo, se ejecuta en la ALU
  • Si es un acceso a memoria, se calcula la dirección efectiva
  • Si es un salto, se realiza (se modifica el registro PC)

ME

Memory access

  • Si es un acceso a memoria, se lee/escribe el dato

WB

Write Back

  • Se almacena el resultado (si lo hay) en los registros

Codigos

Intercambio

.data
    A: .word 1
    B: .word 2
.code
    ld r1, A(r0)
    ld r2, B(r0)
    sd r2, A(r0)
    sd r1, B(r0)
halt

Multiplicacion

.data
    NUM1: .word 5
    NUM2: .word 8
    RES:  .word 0

.code
    LD R1, NUM1 (R0)
    LD R2, NUM2 (R0)

    ;MULTIPLICAMOS 
    DMUL R3, R1, R2

    ;ALMACENAMOS EL RESULTADO EN RES
    SD R3, RES (R0)

HALT

Potencia

.data
    B: .word 5

.code
    DADDI R1, R0, 1
    LD R2, B (R0)
    LOOP: DSLL R1, R1, 1    ; Desplazo a la izquierda
        DADDI R2, R2, -1    ; Cant. de desplazamientos que faltan
        BNEZ R2, LOOP       ; Si no es 0 salto a LOOP
HALT

String_Mayusculas

.data
cadena: .asciiz "Caza"

.code
    ; La pila comienza en el tope de la memoria de datos
    DADDI $sp, $0, 0x400 ; bus 10 bits 🡪 2^10 = 1024 = 0x400

    ; Guarda como primer argumento para upcaseStr
    ; la dirección de cadena
    DADDI $a0, $0, cadena
    JAL upcaseStr
HALT

upcaseStr: DADDI $sp, $sp, -16      ; Reserva lugar en pila -> 2 x 8
    SD $ra, 0 ($sp)                 ; Guarda en pila $ra
    SD $s0, 8 ($sp)                 ; Guarda en pila $s0
    DADD $s0, $a0, $zero            ; Copia la dirección de inicio de la cadena
    LOOP: LBU $a0, 0 ($s0)	        ; Toma car. actual
        BEQ $a0, $zero, FIN         ; Si es el fin, termina
        JAL upcase
        SB $v0, 0 ($s0)             ; Guarda el caracter procesado en la cadena
        DADDI $s0, $s0, 1           ; Avanza al siguiente caracter
    J LOOP
    ; Recupera los datos salvados en la pila
    FIN: 	LD $ra, 0 ($sp)
    LD $s0, 8 ($sp)
    DADDI $sp, $sp, 16
    JR $ra


; Pasa un caracter a mayúscula.
; Parámetros: $a0 -> caracter
; Retorna $v0 -> caracter en mayúscula
; No se utiliza la pila porque no se usan registros que deban ser salvados

upcase: DADD $v0, $a0, $zero
SLTI $t0, $v0, 0x61 ; Compara con ‘a’ minúscula
	BNEZ $t0, salir ; No es un caracter en minúscula
	SLTI $t0, $v0, 0x7B ; Compara con el car sig a 'z' minúscula (z=7AH)
	BEQZ $t0, salir ; No es un caracter en minúscula
	DADDI $v0, $v0, -0x20 ; Pasa a minúscula
salir: JR $ra 	; Retorna

BASE_EXPONENTE

.data
    BASE: .word 2
    EXPONENTE: .word 3
.code
    LD $t0, BASE($0)
    LD $t1, EXPONENTE($0)
    DADD $t2, $t2 , $t0
    LOOP: BEQZ $t1, TERMINO
        dmul $t2, $t2, $t0  
        DADDI $t1, $t1, -1        
    J LOOP
TERMINO: HALT

Instrucciones_de_Transferencia_de_datos

1 2

Instrucciones_Aritmeticas

2 2

Instrucciones_Logicas

3 2

Instrucciones_de_desplazamiento_de_bits

4 2

Instrucciones_de_Transferencia_de_control

5 2

Instrucciones_control

6 2