Tema 2: Instruccions i tipus de dades bàsics

11.1 Operands en registre

Vegeu Secció 2.6.1.

Problema 11.1 Traduïu els fragments següents de C a assemblador RISC-V. Suposeu que les variables f, g, h, i i j són enters de 32 bits assignats als registres t0, t1, t2, t3 i t4 respectivament.

  1. f = g + h + i + j
  2. g = f + (h + 5) - i

Problema 11.2 Traduïu els fragments següents d’assemblador RISC-V a C. Suposeu que les variables f, g, h, i i j són enters de 32 bits assignats als registres t0, t1, t2, t3 i t4 respectivament.

RV32I
        add     t0, t1, t2
        add     t1, t3, t4
        add     t1, t1, t1
        add     t0, t0, t1
RV32I
        add     t1, t1, t2
        add     t3, t3, t4
        add     t0, t1, t3
        addi    t0, t0, 2
        add     t0, t0, t0

11.2 Constants i immediats

Vegeu Secció 2.6.2 i RISC-V 2.16.

Problema 11.3 Donades les declaracions de variables del Codi 11.1, emmagatzemades a partir de l’adreça 0x10010000:

Codi 11.1: Quatre etiquetes, P, Q, R i S, amb paraules inicialitzades.
RV32I
.data
P:      .word   5, 2
Q:      .word   3
R:      .word   4, 0x0FFFF, 0x4180
S:      .word   0x10010008, 0

Tots els apartats parteixen del mateix estat inicial.

  1. Quin és el valor final de la variable Q després d’executar el Codi 11.2?
Codi 11.2: Codi de l’apartat a).
RV32I
.text
        la      t1, R
        lw      t2, 12(t1)
        lb      t1, 8(t2)
        la      t3, Q
        lb      t4, 0(t3)
        add     t1, t1, t4
        sb      t1, 0(t3)
  1. Expliqueu textualment i de forma concisa què fa el Codi 11.3:
Codi 11.3: Fragment de l’apartat b).
RV32I
.text
        la      t1, P+1
        lw      t1, 0(t1)

Nota: la sintaxi la label+offset és admesa a EC (teoria i exàmens), però a RARS cal substituir-la per la + addi.

Problema 11.4 Indiqueu quin és el contingut de memòria a partir de l’adreça 0x10010000, per paraules, per a la declaració de variables globals del Codi 11.4, amb les restriccions d’alineació de l’ABI (RISC-V 2.21; un .dword s’alinea a 8 bytes, encara que RARS 1.6 l’alinea a 4):

Codi 11.4: Declaració de bytes, mitges paraules, paraules i una doble paraula.
RV32I
.data
        .byte   0, 1, 2
P:      .byte   5, -1
Q:      .half   0x66
R:      .word   4, 0x0FDF
S:      .half   3
T:      .byte   25
U:      .byte   0x08
V:      .dword  0x10010008

Problema 11.5 En RISC-V, la pseudoinstrucció li rd, imm s’expandeix en una sola instrucció real (addi) si l’immediat cap en 12 bits amb extensió de signe, i en dues (lui + addi) si no hi cap.

  1. Quina seqüència d’instruccions genera l’assemblador per carregar el valor 0xDEADBEEF al registre t0? Calculeu els valors exactes dels operands de cada instrucció.
  2. Per què cal ajustar el camp immediat d’addi quan el bit 11 del valor original és 1? Il·lustreu-ho amb el valor 0xDEADBEEF.
  3. Quin és el rang de valors immediats que accepta addi (és a dir, el rang de constants que es pot carregar a un registre amb addi rd, zero, imm)? I quin és el rang de constants que es pot carregar a un registre amb la seqüència lui + addi?

11.3 Operands en memòria

Vegeu Secció 2.6.3.

Problema 11.6 Donada la declaració de dades del Codi 11.5, emmagatzemada a partir de l’adreça 0x10010000:

Codi 11.5: Declaració de bytes i paraules sense etiqueta.
RV32I
.data
        .byte   1, 2, 3, 4
        .word   -1, 1, -2, 2, -3, 3
        .word   0x12345678

Indiqueu quin és el valor en hexadecimal del byte emmagatzemat a cada una de les adreces 0x1001000C i 0x1001001C. Si no es pot determinar a partir de la declaració, indiqueu-ho amb la sigla de no aplicable (NA).

Problema 11.7 Donats els continguts inicials de registres i memòria següents (en hexadecimal):

t0 = 0x10010000, t2 = 0x10010008

Adreça Contingut (byte a byte, hex)
0x10010000 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
0x10010010 00 00 00 00 EC FD 0E 0F 00 00 00 00 00 00 00 00

