Tema 4: Aritmètica entera i matrius
22.1 Suma i resta
Enunciat: Problema 13.1.
Codificació en binari dels dos nombres de 16 bits:
El bit de més pes (bit 15) és 0 per a 0x0D34 i 1 per a 0xBA1D: les tres interpretacions coincideixen per al primer nombre i divergeixen per al segon.
0x0D34: com que el bit 15 és 0, el valor és el mateix en les tres representacions:
\[0 \cdot 16^3 + 13 \cdot 16^2 + 3 \cdot 16 + 4 = 3380\]
0xBA1D:
Natural: \(11 \cdot 16^3 + 10 \cdot 16^2 + 1 \cdot 16 + 13 = 47\,645\).
Enter en Ca2 (Secció 1.5.1): el bit 15 val
1, per tant, el nombre és negatiu. El valor absolut s’obté fent el complement a 2:0xBA1D→ invertir bits →0x45E2→ sumar 1 →0x45E3\(= 17\,891\). Resultat: \(-17\,891\). Comprovació: \(47\,645 - 2^{16} = -17\,891\) ✓Enter en signe-magnitud (Secció 1.5.3): bit de signe
1(negatiu) i magnitud als 15 bits restants:0x3A1D\(= 14\,877\). Resultat: \(-14\,877\).
Resum:
| a) Natural | b) Ca2 | c) Signe-magnitud | |
|---|---|---|---|
0x0D34 |
\(3380\) | \(+3380\) | \(+3380\) |
0xBA1D |
\(47\,645\) | \(-17\,891\) | \(-14\,877\) |
Enunciat: Problema 13.5.
El rang dels enters en Ca2 de 8 bits és \([-128, 127]\). Es produeix desbordament quan els dos operands tenen el mateix signe i el resultat en té de diferent.
a) \((-25) + (-34)\)
Codificació: \(-25 =\) 1110 0111, \(-34 =\) 1101 1110.
Càlcul
El resultat truncat a 8 bits és 1100 0101 = \(-59_{10}\) en Ca2. Els dos operands són negatius i el resultat també és negatiu: no hi ha desbordament. El resultat és correcte: \(-25 + (-34) = -59\).
b) \((-25) - (-34) = (-25) + 34\)
Codificació: \(-25 =\) 1110 0111. El subtrahend, \(-34 =\) 1101 1110, es nega complementant-lo i sumant-hi 1 (Secció 1.6.2): 0010 0001 + 1 = 0010 0010 (\(+34\)).
Càlcul
Resultat: 0000 1001 = \(+9_{10}\). Els operands tenen signes oposats: no hi ha desbordament. Correcte: \(-25 + 34 = +9\).
c) \((+127) - (-20) = (+127) + 20\)
Codificació: \(+127 =\) 0111 1111. El subtrahend, \(-20 =\) 1110 1100, es nega: 0001 0011 + 1 = 0001 0100 (\(+20\)).
Resultat: 1001 0011 = \(-109_{10}\) en Ca2. Tots dos operands eren positius, però el resultat és negatiu: hi ha desbordament. El resultat correcte seria \(+147\), que no és representable amb 8 bits en Ca2.
d) \((-128) - (-20) = (-128) + 20\)
Codificació: \(-128 =\) 1000 0000. El subtrahend negat és, com a c), \(+20 =\) 0001 0100.
Resultat: 1001 0100 = \(-108_{10}\) en Ca2. Els operands tenien signes oposats: no hi ha desbordament. Correcte: \(-128 + 20 = -108\).
Enunciat: Problema 13.6.
En sumar dos naturals de 32 bits, el resultat es trunca mòdul \(2^{32}\). Si hi ha ròssec (carry, \(c = 1\)), el valor retornat és \(S = A + B - 2^{32}\) i, com que \(B < 2^{32}\), es compleix \(S < A\) (i, simètricament, \(S < B\)). Si no n’hi ha, \(S = A + B \geq A\). Per tant:
\[c = 1 \iff S <_u A\]
que és exactament la indicació de l’enunciat. La comparació sense signe es fa amb sltu (Secció 3.3.1), que deixa el resultat booleà (0 o 1) directament en un registre, sense cap salt:
RV32I
Dues instruccions en total. Comparar el resultat amb qualsevol dels dos sumands és equivalent; s’ha triat t1.
Enunciat: Problema 13.7.
Les variables t1 i t2 contenen els sumands; el resultat ha d’anar a t0 i l’indicador de desbordament a t3 (1 si hi ha desbordament, 0 altrament), sense cap instrucció de salt.
La condició de desbordament en la suma de dos enters és: els operands tenen el mateix signe i el resultat té signe diferent (Equació 4.2):
\[v = \overline{(A_{31} \oplus B_{31})} \land (A_{31} \oplus S_{31})\]
RV32I
add t0, t1, t2 # t0 = t1 + t2 (resultat truncat a 32 bits)
xor t3, t1, t2 # t1 XOR t2: bit 31 = 0 si mateix signe
not t3, t3 # NOT(t1 XOR t2): bit 31 = 1 si mateix signe
xor t4, t1, t0 # t1 XOR resultat: bit 31 = 1 si signes diferents
and t3, t3, t4 # condició de desbordament als 32 bits
srli t3, t3, 31 # desplaça el bit 31 a la posició 0
# t3 = 1 si desbordament, 0 altramentAnàlisi pas a pas:
xor t3, t1, t2: el bit 31 és0sit1it2tenen el mateix signe,1si en tenen de diferent.not t3, t3: el bit 31 passa a ser1si els operands tenien el mateix signe.xor t4, t1, t0: el bit 31 és1si el signe del resultat és diferent del det1.and t3, t3, t4: el bit 31 és1si i només si es compleixen les dues condicions simultàniament: mateix signe als operands i signe diferent al resultat.srli t3, t3, 31: posa el bit de condició a la posició 0.
El programa no conté cap instrucció de salt: totes les operacions són aritmètiques o lògiques de cost \(\mathcal{O}(1)\).
22.2 Multiplicació
Enunciat: Problema 13.10.
El circuit treballa amb naturals. Per a operands de 6 bits, els registres P i MD tenen 12 bits i MR en té 6. A cada iteració:
- Si
MR[0] == 1:P = P + MD. MD = MD << 1.MR = MR >> 1.
Convenció de la taula: cada fila mostra l’estat final de la iteració; les columnes MR[0] i Acció indiquen el que s’ha executat en aquella iteració (decidit amb el valor de MR[0] abans del desplaçament); la fila inicial porta «—».
a) \(x =\) 101000 (\(40_{10}\)), \(y =\) 010011 (\(19_{10}\)). Resultat esperat: \(760_{10}\).
| Iter. | P (12 bits) | MD (12 bits) | MR (6 bits) | MR[0] | Acció |
|---|---|---|---|---|---|
| inicial | 000000 000000 |
000000 101000 |
010011 |
— | — |
| 1 | 000000 101000 |
000001 010000 |
001001 |
1 | suma |
| 2 | 000001 111000 |
000010 100000 |
000100 |
1 | suma |
| 3 | 000001 111000 |
000101 000000 |
000010 |
0 | no suma |
| 4 | 000001 111000 |
001010 000000 |
000001 |
0 | no suma |
| 5 | 001011 111000 |
010100 000000 |
000000 |
1 | suma |
| 6 | 001011 111000 |
101000 000000 |
000000 |
0 | no suma |
Resultat: \(P =\) 001011 111000\(_2 = 760_{10}\) ✓
b) \(x =\) 110110 (\(54_{10}\)), \(y =\) 000100 (\(4_{10}\)). Resultat esperat: \(216_{10}\).
| Iter. | P (12 bits) | MD (12 bits) | MR (6 bits) | MR[0] | Acció |
|---|---|---|---|---|---|
| inicial | 000000 000000 |
000000 110110 |
000100 |
— | — |
| 1 | 000000 000000 |
000001 101100 |
000010 |
0 | no suma |
| 2 | 000000 000000 |
000011 011000 |
000001 |
0 | no suma |
| 3 | 000011 011000 |
000110 110000 |
000000 |
1 | suma |
| 4 | 000011 011000 |
001101 100000 |
000000 |
0 | no suma |
| 5 | 000011 011000 |
011011 000000 |
000000 |
0 | no suma |
| 6 | 000011 011000 |
110110 000000 |
000000 |
0 | no suma |
Resultat: \(P =\) 000011 011000\(_2 = 216_{10}\) ✓
mul i div
Enunciat: Problema 13.13.
a) mul t3, t1, t2 amb resultat baix 0xFFFFFFFA i t1 = 0x00000002
mul calcula els 32 bits de menys pes del producte, és a dir, el producte mòdul \(2^{32}\) (RISC-V 4.2). Cal trobar un t2 tal que:
\[2 \cdot \texttt{t2} \equiv \texttt{0xFFFFFFFA} \pmod{2^{32}}\]
Com que el factor \(2\) i el mòdul (\(2^{32}\)) no són coprimers, la solució no és única: n’hi ha exactament dues, separades per \(2^{31}\):
t2 = 0xFFFFFFFD: interpretant els valors com a enters, \(2 \times (-3) = -6 =\)0xFFFFFFFA✓t2 = 0x7FFFFFFD: interpretant-los com a naturals, \(2 \times 2\,147\,483\,645 = 4\,294\,967\,290 =\)0xFFFFFFFA✓
Totes dues són coherents amb l’enunciat: els 32 bits de menys pes del producte són idèntics tant si els operands s’interpreten com a enters com si s’interpreten com a naturals — per això hi ha una única instrucció mul, mentre que per a la part alta cal distingir la interpretació amb mulh/mulhu/mulhsu (Secció 4.3.4 i Aprofundiment 4.7).
b) div t3, t1, t2 amb t1 = 0x00000005 i t2 = 0xFFFFFFFE
\(\texttt{t2} =\) 0xFFFFFFFE \(= -2\). La divisió entera trunca cap a zero (Essencial 4.3):
\[q = \operatorname{trunc}\!\left(\frac{5}{-2}\right) = \operatorname{trunc}(-2{,}5) = -2 \qquad \Rightarrow \qquad \texttt{t3} = \texttt{0xFFFFFFFE}\]
El residu té el signe del dividend i satisfà la identitat \(x = y \cdot q + r\):
\[r = 5 - (-2) \times (-2) = 5 - 4 = +1\]
c) Casos de desbordament en la divisió entera
Un únic cas: \(-2^{31} \div (-1)\), el resultat matemàtic del qual (\(+2^{31}\)) no és representable en Ca2 de 32 bits. RISC-V no genera cap excepció: div retorna \(-2^{31}\) i rem retorna \(0\) (Secció 4.4.3.1). La divisió per zero no és un cas de desbordament, sinó un cas especial amb resultat definit (div → \(-1\), rem → dividend).
22.3 Matrius
Nota: les solucions deixen les expressions aritmètiques als operands (NC*4, mat + 3*NC*4, mat + (3*NC + 11)*4) per fer visible l’invariant de cada càlcul d’adreces, tal com s’admet a la teoria i als exàmens (EC 2.3).
Enunciat: Problema 13.14.
L’adreça de mat[i][j] és \(@\texttt{mat} + (i \cdot \texttt{NC} + j) \cdot 4\).
a) mat[3][11] — fila i columna constants: tot és invariant.
b) mat[i][11] — fila variable, columna constant.
RV32IM
c) mat[3][j] — fila constant, columna variable.
RV32I
d) mat[i][j] — fila i columna variables.
RV32IM
e) mat[i+5][j-1]
Equivalent a mat[i'][j'] amb i' = i+5 i j' = j-1. Incorporant les constants als invariants:
RV32IM
f) mat[i*10+4][6]
La fila és i*10+4, la columna és la constant 6. La fila ja conté una multiplicació per 10 que no és potència de 2; les dues multiplicacions es fusionen en una: l’invariant 10*NC*4 permet resoldre-ho amb un únic mul.
mul
Enunciat: Problema 13.16.
Adreces dels dos elements segons l’Equació 4.3 (amb NC = N i \(T = 4\)), reagrupant els termes:
\[@\texttt{M[i][i+1]} = @\texttt{M} + (i \cdot N + i + 1) \cdot 4 = @\texttt{M} + 1 \cdot 4 + i \cdot (N+1) \cdot 4\]
\[@\texttt{M[i+1][i]} = @\texttt{M} + ((i+1) \cdot N + i) \cdot 4 = @\texttt{M} + N \cdot 4 + i \cdot (N+1) \cdot 4\]
Les dues adreces comparteixen el terme variable \(i \cdot (N+1) \cdot 4\): amb un únic mul n’hi ha prou. La part restant de cada adreça és un invariant que s’integra a la la corresponent:
RV32IM
# t0 = i, t1 = suma
li t4, (N+1)*4
mul t4, t0, t4 # d = i*(N+1)*4 (comú a les dues adreces)
la t2, M + 1*4 # invariant: @M[0][1]
add t2, t2, t4 # @M[i][i+1]
lw t2, 0(t2) # M[i][i+1]
la t3, M + N*4 # invariant: @M[1][0]
add t3, t3, t4 # @M[i+1][i]
lw t3, 0(t3) # M[i+1][i]
sub t2, t2, t3 # M[i][i+1] - M[i+1][i]
add t1, t1, t2 # suma += M[i][i+1] - M[i+1][i]Deu instruccions i una sola multiplicació. La traducció directa (calcular cada adreça per separat amb l’Equació 4.3) necessitaria dues multiplicacions i més instruccions.
func i main amb accés seqüencial
Enunciat: Problema 13.20.
C
a) Traducció de func amb accés seqüencial a veci
func és uninivell. El paràmetre veci arriba per a0 (adreça base del vector). j s’assigna a t0.
L’stride del recorregut per fila és 4 bytes (mida d’un int). El bucle es controla amb el punter; la variable j es manté, perquè se’n necessita el valor (veci[j] = j).
RV32I
func:
# a0 = @veci
mv t1, a0 # t1 = p = @veci[0]
addi t2, a0, 4*4 # t2 = sentinella = @veci[4]
li t0, 0 # j = 0
bgeu t1, t2, fibucle1 # comprovació inicial (longitud 4 > 0: mai no salta)
bucle1:
sw t0, 0(t1) # veci[j] = j
addi t1, t1, 4 # p += stride (4 bytes)
addi t0, t0, 1 # j++
bltu t1, t2, bucle1 # salta si p < sentinella
fibucle1:
retb) Traducció de main amb accés seqüencial a mati
main és multinivell (crida func). Com que p i fi han de sobreviure a la crida i func (apartat a) utilitza t0–t2, cal desar-los en registres segurs (s0, s1) en lloc de t0/t1: p → s0, fi → s1. Cal desar ra, s0 i s1 al bloc d’activació.
RV32I
main:
addi sp, sp, -12
sw ra, 8(sp)
sw s1, 4(sp)
sw s0, 0(sp)
la s0, mati # s0 = p = @mati[0][0] (segur: sobreviu a la crida)
addi s1, s0, 5*4*4 # s1 = fi = @mati[5][0]
bgeu s0, s1, fibucle2 # comprovació inicial (5 > 0: mai no salta)
bucle2:
mv a0, s0 # a0 = p
jal ra, func
addi s0, s0, 4*4 # p += 4 (4 ints = 16 bytes)
bltu s0, s1, bucle2
fibucle2:
lw s0, 0(sp)
lw s1, 4(sp)
lw ra, 8(sp)
addi sp, sp, 12
ret22.4 Accés seqüencial
Nota: com a la secció anterior, les solucions deixen les expressions aritmètiques als operands (N*4, (N+1)*4, 3*(N-1)*4, i també les directives .eqv) per fer visible l’stride de cada recorregut, tal com s’admet a la teoria i als exàmens (EC 2.3).
Enunciat: Problema 13.21.
A arriba per a0. N és una constant. Es demana accés seqüencial: les variables d’índex desapareixen de la traducció (el control es fa amb el punter i la sentinella), tret de l’apartat d, on i es conserva com a comptador. suma ocupa t2.
a) Suma de la fila 3: for (i = 0; i < N; i++) suma += A[3][i]
L’stride del recorregut per fila és 4 bytes.
L’adreça del primer element és @A[3][0] = @A + 3*N*4.
RV32I
# a0 = @A, t2 = suma (inicialitzada prèviament a 0)
li t3, 3*N*4
add t3, a0, t3 # t3 = p = @A[3][0]
li t4, N*4
add t4, t3, t4 # t4 = sentinella = @A[3][N]
bgeu t3, t4, fibucle # comprovació inicial
bucle:
lw t5, 0(t3) # A[3][i]
add t2, t2, t5 # suma += A[3][i]
addi t3, t3, 4 # p += stride (4 bytes)
bltu t3, t4, bucle
fibucle:b) Suma de la columna 4: for (i = 0; i < N; i++) suma += A[i][4]
L’stride del recorregut per columna és N*4 bytes.
L’adreça del primer element és @A[0][4] = @A + 4*4.
La sentinella és @A[N][4] = @A[0][4] + N*(N*4). Com que N és una constant, el desplaçament N*N*4 també ho és, i va directament a l’operand de li (EC 2.3): no cal mul.
RV32I
# a0 = @A, t2 = suma (inicialitzada prèviament a 0)
addi t3, a0, 4*4 # t3 = p = @A[0][4]
li t5, N*4 # stride = N*4
li t4, N*N*4 # N²*4
add t4, t3, t4 # t4 = sentinella = @A[N][4]
bgeu t3, t4, fibucle # comprovació inicial
bucle:
lw t6, 0(t3) # A[i][4]
add t2, t2, t6 # suma += A[i][4]
add t3, t3, t5 # p += stride (N*4 bytes)
bltu t3, t4, bucle
fibucle:c) Suma de la diagonal principal: for (i = 0; i < N; i++) suma += A[i][i]
D’un element A[i][i] al següent A[i+1][i+1] hi ha \(N + 1\) elements de distància: l’stride és (N+1)*4 bytes (fila «diagonal principal» de la taula de strides de Secció 4.6.4).
El primer element és @A[0][0] = @A, i la sentinella, @A + N*((N+1)*4): com a l’apartat b, el desplaçament és constant i va a l’operand de li.
RV32I
# a0 = @A, t2 = suma (inicialitzada prèviament a 0)
mv t3, a0 # t3 = p = @A[0][0]
li t5, (N+1)*4 # stride = (N+1)*4
li t4, N*(N+1)*4 # N * (N+1)*4
add t4, t3, t4 # t4 = sentinella
bgeu t3, t4, fibucle # comprovació inicial
bucle:
lw t6, 0(t3) # A[i][i]
add t2, t2, t6 # suma += A[i][i]
add t3, t3, t5 # p += stride ((N+1)*4 bytes)
bltu t3, t4, bucle
fibucle:d) Diagonal secundària saltant de 3 en 3: for (i = 0; i < N; i += 3) suma += A[i][N-1-i]
Entre dos elements accedits consecutivament, A[i][N-1-i] i A[i+3][N-1-(i+3)], la distància en elements és \(3N - 3 = 3(N-1)\): l’stride és constant, 3*(N-1)*4 bytes, i l’accés seqüencial és aplicable al càlcul d’adreces.
Ara bé, el nombre d’iteracions és \(\lceil N/3 \rceil\) i l’adreça de la sentinella no té una expressió senzilla. En aquest cas és més net conservar i com a comptador del bucle (la variable d’inducció sobreviu per al control) i avançar el punter només per a l’accés a A:
RV32I
# a0 = @A, t0 = i, t2 = suma (inicialitzada prèviament a 0)
li t0, 0 # i = 0
li t3, (N-1)*4
add t3, a0, t3 # t3 = p = @A[0][N-1]
li t5, 3*(N-1)*4 # stride = 3*(N-1)*4
li t4, N # invariant
bge t0, t4, fibucle # comprovació inicial
bucle:
lw t6, 0(t3) # A[i][N-1-i]
add t2, t2, t6 # suma += A[i][N-1-i]
add t3, t3, t5 # p += stride
addi t0, t0, 3 # i += 3
blt t0, t4, bucle
fibucle:Contrast entre els recorreguts per fila i per columna (apartats a i b): el recorregut per fila (apartat a) té stride 4, el recorregut per columna (apartat b) té stride N*4. Per a valors grans de N, el recorregut per columna genera moltes fallades de memòria cau, ja que cada accés aterra en una línia de memòria cau diferent. El recorregut per fila aprofita molt millor la localitat espacial (aquests conceptes s’estudien a Capítol 7).
Enunciat: Problema 13.23.
a) vector[i] = z[4][j]
Els paràmetres arriben per a0 (i) i a1 (j). La fila de z[4][j] és constant: l’invariant @z[4][0] = @z + 4*3*4 s’integra a la la (com a Exemple 4.11) i només cal escalar j. L’adreça de vector[i] s’obté escalant i:
RV32I
b) Constants del recorregut seqüencial
El bucle accedeix sempre a vector[2] (posició fixa) i recorre la columna 2 de z (int z[5][3]):
offset_vector: distància de@vectora@vector[2]→2*4= 8.offset_z: distància de@zal primer element del recorregut,z[0][2]→2*4= 8.stride: d’un elementz[k][2]al següent,z[k+1][2], hi ha una fila sencera (3int) →3*4= 12.max_dist: la sentinellat6s’assoleix (beq) després de les 5 iteracions → 5 vegades l’stride →5*3*4= 60.
short — traducció i inicialització
Enunciat: Problema 13.25.
a) Traducció a C del fragment
Els paràmetres arriben per a0 (@p1) i a1 (p2). El fragment calcula t2 = p2 + 3, l’escala per la mida d’un short (\(T = 2\); per això slli t2, t2, 1), el suma a la base @p1 i hi escriu un zero de 16 bits (sh):
b) Inicialització de p1 amb accés seqüencial
Sentències que falten (i a t0, p a t1):
Al fragment d’assemblador, els dos buits del cos del bucle són l’escriptura i l’avanç del punter. L’stride és \(T = 2\) bytes (mida d’un short): p++ es tradueix per addi t1, t1, 2, i l’escriptura de 16 bits, per sh:
RV32I
Nota: la inicialització p = p1 (mv t1, a0) no apareix al fragment de l’enunciat, que comença a li t0, 0; s’ha inclòs aquí per completesa.
Enunciat: Problema 13.28.
Versió inicial:
RV32I
a) Cost de la versió inicial
10 instruccions per iteració: les pseudoinstruccions es compten per les instruccions reals, i la en són dues, auipc i addi. Cost per iteració (model de costos: lw = 4, salt pres = 2, salt no pres = 1, resta = 1):
| Instrucció | Cost |
|---|---|
li t1, N |
1 |
bge (no pres, \(N\) vegades) |
1 |
la t2, v (auipc + addi) |
2 |
slli t3 |
1 |
add t2 |
1 |
lw t3 |
4 |
add t4 |
1 |
addi t0 |
1 |
j bucle (pres) |
2 |
| Total per iteració | 14 |
Inicialització: li t0, 0 = 1 cicle.
Última comprovació (\(i = N\)): li t1, N (1) + bge pres (2) = 3 cicles.
Total: \(1 + 14N + 3 = 14N + 4\) cicles.
b) Versió optimitzada (condició al final)
Es pot fer la comprovació inicial una sola vegada (si N > 0 sempre es compleix, es pot ometre si es pot garantir). Per ser fidel a la semàntica del while original:
RV32I
S’han extret li t1, N i la t2, v com a invariants fora del bucle (extracció d’invariants, Secció 2.8.5.1, prerequisit de tota optimització).
Instruccions per iteració:
| Instrucció | Cost |
|---|---|
slli t3 |
1 |
add t5 |
1 |
lw t3 |
4 |
add t4 |
1 |
addi t0 |
1 |
blt pres (\(N-1\) vegades) / no pres (última) |
2 / 1 |
| Total per iteració (menys la darrera) | 10 |
Inicialització: li t0 (1) + li t1 (1) + la t2 (2) + bge no pres (1) = 5 cicles.
Última iteració: blt no pres (1) → cost = \(10 - 2 + 1 = 9\) cicles.
Total: \(5 + 10(N-1) + 9 = 10N + 4\) cicles.
c) Reducció percentual per a \(N = 100\)
Versió inicial: \(14 \times 100 + 4 = 1404\) cicles.
Versió optimitzada: \(10 \times 100 + 4 = 1004\) cicles.
\[\text{Reducció} = \frac{1404 - 1004}{1404} \times 100 \approx \mathbf{28{,}5\ \%}\]
Enunciat: Problema 13.29.
a) Versió sense cap optimització (usant i explícitament, condició a l’inici)
RV32I
li t0, 0 # i = 0
li t1, N # N (invariant)
la t2, v # @v (invariant)
la t3, w # @w (invariant)
bucle:
bge t0, t1, fibucle # [ctrl]
slli t4, t0, 2 # i*4
add t5, t2, t4 # @v[i]
lw t5, 0(t5) # v[i]
slli t5, t5, 1 # v[i] * 2
add t6, t3, t4 # @w[i]
sw t5, 0(t6) # w[i] = v[i] * 2
addi t0, t0, 1 # i++
j bucle
fibucle:9 instruccions per iteració: bge, slli, add, lw, slli, add, sw, addi i j. Amb el model de costos de Problema 13.28 (memòria = 4 cicles, salt pres = 2, salt no pres = 1, resta = 1), 16 cicles.
b) Eliminació de la variable d’inducció (punters directes), mantenint la condició a l’inici
Es mantenen dos punters pv i pw que avancen en paral·lel amb stride 4, controlats amb la sentinella de pv. La condició es continua avaluant a l’inici de cada iteració (amb el salt incondicional j corresponent), sense aplicar encara l’optimització #2.
RV32I
7 instruccions per iteració: bgeu, lw, slli, sw, dues addi i j. Amb el mateix model de costos, 14 cicles.
c) Combinació amb l’avaluació de la condició al final
Partint de b), s’aplica l’optimització #2: la comprovació es fa una única vegada abans d’entrar al bucle (cas de zero iteracions) i el salt incondicional j se substitueix pel salt condicional bltu al final:
RV32I
la t0, v # t0 = pv = @v[0]
la t1, w # t1 = pw = @w[0]
li t2, N*4
add t2, t0, t2 # t2 = sentinella = @v[N]
bgeu t0, t2, fibucle # comprovació inicial
bucle:
lw t3, 0(t0) # *pv = v[i]
slli t3, t3, 1 # v[i] * 2
sw t3, 0(t1) # *pw = v[i] * 2
addi t0, t0, 4 # pv++
addi t1, t1, 4 # pw++
bltu t0, t2, bucle
fibucle:El cos del bucle conté:
| Instrucció | Nombre |
|---|---|
lw |
1 |
slli |
1 |
sw |
1 |
addi (pv++) |
1 |
addi (pw++) |
1 |
bltu (control) |
1 |
| Total | 6 |
Amb el mateix model de costos, 13 cicles per iteració (12 a la darrera, on bltu no és pres).
22.5 Divisió
Enunciat: Problema 13.30.
El circuit (Secció 4.4.2) prova de restar el divisor alineat a cada posició de pes, de la més significativa a la menys significativa. Paper dels registres, per a \(n = 32\):
- R (\(2n\) bits): comença amb el dividend \(x\) a la part baixa i zeros a la part alta; en acabar, la part baixa conté el residu.
- D (\(2n\) bits): comença amb el divisor \(y\) a la part alta (equival a \(y \cdot 2^n\)) i es desplaça una posició a la dreta a cada iteració: a la iteració \(i\)-èsima queda alineat amb el pes \(2^{n-i}\).
- Q (\(n\) bits): acumula els bits del quocient, del més significatiu al menys significatiu.
Algorisme iteratiu complet:
Pseudocodi: divisió amb restauració
A cada iteració es fa la resta de prova R − D: si el resultat no és negatiu (bit \(R_{2n-1}\) a 0), el divisor desplaçat «hi cap» i s’anota un 1 al quocient; si és negatiu, es restaura el valor de R sumant-hi D de nou, i s’anota un 0. Després de les \(n\) iteracions, Q conté el quocient i la part baixa de R, el residu (Algorisme 4.2; per a un seguiment numèric complet, Exemple 4.7 i Solució 22.16).
Enunciat: Problema 13.31.
El circuit treballa amb naturals. Per a operands de 6 bits, els registres R i D tenen 12 bits i Q en té 6. L’algorisme amb restauració a cada iteració:
D = D >> 1.R = R - D.- Si
R[11] == 0(resultat no negatiu):Q = (Q << 1) | 1. - Altrament (resultat negatiu):
R = R + D(restauració);Q = Q << 1.
Convenció de la taula: la columna «R − D» mostra el valor intermedi de la resta (abans de decidir si cal restaurar); la columna «R (final)» mostra l’estat ja restaurat si ha calgut; la fila inicial porta «—».
a) \(x =\) 101000 (\(40_{10}\)), \(y =\) 010011 (\(19_{10}\)). Resultat esperat: \(q = 2\), \(r = 2\).
| Iter. | D (12 bits) | R − D | Signe | Acció | R (final) | Q |
|---|---|---|---|---|---|---|
| inicial | 010011 000000 |
— | — | — | 000000 101000 |
000000 |
| 1 | 001001 100000 |
110111 001000 |
neg. | restaura; Q<<1 |
000000 101000 |
000000 |
| 2 | 000100 110000 |
111011 111000 |
neg. | restaura; Q<<1 |
000000 101000 |
000000 |
| 3 | 000010 011000 |
111110 010000 |
neg. | restaura; Q<<1 |
000000 101000 |
000000 |
| 4 | 000001 001100 |
111111 011100 |
neg. | restaura; Q<<1 |
000000 101000 |
000000 |
| 5 | 000000 100110 |
000000 000010 |
pos. | Q = (Q<<1)\|1 |
000000 000010 |
000001 |
| 6 | 000000 010011 |
111111 101111 |
neg. | restaura; Q<<1 |
000000 000010 |
000010 |
Quocient: \(Q = 000010_2 = 2_{10}\), residu: \(R[5:0] = 000010_2 = 2_{10}\) ✓
Verificació: \(19 \times 2 + 2 = 40\) ✓
b) \(x =\) 010101 (\(21_{10}\)), \(y =\) 100100 (\(36_{10}\)). Resultat esperat: \(q = 0\), \(r = 21\).
Com que \(x < y\), el quocient és 0 i el residu és \(x\) en totes les iteracions: el divisor desplaçat sempre és més gran que el dividend parcial i cal restaurar en cada pas.
| Iter. | D (12 bits) | R − D | Signe | Acció | R (final) | Q |
|---|---|---|---|---|---|---|
| inicial | 100100 000000 |
— | — | — | 000000 010101 |
000000 |
| 1 | 010010 000000 |
101110 010101 |
neg. | restaura; Q<<1 |
000000 010101 |
000000 |
| 2 | 001001 000000 |
110111 010101 |
neg. | restaura; Q<<1 |
000000 010101 |
000000 |
| 3 | 000100 100000 |
111011 110101 |
neg. | restaura; Q<<1 |
000000 010101 |
000000 |
| 4 | 000010 010000 |
111110 000101 |
neg. | restaura; Q<<1 |
000000 010101 |
000000 |
| 5 | 000001 001000 |
111111 001101 |
neg. | restaura; Q<<1 |
000000 010101 |
000000 |
| 6 | 000000 100100 |
111111 110001 |
neg. | restaura; Q<<1 |
000000 010101 |
000000 |
Quocient: \(Q = 000000_2 = 0_{10}\), residu: \(R[5:0] = 010101_2 = 21_{10}\) ✓
Enunciat: Problema 13.32.
El circuit (Algorisme 4.2) treballa amb registres R i D de \(2n = 64\) bits, que no caben en un registre d’RV32I. En lloc de simular-los amb parells de registres, s’usa una formulació equivalent: mantenir el divisor fix i desplaçar R a l’esquerra (desplaçar D a la dreta respecte de R equival a desplaçar R a l’esquerra respecte del divisor), injectant a cada pas el bit següent del dividend. Així tots els valors caben en registres de 32 bits. A més, en lloc de restar i restaurar, és més senzill comparar abans de restar (bltu), que és equivalent: només es fa la resta quan el resultat no seria negatiu.
Registres: t3 = dividend \(x\) (es va desplaçant; al final es reutilitza per al residu, com demana l’enunciat), t1 = divisor \(y\), t2 = quocient (Q), t4 = residu parcial (R), t5 = comptador, t6 = bit extret.
RV32I
li t2, 0 # Q = 0
li t4, 0 # R = 0
li t5, 32 # 32 iteracions (una per bit)
bucle:
slli t4, t4, 1 # R = R << 1
srli t6, t3, 31 # bit més significatiu de X
or t4, t4, t6 # R = (R << 1) | X[31]
slli t3, t3, 1 # X = X << 1 (consumeix el bit)
slli t2, t2, 1 # Q = Q << 1
bltu t4, t1, seguent # si R < y: bit de quocient = 0
sub t4, t4, t1 # R = R − y
ori t2, t2, 1 # Q = (Q << 1) | 1
seguent:
addi t5, t5, -1
bnez t5, bucle
mv t3, t4 # residu a t3El bucle s’executa exactament 32 vegades: el nombre d’iteracions és conegut i positiu, de manera que no cal comprovació inicial i el salt condicional va al final (Secció 4.6.2). En acabar, t2 conté el quocient i t3 el residu.