• No se han encontrado resultados

ELO311 Estructuras de Computadores Digitales. Estructuras de Datos

N/A
N/A
Protected

Academic year: 2021

Share "ELO311 Estructuras de Computadores Digitales. Estructuras de Datos"

Copied!
27
0
0

Texto completo

(1)

ELO311

Estructuras de Computadores Digitales

Estructuras de Datos

Tomás Arredondo Vidal

Este material está basado en:

material de apoyo del texto de David Patterson, John Hennessy, "Computer Organization & Design", (segunda y tercera edición), Morgan Kaufmann, CA. 2005

material del curso anterior ELO311 del Prof. Leopoldo Silva

(2)

Arreglos

Arreglos son una estructura de datos consecutivos en memoria usados para almacenar elementos.

Se requiere una variable entera sin signo, denominada el índice del arreglo, generalmente se emplea un

registro para este índice. (e.g. en C es A[i])

Todas los elementos tienen igual tamaño, típicamente se asume que están almacenadas en forma contigua

En assembler si se conoce la dirección del primero entonces la dirección del elemento i, queda dada por:

Dirección del primero + i * (tamaño del elemento en bytes)

En assembler típicamente el tamaño del elemento es una constante (múltiplo de dos) y la multiplicación

(3)

Arreglos (cont)

En C, si se usan índices se inicia con el elemento 0 (e.g. A[0] es el primer elemento del arreglo).

Este modelo de representación de los arreglos en

assembler, es el que usa el lenguaje C, que emplea el nombre del arreglo como un puntero al primer

elemento (e.g. A es la misma dirección que &A[0] para el arreglo A).

C también permite acceder a un elemento vía

indirección, con la expresión A+i, que es la dirección del elemento i del arreglo A.

En C la aritmética de punteros (e.g. A+i) calcula la