Determineu, per a cada instrucció, quin registre o adreça de memòria es modifica i quin és el seu contingut:

RV32I
        lw      t1,  0(t0)
        lw      t3,  0(t2)
        sw      t3, -8(t2)
        lw      t4,  4(t0)
        sw      t1, -4(t2)
        sw      t4,  0(t2)

Problema 11.8 Donada la declaració del Codi 11.6:

Codi 11.6: Vector A de cinc bytes.
RV32I
.data
A:      .byte   0, 0, 0, 0, 0

Escriviu un fragment de no més de 12 línies de codi assemblador que guardi el valor complet de t1 (32 bits) a partir de l’adreça A+1, sense produir cap excepció d’alineació. Podeu escriure valors temporals a la posició A de memòria si cal (és una adreça alineada a paraula).

Problema 11.9 Indiqueu quin és el contingut de memòria a partir de l’adreça 0x10010000, byte a byte, per a la declaració de variables globals del Codi 11.7, amb les restriccions d’alineació de l’ABI (RISC-V 2.21; un .dword s’alinea a 8 bytes, encara que RARS 1.6 l’alinea a 4):

Codi 11.7: Declaració de bytes, mitges paraules, paraules i dobles paraules, amb caràcters.
RV32I
.data
        .byte   0x10
P:      .half   -5
Q:      .word   -1, 67
R:      .byte   -4, '5', 6
S:      .half   66, 67
T:      .dword  0x5799
U:      .byte   'C'
V:      .half   0x66
W:      .dword  579

Problema 11.10 RISC-V és una arquitectura little-endian.

  1. Expliqueu què significa little-endian i en quin ordre s’emmagatzemen els bytes d’un enter de 32 bits a memòria.
  2. La variable global int x = 0x12345678 s’emmagatzema a partir de l’adreça 0x10010000. Indiqueu el contingut byte a byte de les adreces 0x10010000 a 0x10010003.
  3. Després d’executar el Codi 11.8, quin valor té t1? Raoneu la resposta tenint en compte l’ordre dels bytes.
Codi 11.8: Codi de l’apartat c).
RV32I
.data
x:      .word   0x12345678
.text
        la      t0, x
        lb      t1, 0(t0)
  1. Quin hauria de ser el resultat si l’arquitectura fos big-endian?

Problema 11.11 Suposeu que el registre t0 conté l’adreça 0x10010000 i que la memòria té el contingut inicial següent:

Adreça +0 +1 +2 +3
0x10010000 11 22 CC DD
  1. Determineu el valor dels registres resultants de l’execució de cada instrucció (de forma independent, partint sempre del contingut inicial de memòria). Raoneu l’extensió de signe o per zero quan sigui rellevant.
Instrucció Resultat al registre
lb t1, 1(t0)
lb t1, 2(t0)
lh t1, 0(t0)
lh t1, 2(t0)
lbu t1, 2(t0)
lhu t1, 2(t0)
  1. Determineu l’estat final de la memòria després d’executar les instruccions del Codi 11.9 de forma seqüencial (una rere l’altra, partint del contingut inicial):
Codi 11.9: Un lb i un sb.
RV32I
        lb      t1, 2(t0)
        sb      t1, 1(t0)

11.4 Representació de naturals i enters

Vegeu els problemes del Tema 1: Introducció: complement a 2, complement a 1, signe i magnitud i excés.

11.5 Representació de caràcters

Vegeu Secció 2.9.

Problema 11.12 Donades les declaracions del Codi 11.10:

Codi 11.10: Dos dígits en ASCII, u1 i u2, i el byte del resultat, d3.
RV32I
.data
u1:     .byte   '9'
u2:     .byte   '3'
d3:     .byte   0

Cadascuna de les dades u1 i u2 conté un caràcter ASCII que representa un dígit decimal individual. Escriviu un programa en assemblador que sumi els naturals representats per u1 i u2 i deixi el resultat en binari (natural) a d3. Com que cada operand és un sol dígit (rang \([0, 9]\)), la suma màxima és \(9+9=18\) i sempre cap en un sol byte.

Problema 11.13 Escriviu en hexadecimal el contingut de memòria ocupat per les declaracions del Codi 11.11, suposant que comencen a emmagatzemar-se a partir de l’adreça 0x10010000, amb les restriccions d’alineació de l’ABI (RISC-V 2.21):

Codi 11.11: Declaració de mitges paraules, bytes, paraules i una doble paraula.
RV32I
.data
p:      .half   54
q:      .byte   'C'
r:      .half   0xAAAA
s:      .word   0x4F3C
t:      .byte   -18
u:      .dword  0x00000000FFFFEEEE

