Instrucciones para la transferencia de datos

Anuncio
ARQUITECTURA DE SISTEMAS PARALELOS I.
4º INGENIERÍA INFORMÁTICA.
ENSAMBLADOR DEL “DLX”
1. Sea el siguiente fragmento de código:
Loop:
LW
ADDI
SW
ADDI
SUB
BNEZ
R1, 0(R2)
R1, R1, #1
0(R2), R1
R2, R2, #4
R4, R3, R2
R4, loop
donde el valor inicial de R3 es R2+400.
Explicar qué hace y cual puede ser su traducción en lenguaje C o similar.
2. Dado el fragmento de código:
int i;
double a[MAX], b[MAX], c[MAX], t;
for (i=0, t=0 ; i<MAX ; i++)
t += b[i] + c[i]*a[i];
Escribir una posible traducción a ensamblador del DLX.
3. Explicar qué hace el siguiente fragmento de código y cual puede ser su traducción
en lenguaje C o similar.
Bucle:
LW R1, (R8)0
LW R2, (R7)0
SW (R8)0, R2
SW (R7)0, R1
ADDI R7, R7, #4
SUBI R8, R8, #4
BNEZ R8, Bucle
¿Qué ha de retocarse si se ponen las instrucciones de suma y resta al principio del
bucle?
4. Para el siguiente código en C, escribir una posible traducción a ensamblador del
DLX:
double a, z[256]; /*suponer que z[0] está en la dirección 0, para usar un único puntero al array z, y
decrementarlo hasta que éste sea 0 */
for (i=127 ; i>=0 ; i--)
z[i+128] = a*z[i] + z[i+128];
SOLUCIONES:
1. Se trata de un bucle donde en las últimas tres instrucciones (parte de “control del
bucle”) el registro R2 se va incrementando de 4 en 4 y se va comparando con R3,
usando la instrucción SUB. En el DLX la instrucción de comparar no existe con el
mnemónico CMP o algo parecido, aunque sí existen instrucciones de valorar un registro
(set en inglés) cuyo mnemónico es Sxx, donde xx es GT(>), GE(>=), EQ(=), etc. En
lugar de SUB podría haberse usado SNE (Set if Not Equal).
Tal comparación hace de límite del bucle ya que el valor inicial de R3 es
R2+400, y R2 va creciendo hasta haberse incrementado en 400. Como se incrementa de
4 en 4, el bucle tiene 100 iteraciones.
Loop:
LW
ADDI
SW
R1, 0(R2)
R1, R1, #1
R1, 0(R2)
ADDI
SUB
BNEZ
R2, R2, #4
R4, R3, R2
R4, loop
; incrementa R2
; compara R2 y R3. Podría haberse usado SNE
En las tres primeras instrucciones del bucle tenemos que se carga el dato de la dirección
0(R2), se incrementa en un registro, y se escribe sobre memoria en la misma posición.
Por tanto debe existir un array en memoria que está siendo incrementado. Por tanto el
código de alto nivel puede ser algo así como:
do {
r1 = *(r2);
r1 = r1 +1; /* o r1++ */
*(r2) = r1
r2 = r2 +4; /* r2 +=4*/
}
while (r2 != r3)
Evidentemente este código no es muy de alto nivel, y sería más lógico definir un array
en lugar de usar punteros. Entonces sería algo como:
for (i=0 ; i<100; i++)
a[i]=a[i]+1;
donde a[i] es un array de enteros de 32 bits apuntado por r2.
2. Se trata de un bucle y de tres arrays. Vamos a usar el índice de cualquiera de los
arrays para decidir el límite del bucle, de forma análoga a problema anterior, por
ejemplo el de a[] apuntado por el registro genérico Ra. Como los RISC tienen muchos
registros y son ortogonales (es decir, sirven todos para todo), utilizaremos los registros
con letras para seguir mejor el código: Rb, Rc apuntan a b[], c[] y Rt hace de
acumulador t. Entonces hay que hacer las lecturas de memoria de un elemento de a, b y
c, y hacer las operaciones:
Bucle:
LD Fa, (Ra)0
LD Fb, (Rb)0
LD Fc, (Rc)0
MULD Fa, Fa, Fc
ADDD Fa, Fa, Fb
ADDD Ft, Ft, Fa
Se ha usado el mismo registro Fa para hacer de variable temporal donde ir calculando
los valores intermedios, y así ahorrar el uso de otro registro (análogamente se podrían
ahorrar más registros si no se hacen tres cargas seguidas sino sólo dos, se calcula el
producto, luego se hace otra carga y se calculan las sumas, hacerlo como ejercicio).
Por último han de incrementarse los punteros de los tres arrays y evaluar la condición de
salida del bucle (con Ra como se dijo), por ejemplo algo como:
ADD Ra, Ra, #8 ; incrementa 8 porque es double, doble precisión , 8 bytes
ADD Rb, Rb, #8
ADD Rc, Rc, #8
SGE R1, Ra, FinRa
; R1 es temporal para contener la comparación entre Ra y FinRa, que se
supone que apunta al final del array, es decir FinRa=RA inicial + 8*MAX
BEQZ R1, Bucle
3. Se trata de un bucle y de dos arrays apuntados por R7 y R8. R7 se incrementa pero
R8 se decrementa, y además controla la salida del bucle, ya que cuando R8 sea cero el
salto no se tomará. Es decir el array R8 empieza en la dirección 0x00000000 del
segmento de datos. Por otra parte los elementos apuntados por R7 y R8 se intercambian,
como se entiende ya que lo que se lee de (R8)0 se escribe en (R7)0 y viceversa. Todo se
explica en la siguiente figura:
Se incrementa
(R7)
Se intercambian
(R8)
Direcc 0x0
Se decrementa
Total que podría ser algo así, si a8 es el array de R8, y a7 es el de R7:
for (i=0; i<TAM_a8; i++)
{
temp = a8[TAM_a8-i-1]; /* el -1 es porque en C se indexa un array desde el 0 al TAM-1 */
a8[TAM_a8-i-1]=a7[i];
a7[i]=temp;
}
Si se ponen las instrucciones de suma y resta al principio del bucle, éste quedaría así:
Bucle:
ADDI R7, R7, #4
SUBI R8, R8, #4
LW R1, (R8)4
LW R2, (R7)-4
SW (R8)4, R2
SW (R7)-4, R1
BNEZ R8, Bucle
Es decir se han tenido que cambiar los desplazamientos de los direccionamientos, para
que el bucle siga siendo correcto; ya que si se incrementa antes de tiempo el registro R7,
hay que restar 4 al índice (R7) (recuérdese que admite signo el desplazamiento). Idem
pero al revés para R8
4. La solución podría ser algo así: (suponemos que R1 apunta inicialmente a z[127])
Bucle:
LD F0, 0(R1)
LD F4, 1024(R1)
MULTD F0, F0, F2
ADDD F0, F0, F4
SD 1024(R1), F0
SUBI R1, R1, #8
BNEZ R1, Bucle
; cargo z[i]
; cargo z[i+128]
; F2 contiene a ‘a’
; almaceno en z[i+128]
; condición de salida y decremento el puntero
ANEXO 1:
JUEGO DE INSTRUCCIONES DEL DLX
Instrucciones para la transferencia de datos
LB Rd,Adr
LBU Rd,Adr
LH Rd,Adr
LHU Rd,Adr
LW Rd,Adr
LF Fd,Adr
LD Dd,Adr
SB Adr,Rs
SH Adr,Rs
SW Adr,Rs
SF Adr,Fs
SD Adr,Fs
MOVI2FP Fd,Rs
MOVI2FP Rd,Fs
MOVF Fd,Fs
MOVD Dd,Ds
MOVI2S SR,Rs
MOVS2I Rs,SR
Load byte (sign extension)
Load byte (unsigned)
Load halfword (sign extension)
Load halfword (unsigned)
Load word
Load single-precision Floating point
Load double-precision Floating point
Store byte
Store halfword
Store word
Store single-precision Floating point
Store double-precision Floating point
Move 32 bits from integer registers to FP registers
Move 32 bits from FP registers to integer registers
Copy one Floating point register to another register
Copy a double-precision pair to another pair
Copy a register to a special register (not implemented!)
Copy a special register to a GPR (not implemented!)
Instrucciones lógicas y aritméticas para enteros
ADD Rd,Ra,Rb
ADDI Rd,Ra,Imm
ADDU Rd,Ra,Rb
ADDUI Rd,Ra,Imm
SUB Rd,Ra,Rb
SUBI Rd,Ra,Imm
SUBU Rd,Ra,Rb
SUBUI Rd,Ra,Imm
MULT Rd,Ra,Rb
MULTU Rd,Ra,Rb
DIV Rd,Ra,Rb
DIVU Rd,Ra,Rb
AND Rd,Ra,Rb
ANDI Rd,Ra,Imm
OR Rd,Ra,Rb
ORI Rd,Ra,Imm
XOR Rd,Ra,Rb
XORI Rd,Ra,Imm
LHI Rd,Imm
SLL Rd,Rs,Rc
SRL Rd,Rs,Rc
SRA Rd,Rs,Rc
SLLI Rd,Rs,Imm
SRLI Rd,Rs,Imm
SRAI Rd,Rs,Imm
S__ Rd,Ra,Rb
S__I Rd,Ra,Imm
S__U Rd,Ra,Rb
S__UI Rd,Ra,Imm
NOP
Add
Add immediate (all immediates are 16 bits)
Add unsigned
Add unsigned immediate
Subtract
Subtract immediate
Subtract unsigned
Subtract unsigned immediate
Multiply signed
Multiply unsigned
Divide signed
Divide unsigned
And
And immediate
Or
Or immediate
Xor
Xor immediate
Load high immediate - loads upper half of register with immediate
Shift left logical
Shift right logical
Shift right arithmetic
Shift left logical 'immediate' bits
Shift right logical 'immediate' bits
Shift right arithmetic 'immediate' bits
Set conditional: "__" may be EQ, NE, LT, GT, LE or GE
Set conditional immediate: "__" may be EQ, NE, LT, GT, LE or GE
Set conditional unsigned: "__" may be EQ, NE, LT, GT, LE or GE
Set conditional unsigned immediate: "__" may be EQ, NE, LT, GT, LE or GE
No operation
Instrucciones de Control
BEQZ Rt,Dest
BNEZ Rt,Dest
BFPT Dest
BFPF Dest
J Dest
JR Rx
JAL Dest
JALR Rx
TRAP Imm
RFE Dest
Branch if GPR equal to zero; 16-bit offset from PC
Branch if GPR not equal to zero; 16-bit offset from PC
Test comparison bit in the FP status register (true) and branch; 16-bit offset
from PC
Test comparison bit in the FP status register (false) and branch; 16-bit offset
from PC
Jump: 26-bit offset from PC
Jump: target in register
Jump and link: save PC+4 to R31; target is PC-relative
Jump and link: save PC+4 to R31; target is a register
Transfer to operating system at a vectored address; see Traps.
Return to user code from an execption; restore user mode (not implemented!)
Instrucciones en punto flotante
ADDD Dd,Da,Db
ADDF Fd,Fa,Fb
SUBD Dd,Da,Db
SUBF Fd,Fa,Fb
MULTD Dd,Da,Db
MULTF Fd,Fa,Fb
DIVD Dd,Da,Db
DIVF Fd,Fa,Fb
CVTF2D Dd,Fs
CVTD2F Fd,Ds
CVTF2I Fd,Fs
CVTI2F Fd,Fs
CVTD2I Fd,Ds
CVTI2D Dd,Fs
__D Da,Db
__F Fa,Fb
Add double-precision numbers
Add single-precision numbers
Subtract double-precision numbers
Subtract single-precision numbers.
Multiply double-precision Floating point numbers
Multiply single-precision Floating point numbers
Divide double-precision Floating point numbers
Divide single-precision Floating point numbers
Converts from type single-precision to type double-precision
Converts from type double-precision to type single-precision
Converts from type single-precision to type integer
Converts from type integer to type single-precision
Converts from type double-precision to type integer
Converts from type integer to type double-precision
Double-precision compares: "__" may be EQ, NE, LT, GT, LE or GE; sets
comparison bit in FP status register
Single-precision compares: "__" may be EQ, NE, LT, GT, LE or GE; sets
comparison bit in FP status register
Directivas del simulador WinDLX
.align n
.ascii "string1","..."
.asciiz "string1","..."
.byte byte1,byte2,...
.data [address]
.double number1,...
.global label
.space size
.text [address]
.word word1,word2,...
Cause the next data/code loaded to be at the next higher address with the
lower n bits zeroed (the next closest address greater than or equal to the
current address that is a multiple of 2n (e.g. .align 2 means the next word
begin).
Store the "strings" listed on the line in memory as a list of characters. The
strings are not terminated by a 0 byte.
Similar to .ascii, except each string is terminated by a 0 byte.
Store the bytes listed on the line sequentially in memory.
Cause the following code and data to be stored in the data area. If an address
was supplied, the data will be loaded starting at that address, otherwise, the
last value for the data pointer will be used. If we were just reading data based
on the text (code) pointer, store that address so that we can continue from
there later (on a .text directive).
Store the "numbers" listed on the line sequentially in memory as doubleprecision Floating point numbers.
Make the label available for reference by code found in files loaded after this
file.
Move the current storage pointer forward size bytes (to leave some empty
space in memory)
Cause the following code and data to be stored in the text (code) area. If an
address was supplied, the data will be loaded starting at that address,
otherwise, the last value for the text pointer will be used. If we were just
reading data based on the data pointer, store that address so that we can
continue from there later (on a .data directive).
Store the word listed on the line sequentially in memory.
Descargar