posición de memoria del elemento i acuerdo al tamaño de los elementos i (e.g. primer elemento es A + 0,

(4)

Arreglos (cont)

Con este modelo es posible ubicar un elemento cualquiera del arreglo sin tener que acceder a los elementos secuencialmente.

Ubicar cualquier elemento del arreglo (e.g. el primero, A[0] o el ultimo: A[99]) toma el mismo tiempo.

Porque tiene la capacidad de acceder a cualquier elemento de memoria de acuerdo a la necesidad del usuario sin tener que hacerlo secuencialmente es que esta estructura se la denomina RAM (Random Access Memory) o Memoria de Acceso Aleatorio.

(5)

Ejemplo: Arreglos con Índices

El siguiente segmento, en C, describe la manipulación mediante acceso vía un índice:

int a[ ] = {0,1,2,3,4,5,6}; int i = 0; int k = 0; void main(void) { i = 5; ...

k = a[i]; /* lectura de elemento de arreglo */

...

a[i] = k; /* escritura en elemento de arreglo */

(6)

Ejemplo: Arreglos con Índices

En assembler:

.data 0x10010000 # comienzo segmento datos a: .word 0,1,2,3,4,5,6 i: .word 0 k: .word 0 .text .globl main main:

# inicia variable i, en zona estática, con constante 5.

li $t3, 5 # t3=5 Macro que puede escribirse: ori $t3,$zero,5 la $t0, i # t0=&i t0 es un puntero. Apunta a variable i.

# este macro se puede remplazar por un lui y un ori sw $t3, 0($t0) # *t0=t3 Escribe en lo que apunta t0: i=5

(7)

Ejemplo: Arreglos con Índices (cont)

#Primero se obtiene en t2, el offset en bytes respecto al inicio. la $t0, i # t0 = &i

lw $t0, 0($t0) # t0 = *t0 o también t0 = i

sll $t2, $t0, 2 # t2 = 4*i

# Luego se forma, en t2, la dirección de a[i]

la $t1, a # t1 = &a[0] = &a, sin usar macro la: lui $t1, 0x1001

# ori $t1, $t1, 0

addu $t2, $t2, $t1 # t2 = &a + 4*i = &( a[i] )

# Finalmente se deposita en t3 el contenido de a[i] lw $t3, 0($t2) # t3 = a[i]

# Los comandos previos pueden escribirse con un macro: lw $t3, a($t2) la $t4, k # t4 = &k

sw $t3, 0($t4) # k = a[i] jr ra

(8)

Ejemplo: Arreglos con Punteros

El siguiente segmento, en C, describe la manipulación mediante acceso vía un puntero:

int a[ ] = {0,1,2,3,4,5,6}; int i = 0; int k = 0; void main(void) { i = 5; ...

k = *(a + i); /* lectura de elemento de arreglo */

...

*(a + i) = k; /* escritura en elemento de arreglo */

(9)

Ejemplo: Arreglos con Punteros (cont)

En assembler:

.data # por defecto comienza en 0x10010000

a: .word 0,1,2,3,4,5,6 i: .word 0 k: .word 0 .text .globl main main:

# inicia variable i, en zona estática, con constante 5.

li $t3, 5 # t3=5 Macro que puede escribirse: ori $t3,$zero,5

la $t0, i # t0=&i t0 es un puntero. Apunta a variable i.

sw $t3, 0($t0) # *t0=t3 Escribe el contenido de $t3 donde apunta $t0. # Los 2 comandos anteriores pueden escribirse con macro: sw $t3,

(10)

Ejemplo: Arreglos con Punteros (cont)

#Primero se obtiene en t2, el offset en bytes respecto al inicio. la $t0, i # t0 = &i

lw $t0, 0($t0) # t0 = *t0 o también t0 = i

sll $t2, $t0, 2 # t2 = 4*i

# Luego se forma, en t2, la dirección de (a+i)

la $t1, a # t1 = &a, sin usar macro la: lui $t1, 0x1001

# ori $t1, $t1, 0

addu $t2, $t2, $t1 # t2 = a+4*i

# Finalmente se deposita en t3 el contenido de *(t2) lw $t3, 0($t2) # t3 = *(t2)

# Los comandos previos pueden escribirse con un macro: lw $t3, a($t2) la $t4, k # t4 = &k

sw $t3, 0($t4) # k = *(a + i); jr ra

(11)

Arreglos de Caracteres (Strings)

Arreglos de caracteres (e.g. strings) son arreglos en el cual cada elemento almacenado es un carácter

(típicamente de un byte si es ASCII).

Z-strings (vs L-strings) son los strings usados en C y assembler normalmente, estos strings están

terminados por un carácter NULL ASCII (0x00) como

delimitador.

Al inicializar un string usando “ “ el carácter NULL es insertado automaticamente (e.g. “hola string”) pero de generar strings carácter por carácter hay que insertar el NULL explicitamente.

(12)

Ejemplo: Strings

Este ejemplo en C recorta “largo” carácteres de un string, desde la posición “inicial”; y devuelve un puntero al string resultante.

Se le pasa como argumentos la dirección del string y punteros a variables enteras que contienen la posición inicial y el largo.

Entonces, un ejemplo de invocación es: pchar = recortastring(arr, &inicio, &largo);

Recordar que en assembler: los argumentos van en registros $a0, $a1, $a2 y resultado en registro $v0

char *recortastring(register char *s, register int *inicial, register int *largo)

{

s = s + *inicial; *(s + *largo) = '\0'; return s;

(13)

Ejemplo: Strings (cont)

# v0 = recortastring($a0, $a1, $a2)

# char *recortastring(register char *s, register int *inicial, register int *largo) recortastring:

# no usa el stack al usar solo registros tN

move $t0, $a0 # t0 = s, macro puede usar: addu $t0, $zero, $a0 lw $t2, 0($a1) # t2 = *inicial

addu $t0, $t0, $t2 # t0 = s + *inicial lw $t1, 0($a2) # t1 = *largo

addu $t1, $t0, $t1 # t1 = s + *largo

sb $zero, 0($t1) # *t1 = '\0' Coloca el carácter nulo de fin de string. move $v0, $t0 # vo = nuevo inicio del string recortado. return(s)

(14)

Manipulación de arreglos via índice vs punteros

Existen diferencias en la eficiencia de manipular arreglos usando

índices vs punteros.

void cleararray1(int a[], int celdas) { int i;

for( i = 0; i < celdas ; i++) { a[i] = 0;

} }

Código assembler generado por lcc ($4 = $a0, $5 = $a1) -> .text .ent cleararray1 cleararray1: addu $sp,$sp,-8 sw $30,0($sp)

addu $30, $zero, $zero # i = 0

b L.5 L.2: sll $24,$30,2 # $t8 = 4*i addu $24,$24,$4 # $t8 = a + 4*i sw $0,($24) # Mem($t8) = 0 la $30,1($30) # i = i + 1 L.5: blt $30,$5,L.2 # $ i < a1 -> L.2 lw $30,0($sp) addu $sp,$sp,8 j $31 .end cleararray1

(15)

Manipulación de arreglos via índice vs punteros

Versión con punteros 1:

void clearpunt1(int *a , int celdas)

// Versión con punteros

{ int *p;

for( p = a; p < a+celdas ; *p = 0, p++);

}

Código assembler generado por lcc ->

a+celdas es una constante…

.text .ent clearpunt1 clearpunt1: addu $sp,$sp,-8 sw $30,0($sp) addu $30, $zero, $4 # p = a b L.10 L.7: sw $0,($30) # Mem(p) = 0 la $30,4($30) # p = p + 4 L.10: addu $24, $zero, $30 # $t8 = p sll $15,$5,2 # $t7 = 4*celdas addu $15,$15,$4 # $t7 = a + 4*i bltu $24,$15,L.7 # $t8 < t7 -> L.7 lw $30,0($sp) addu $sp,$sp,8 j $31 .end clearpunt1

(16)

Manipulación de arreglos via índice vs punteros

Versión con punteros 2:

void clearpunt2(int *a , int celdas)

// Versión con punteros

{ int *p, *q;

for( p = a, q=a+celdas; p < q; p++) *p = 0; }

En general los punteros son mas

eficientes ya que referenciar a+celdas requiere menos instrucciones que a[i] en el lazo interno (inner loop).

.text .ent clearpunt2 clearptr2: addu $sp,$sp,-8 sw $23,0($sp) # guardar $s7 en stack sw $30,4($sp) # guardar $fp en stack addu $30, $zero, $4 # p = a sll $24,$5,2 # $t8 = 4*celdas addu $23,$24,$4 # $s7 = a + 4*i b L.15 L.12: sw $0, ($30) # *p = 0 la $30,4($30) # p = p + 4 L.15: addu $24, $zero, $30 # $t8 = p bltu $24,$23,L.12 # if $t8 < $s7 -> L.12 lw $23,0($sp) lw $30,4($sp) addu $sp,$sp,8 j $31 .end clearpunt2

(17)

Estructuras

En C se puede definir estructuras que contienen elementos compuestos de diferentes tipos de datos

(e.g. int, char, float, etc).

Para declarar estas estructuras se usa la palabra

struct

La dirección del primer campo está dada por la dirección de inicio de la estructura.

La dirección del segundo campo está dada por la

dirección de inicio de la estructura + tamaño del primer campo.

La dirección del tercer campo está dada por la dirección de inicio de la estructura + suma de los tamaños del primer y segundo campo.

Puede ser necesario el uso de .space para mantener el alineamiento (ver ejemplo mas adelante)

(18)

Ejemplo: Estructuras

En lenguaje C: struct punto { int x; int y; };

struct punto a = { 1 , 2}; /* Se inicializan al definir el espacio */

struct punto b = { 3 , 4}; void main(void)

{

a.x=b.x; a.y=b.y; /* Se puede escribir a = b, pero es una */

(19)

Ejemplo: Estructuras

En lenguaje C: struct punto { int x; int y; }; struct punto a = { 1 , 2}; struct punto b = { 3 , 4}; void main(void) { a.x=b.x; a.y=b.y; } En assembler: .data structa: .word 1 .word 2 structb: .word 3 .word 4 .text .globl main main:

# apuntar a estructuras, registro base con offset

la $t0, structb la $t1, structa lw $t3, 0($t0) # t3=b.x sw $t3, 0($t1) lw $t4, 4($t0) # t4=b.y sw $t4, 4($t1)

(20)

Ejemplo: Estructuras con Strings

En lenguaje C: struct pixel{ char color[6]; int lugar[2]; };

struct pixel p1 = {"red", {10,20}}; void main(void) { p1.color[0]='g'; p1.color[1]='r'; p1.color[2]='e'; p1.color[3]='e'; p1.color[4]='n'; p1.color[5]='\0'; }

(21)

Ejemplo: Estructuras con Strings (cont)

En lenguaje C: struct pixel{ char color[6]; int lugar[2]; };

struct pixel p1 = {"red", {10,20}};

void main(void) { p1.color[0]='g'; p1.color[1]='r'; p1.color[2]='e'; p1.color[3]='e'; p1.color[4]='n'; p1.color[5]='\0'; } En assembler: .globl p1 .data .align 2 p1: .byte 114 # 104 = ‘r’ en ASCII

.byte 101 # 101 = ‘e’ en ASCII

.byte 100 # 100 = ‘d’ en ASCII

.byte 0 # 0 = NULL Terminator

.space 2 # 2 bytes de espacio

.space 2 # 2 bytes de espacio

.word 0xa # 10

.word 0x14 # 20

(22)

En lenguaje C: struct pixel{

char color[6]; int lugar[2]; };

struct pixel p1 = {"red", {10,20}};

void main(void) { p1.color[0]='g'; p1.color[1]='r'; p1.color[2]='e'; p1.color[3]='e'; p1.color[4]='n'; p1.color[5]='\0'; } En assembler: main: .frame $sp,0,$31 la $24,103 # $t8 = ‘g’ = 103 sb $24,p1 # p1.color[0] = ‘g’ la $24,114 # $t8 = ‘r’ = 114 sb $24,p1+1 # p1.color[1] = ‘r’ la $24,101 # etc... sb $24,p1+2 la $24,101 sb $24,p1+3 la $24,110 sb $24,p1+4 sb $0,p1+5 L.1: j $31 .end main

(23)

Manejo dinámico de la memoria

malloc, calloc y free se usan para obtener memoria dinámicamente

Del Linux Programmer's Manual (man malloc):

NAME calloc, malloc, free, realloc - Allocate and free

dynamic memory

SYNOPSIS #include <stdlib.h>

void *calloc(size_t nmemb, size_t size); void *malloc(size_t size);

void free(void *ptr);

DESCRIPTION calloc() allocates memory for an array of nmemb elements of size bytes each and returns a

pointer to the allocated memory. The memory is set to zero. malloc() allocates size bytes and returns a pointer to the allocated memory. The memory is not cleared.

(24)

Manejo dinámico de la memoria (cont)

Se puede usar la función estándar sizeof para

determinar el número de bytes de un cierto tipo de datos que se solicitaran al administrador de memoria (parte

del sistema operativo)

sizeof(char *) es igual a 4 (un word) y no refleja el tamaño de un string (usar strlen)

Si es posible asignar espacio retorna un puntero a carácter del primer byte asignado; en caso contrario retorna Null.

El administrador dinámico mantiene datos para asignar y desasignar segmentos de memoria en la zona de

memoria dinámica (denominada heap).

En MIPS por defecto el inicio del segmento datos es 0x10010000 el comienzo del heap es 0x10040000 y el comienzo de datos

(25)

Organización de Memoria en MIPS (spim)

Memory 230 words 0000 0000 f f f f f f f c Your Code Reserved OS Static data Mem Map I/O

0040 0000 1000 0000 1000 8000 7f f e f f fc Stack Dynamic data $sp $gp PC Kernel Code & Data 8000 0080

(26)

Manejo dinámico de la memoria (cont)

El código siguiente ilustra la forma de pedir espacio para un entero y luego libera el espacio asignado.

#include <stdio.h>

#include <stdlib.h> /* Para incluir prototipos de malloc y free */

int main(void) {

int *punt=0; /*Define e inicia puntero*/

punt = (int *) malloc(sizeof(int));/*pide espacio y lo encadena. */

if (punt ==0) return(1); /* si no hay espacio */

*punt=5;

printf("%d\n",*punt);

free(punt); /*Libera espacio*/

return(0); }

(27)

Manejo dinámico de la memoria (cont)

Otro ejemplo de asembler MIPS usando servicios: main:

...

li $v0,9 # $v0=9 para pedir memoria en heap (sbrk) li $a0,8 # se pide en bytes (dos palabras)

syscall # heap por defecto en 0x10040000

move $t0,$v0 # retorna en $v0 un puntero al espacio li $t1,0xFFFFFFFF

sw $t1,0($t0) # escribe en las celdas asignadas. sw $t1,4($t0)

Referencias

Documento similar

If certification of devices under the MDR has not been finalised before expiry of the Directive’s certificate, and where the device does not present an unacceptable risk to health

Where possible, the EU IG and more specifically the data fields and associated business rules present in Chapter 2 –Data elements for the electronic submission of information

The 'On-boarding of users to Substance, Product, Organisation and Referentials (SPOR) data services' document must be considered the reference guidance, as this document includes the

In medicinal products containing more than one manufactured item (e.g., contraceptive having different strengths and fixed dose combination as part of the same medicinal

Products Management Services (PMS) - Implementation of International Organization for Standardization (ISO) standards for the identification of medicinal products (IDMP) in

Products Management Services (PMS) - Implementation of International Organization for Standardization (ISO) standards for the identification of medicinal products (IDMP) in

This section provides guidance with examples on encoding medicinal product packaging information, together with the relationship between Pack Size, Package Item (container)

Package Item (Container) Type : Vial (100000073563) Quantity Operator: equal to (100000000049) Package Item (Container) Quantity : 1 Material : Glass type I (200000003204)