Feu servir el format següent:

Adreça Contingut (byte a byte, hex)
0x10010000 __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __
0x10010010 __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __

Problema 11.14 Escriviu en hexadecimal el contingut de memòria ocupat per les declaracions del Codi 11.12, suposant que comencen a emmagatzemar-se a partir de l’adreça 0x10010000. Recordeu que la directiva .align 0 desactiva l’alineació automàtica fins al final del segment .data actual (cap .align k amb \(k>0\) posterior no la reactiva):

Codi 11.12: Declaració amb .align 0 i .align 1.
RV32I
.data
        .align 0
        .byte   24
        .align 1
Q:      .byte   'A', 'C', 'E'
R:      .half   512, 0xAAAA
S:      .word   0x43, 0xF3C, 'a'
T:      .byte   -18, 'A'

Feu servir el format següent:

Adreça Contingut (byte a byte, hex)
0x10010000 __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __
0x10010010 __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __

Problema 11.15 Donada la declaració en C:

C
char X = 'C';
int  Y = -1;
  1. Traduïu la declaració a llenguatge assemblador RISC-V.
  2. Especifiqueu el valor hexadecimal de t0 després d’executar el Codi 11.13:
Codi 11.13: Codi de l’apartat b).
RV32I
.text
        la      t0, X
        la      t1, Y
        lb      t0, 0(t0)
        lw      t1, 0(t1)
        add     t0, t0, t1

11.6 Format de les instruccions

Vegeu Secció 2.2.

Problema 11.16 Convertiu les instruccions d’assemblador RISC-V següents a llenguatge màquina (format binari i hexadecimal):

Assemblador RISC-V Binari Hexadecimal
add t4, t3, t5
addi t6, t5, 25
lw t3, 0(t2)
sw t0, 0(t1)

Problema 11.17 Desassembleu els valors hexadecimals següents a les instruccions RISC-V corresponents:

  1. 0x00B50633
  2. 0xFFC50413
  3. 0x0062A023
  4. 0x0062A2B3 (instrucció slt, presentada al Tema 3: Traducció de programes; vegeu Secció 3.3.1)

Problema 11.18 S’estudien dues modificacions possibles a l’arquitectura RISC-V:

  1. Passar de 32 registres a 8 registres.
  2. Passar de 12 bits per a l’operand immediat a 6 bits.

Per a cadascuna d’elles contesteu:

  1. Quin impacte tindria en la mida total d’una instrucció de tipus R?
  2. I en la mida total d’una instrucció de tipus I?

11.7 Punters

Vegeu Secció 2.7.

Problema 11.19 Suposeu les declaracions en C del Codi 11.14:

Codi 11.14: Dos punters globals i dos de locals.
C
int *m1, *m2;   // m1 i m2 són punters a int (en memòria)
void main() {
    int *r1, *r2;   // r1 i r2 són punters a int (en registre)
    ...
}

Suposant que r1 i r2 ocupen els registres t1 i t2, traduïu a assemblador RISC-V les sentències en C següents, pertanyents a main:

  1. r1 = r2;
  2. *r1 = *r2;
  3. m1 = m2;
  4. *m1 = *m2;

Problema 11.20 Donada la declaració de dades global en C:

C
int *pdada;

Traduïu a una única sentència en C el conjunt d’instruccions de cada apartat:

RV32I
        la      t0, pdada
        lw      t0, 0(t0)
        lw      t1, 0(t0)
        addi    t1, t1, 4
        sw      t1, 0(t0)
RV32I
        la      t0, pdada
        lw      t1, 0(t0)
        addi    t1, t1, 4
        sw      t1, 0(t0)
RV32I
        la      t0, pdada
        lw      t0, 0(t0)
        lw      t1, 0(t0)
        addi    t0, t0, 4
        sw      t1, 0(t0)

Problema 11.21 Donades les declaracions en C:

C
int vec[6] = {2, 4, 0, 6, 8, 0};
int *punter;

Traduïu a una única sentència en C el conjunt d’instruccions de cada apartat:

RV32I
        la      t0, punter
        la      t1, vec+8
        sw      t1, 0(t0)
RV32I
        la      t0, punter
        lw      t1, 0(t0)
        addi    t1, t1, 4
        sw      t1, 0(t0)
RV32I
        la      t1, vec
        lw      t3, 0(t1)
        lw      t4, 4(t1)
        add     t3, t3, t4
        sw      t3, 4(t1)
RV32I
        la      t1, vec
        la      t0, punter
        lw      t2, 0(t0)
        lw      t3, 0(t2)
        addi    t3, t3, 1
        sw      t3, 8(t1)
RV32I
        la      t0, punter
        lw      t2, 0(t0)
        lw      t3, 0(t2)
        addi    t3, t3, 1
        sw      t3, 8(t2)

Problema 11.22 Donades les declaracions de variables globals en C:

C
char      *punterc;
short     *punterh;
int       *punteri;
long long *punterd;

Traduïu a assemblador RISC-V les sentències següents:

  1. punterc++;
  2. punteri++;
  3. punterh++;
  4. punterd++;
  5. *punteri = *punteri + 5;
  6. *punterh = *punterh + 10;

Problema 11.23 Donades les declaracions en C:

C
char          a;
int           b;
long long int c;
void main() {
    char          *p;   // guardat a t0
    int           *q;   // guardat a t1
    long long int *h;   // guardat a t2
    ...
}

Traduïu a assemblador RISC-V les sentències en C següents, pertanyents a main:

  1. q = q + 1;
  2. a = *p;
  3. h = &c;
  4. b = *(q + b);
  5. *h = *(h + b);
  6. p[*q + 10] = a;
  7. h = &h[*p];

Problema 11.24 Donades les declaracions en C:

C
int  dada;
int *pdada;

Traduïu a assemblador RISC-V les sentències en C següents:

  1. pdada = &dada;
  2. *pdada = *pdada + 1;
  3. pdada = pdada + 1;
  4. dada = dada - 1;

11.8 Vectors

Vegeu Secció 2.8 i Secció 2.8.5.

Problema 11.25 Donades les declaracions en C:

C
char  indx[100];    // enters d'1 byte
short meitat[100];  // enters de 2 bytes
int   val[100], vec[100];  // enters de 4 bytes
void main() {
    char c;
    int  i, j;
    ...
}

Traduïu les sentències en C següents, suposant que i, j i c ocupen els registres t0, t1 i t2:

  1. i = val[5] + vec[10];
  2. i = vec[10 + val[5]];
  3. c = indx[i + val[j]];
  4. c = indx[meitat[i]];
  5. i = meitat[vec[i] + val[j]];
  6. i = val[meitat[i]] + vec[j];
  7. i = vec[indx[i]] - val[j];
  8. i = meitat[indx[val[j]]];

Problema 11.26 Donades les declaracions en C:

C
int v[10];
void main() {
    int i, suma = 0;  // i a t0, suma a t1
    ...
}
  1. Escriviu en assemblador RISC-V el bucle que inicialitza tots els elements de v a zero.
  2. Escriviu el bucle que calcula la suma de tots els elements de v i deixa el resultat a suma.
  3. Escriviu el bucle que copia els elements de v al revés en un nou vector w de la mateixa longitud declarat a continuació de v.

Problema 11.27 Donada la declaració en C:

C
int vec[100];
void main() {
    int i, val;  // i a t0, val a t1
    ...
}

Escriviu en assemblador RISC-V un fragment de codi que cerqui el valor de val dins vec i deixi a t2 l’índex de la primera ocurrència, o −1 si no s’hi troba.

Problema 11.28 Donades les declaracions en C:

C
short v[8] = {10, 20, 30, 40, 50, 60, 70, 80};
void main() {
    short *p = v;   // p a t0
    int i;          // i a t1
    ...
}
  1. Escriviu en assemblador RISC-V la sentència p = v + 3; i expliqueu de quants bytes s’incrementa el punter.
  2. Escriviu el bucle que, usant el punter p, dobla el valor de cada element del vector.

11.9 Cadenes de caràcters

Vegeu Secció 2.9.4.

Problema 11.29 Traduïu a assemblador RISC-V el programa en C del Codi 11.15, que escriu a la cadena minus els caràcters ASCII en minúscules corresponents a cada element del vector vec:

Codi 11.15: Programa que omple la cadena minus a partir del vector vec.
C
#define N 8
char         minus[N+1];
unsigned int vec[N] = {70, 85, 78, 67, 73, 79, 78, 65};

void main() {
    int i = 0;
    while (i < N) {
        minus[i] = (char)vec[i] + 'a' - 'A';
        i++;
    }
    minus[N] = 0;
}

Problema 11.30 Escriviu en assemblador RISC-V una funció longitud que, donada una cadena de caràcters acabada en '\0' amb adreça base a a0, retorni la seva longitud (sense comptar el '\0') a a0.

Problema 11.31 Donades les declaracions en C:

C
char src[50], dst[50];

Escriviu en assemblador RISC-V un fragment de codi que copiï el contingut de src a dst, incloent-hi el caràcter '\0' de final.