Esercizi Assembly
Un programma per calcolare la media
Dato un vettore di 32 bytes unsigned memorizzato a
partire dalla locazione 0x20a0, calcolarne la media e
memorizzarne il valore sovrascrivendo l’ultima
posizione del vettore. Se viene rilevato un overflow
in V[31] e’ posizionato il valore ff ff ff ff
0x20a0
V[0]
V[1]
V[2]
…
V[31]
V[31]=_i=031V[i]/32
Come gestire l’overflow?
L’istruzione da controllare e’:
addb (R1)+, R2
Microcodice :
1.
MAR<-R1
2.
R1<-R1+1
3.
Temp1<-[MDR] 8 //gli 8 lsbs di MDR estesi in segno vanno in T1
4.
Temp2<-[R2] 8 //gli 8 lsbs di R2 estesi in segno vanno in T2
5.
ALU_OUT=Temp1+Temp2
Se (Temp1 + Temp2) >232-1 il CARRY bit viene settato per
segnalare l’overflow. Quindi , e’ sufficiente far seguire
all’operazione di somma un salto condizionato del tipo:
jc error
org 400h
ARRAY
DIM
LOG2DIM
loop:
error:
fine:
Il codice
EQU 20a0h
EQU 32
EQU 5
; indirizzo base array
; num.elementi array
; log. base 2 di DIM
code
movl #DIM,R0
movl #ARRAY,R1
xorl R2,R2
;resetta R2, risultato parziale
addb (R1)+,R2
;somma i-esimo elem. i=0..DIM-1
jc error
;bit c settato =>Overflow
subl #1,R0
;decrementa contatore
jnz loop
;se contatore!=0 continua il cicla
lsrb #LOG2DIM, R2;dividi per il numero di elementi,
;usiamo LSRB poichè lavoriamo con unsigned
movb R2, -(R1)
;memorizza la media in ARRAY[DIM-1]
jmp fine
movl #DIM, R1
;gestione overflow, calcola in R1
addl #ARRAY, R1 ; R1=ARRAY+DIM
subl #1,r1
xorl R3,R3
notl R3,R3
; R3=111....111
movb R3,(R1)
; ARRAY[DIM]=11111111
halt
end
Una variazione sul tema…
ora, senza contatore!
Calcolare la media di 128 words memorizzate a
partire dall’indirizzo 0x20ab, ma senza impiegare
un registro appositamente come contatore (R0 del
programma precedente) .
0x20 ab
0x20ad
V[0]
V[1]
V[2]
…
0x21a9
0x21 ab
V[127]
NOTA: non si considera
l’overflow.
V[127]=_i=0127V[i]/127
Il codice
(funziona solo se il numero di elementi è pari a 128 words)
org 400h
DATI
EQU 20abh
code
main:
xorl R2,R2
movl #DATI,R1
movb R1,R0
loop:
addw (R1)+, R2
cmpb R1,R0
jnz loop
lsrw #7,R2
movw R2,-(R1)
halt
end
; programma allocato a partire da 400h
;indirizzo inizio
;inizio istruzioni
; R2=risult.parziale
; puntatore elemento
; copio lsB addr. inizio
; in R0
; lsB addr. elemento
; e' = lsB addr. inizio ?
; divido per 128
;serve solo per bloccare il simulatore
;fine della compilazione
Un altro esempio: la moda
Assumiamo di avere un vettore,V, di N bytes che
memorizza nella posizione i-esima l’altezza in
centimetri dell’i-esimo studente.
altezza
PROBLEMA:
Trovare l’altezza piu’ frequente
tra gli studenti (moda).
id-studente
Prima soluzione:
vettore di frequenze
Vogliamo calcolare la moda, costruendo innanzitutto
un vettore di frequenze, F, di 255 longwords, che
associ in posizione j, il numero di ricorrenze
dell’altezza j nel vettore di partenza V.
num.studenti
Probabilmente: F[j]=0 se i<50 o i>220
Osservazione:
Noto il vettore delle frequenze F, il
calcolo della moda si riconduce a
determinare per quale i, F[i]=max{F}
cm.
L’algoritmo per il calcolo delle frequenze
Possiamo costruire F in 2 passi.
1) Inizializziamo l’array F, di 255 longwords, con tutti 0.
for (i=0;i<256;i++) {
array2[i]=0;
}
2) Memorizziamo le frequenze in F scandendo una sola volta V e
incrementando di volta in volta l’elemento di F in posizione V(i) di 1.
for (i=0;i<N;i++) {
index=array1[i];
array2[index]++;
}
Codice
org 1400h
array1 equ 800h
array2 equ 1500h
dim equ 30
code
; V, vettore originale
; F, vettore frequenze
;inizializzo array2 con tutti 0
; for (i=0;i<256;i++) {
;
array2[i]=0;
;}
;
MOVL #array2,R5
movl #0,r4
clean:
movl #0, (R5)+
addl #1,r4
cmpl #0ffh,r4
jc clean
; r4 è inizializzato a zero perchè la successiva mvlb
; si aspetta i 3 bytes + significativi di R4 uguali a 0
mvlb array1(R3),R4 ;R4=V[i]=array1[R3]
;NOTA: MVLB non estende il segno
aslw #2,R4
;offset_array2=R4*4
;Moltiplicando per 4 il contenuto
;del lsb di R4 possiamo avere trabocchi,
;quindi usiamo aslw per operare con 2 byte
movl array2(R4),r5 ;r5=array2[offset_array2]
addl #1,r5
; r5=array2[offset_array2]+1
addl #array2,r4
; prima r4 era = offset_array2, ora
;r4=offset_array2+base_add_array2
movl r5,(r4) ;array2[offset_array2]=array2[offset_array2]+1
addl #1,R3
; i=i+1
cmpl #R2,R3
jnz count
;R2 base dell'array
; memorizzo frequenze in array2
; for (i=0;i<N;i++) {
;
index=array1[i];
;
array2[index]++;
;}
MOVL #dim,R2
XORL R3,R3
array1;
count: xorl r4,r4
;R2 dimensione di array1
;R3=0, contatore e offset per
halt
end
Prima soluzione:
determiniamo il max su F
Ora che abbiamo il vettore delle frequenze, il
calcolo della moda si riconduce a determinare per
quale i, F[i]=max{F}
num.studenti
170=moda
cm.
Codice
org 1400h
array2 equ 1500h
code
MOVL #255,R1
;copia il lsb byte in R1
ASLL #2,R1
ADDL #array2,R1 ; in R1 c’è l’indirizzo dell 256° elemento di Array2
MOVL #array2,R2 ;R2 puntatore all'array
XORL R3,R3
;R3=0;
MOVL #1,R4
;R4=1
loop:
MOVL (R2)+,R5
CMPB R5,R3
JNC skip
; se R3>=R5 salta a skip
MOVL -(R2),R3
; in R3 c'è il massimo temp.
MOVL R2,R4
; in R4 c'è l'indice corrisp.all'elemento massimo
ADDL #4,R2
skip:
CMPB R2,R1
jnz loop
; condizione di uscita dal ciclo
SUBL #ARRAY2,R4
; R4=[OFFSET_MAX_FREQUENZA*4]
ASRL #2,R4
; R4 / 4=OFFSET_MAX_FREQUENZA
halt
end
Ancora Moda… evitiamo il calcolo del
vettore delle frequenze
Dato un vettore di DIM dati da un byte, rappresentati come unsigned trovare:
1) l’elemento con il massimo numero di ricorrenze (moda)
2) il corrispondente numero di ricorrenze
L’ALGORITMO
MAX_NUM=0; //memorizza la moda
MAX_RIC=0; //memorizza il numero di ricorrenze della moda
FOR INT I=0 TO DIM-1 {
IF ((I==0) || ( (I!=0) && (A[I]!=MAX_NUM) ) ) {
// Conta il numero di ricorrenze dell’elemento i-esimo se e solo se I=0, oppure
// I!=0 e l’elemento A[I] non è già la moda
TEMP_RIC=0;
FOR INT J=I TO DIM-1
{ IF A[J]=A[I] TEMP_RIC++; }
IF (TEMP_RIC>MAX_RIC) {MAX_RIC=TEMP_RIC; MAX_NUM=A[I];}
}
Codice
ORG 400H
ARRAY EQU 1000H
DIMEQU 10
MAXNUM EQU 950H
MAXRIC EQU 951H
CODE
XORL R0,R0 ; MAXNUM=0
XORL R1,R1 ; MAXRIC=0
XORL R2,R2 ; I=0
FOR1:
MOVB ARRAY(R2),R5; R5=A[I]=ARRAY(R2)
CMPL #0,R2
JZ DOIT
; IF (I==0) JMP DOIT
CMPB R5,R0 ; ELSE IF A[I]== MAXNUM
JZ NOMAX ; JMP NOMAX (SKIP INNER CICLE)
DOIT:
MOVL R2,R3 ;J=I
XORL R4,R4 ;TEMPRIC=0
FOR2:
CMPB ARRAY(R3), R5 ; IF A[I]!=A[J]
JNZ NOADD
; SKIP ADD
ADDL #1,R4
; TEMPRIC++
NOADD:
ADDL #1,R3
; J++
CMPL #DIM,R3
; IF (J!=N) GOTO FOR2
JNZ FOR2
CMPL R4,R1
; IF MAXRIC>TEMPRIC
JNC NOMAX
; SKIP UPDATING MAX
MOVL R4,R1
; MAXRIC=TEMPRIC
MOVB ARRAY(R2),R0; MAXNUM=A[I]
NOMAX:
ADDL #1,R2
CMPL #DIM,R2
JNZ FOR1
; I++
; IF (R2!=DIM)
; GOTO FOR1
MOVB R0, MAXNUM
MOVL R1, MAXRIC
HALT
END
Inversione di un array
Dato un array di 10 elementi, memorizzato a partire
da 250h, rimpiazzarlo con l’array inverso (senza
usare un altro vettore di appoggio).
250h
254h
258h
25Ch
260h
264h
268h
26Ch
270h
274h
prima
11
1
21
5
2
13
4
8
9
3
250h
254h
258h
25Ch
260h
264h
268h
26Ch
270h
274h
dopo
3
9
8
4
13
2
5
21
1
11
Il primo passo di esecuzione
R3=10/2=5
11
1
21
5
2
13
4
8
9
3
scambia (R1) con (R2)
R1
R2
11
1
21
5
2
13
4
8
9
3
R3=R3-1=4
3
1
21
5
2
13
4
8
9
11
R1
R2
Rappresentazione dell’informazione
250h
254h
258h
25Ch
260h
264h
268h
26Ch
270h
274h
11
1
21
5
2
13
4
8
9
3
336 (dec)
340
344
348
352
356
360
364
368
372
258h
259h
25ah
25bh
00010101
00000000
00000000
00000000
Base_Addr(Array)
+
(DIM-1)*size_of(elem) =
Addr(Array[DIM-1])
9*4=36 (OFFSET)
344
345
346
347
336 +
9*4=
372
Il codice
ORG 400H
DIM EQU 10
ARRAY EQU 250H
CODE
MOVL #ARRAY,R2
MOVL #DIM,R4
SUBL #1,R4
ASLL #2,R4 ; offset da sommare alla base dell'array per ottenere l'ultimo elemento
ADDL R4,R2 ; in R2 c'è l'indirizzo dell'ultimo elemento dell'array
MOVL #ARRAY,R1 ; R1 <-indirizzo array
MOVL #DIM,R3 ; R3<-10 (000... 00001010)
ASRL #1,R3 ; R3=R3/2=5 (000... 000000101)
REPEAT:
MOVL (R1),R0; R0 registro d'appoggio per lo scambio
MOVL (R2),(R1); Copia memoria memoria dell'"ultimo" elemento sul "primo"
MOVL R0,(R2); recupera il valore del primo elemento da R0 e copialo in coda
ADDL #4,R1; avanza di 4 byte il valore dell'offset sul vettore originale
SUBL #4,R2; decrementa di 4 byte il valore dell'offset sul vettore invertito
SUBL #1,R3; decrementa il contatore
JNZ REPEAT; fino a 0
HALT
END
Un algoritmo per la moltiplicazione
Il set di istruzioni del PD32 non prevede istruzioni per
effettuare la moltiplicazione tra due operandi.
La moltiplicazione puo’ essere realizzata banalmente
sommando al moltiplicando se stesso, un numero di volte
pari al valore del moltiplicatore. 5*3=5+5+5=15.
Tale algoritmo ha complessità computazionale pari a O(N),
dove N è il valore del moltiplicatore.
Vogliamo proporre un algoritmo per la moltiplicazione la cui
complessità sia pari a O(log2N).
Moltiplicazione: primo approccio
00110 x
00101 =
00110
00000
00110
somme
00000
parziali
00000
000011110
00000
00110
00110
00000
000110
00110
0011110
00000
00011110
00000
000011110
+
somma
parziale
+
+
“prodotto
parziale”
+
+
Risultato
finale
In altre parole...
Traslo a destra il moltiplicatore di una posizione per
verificare se il suo lsb vale 1. Il suo lsb finisce in C.
C=1
C=0
Sommo il moltiplicando
alla somma parziale.
Traslo a destra la somma parziale, copiando il bit
fuoriuscito (lsb della somma parziale) nel msb del
moltiplicatore (che diventa passo dopo passo la
parte meno significativa del risultato)
L’algoritmo (precondizioni)
moltiplicando, A=6
moltiplicatore,D=5
0
0
1
1
0
A
0
0
0
0
0
B
0
0
0
1
C
0
1
D
•
Ripeti i seguenti passi tante volte quanti sono i bit di D.
1. Azzero C
2. Trasla a destra D
3. Se C=1 somma A e B
4. Trasla a destra B
5. Se C=1 inverto il bit più significativo di D
L’algoritmo (postcondizione)
moltiplicando, A=6
Risultato=30
0
0
1
1
0
A
0
0
0
0
0
B
0
1
1
1
C
1
0
D
Il risultato della moltiplicazione necessita di un numero di
bits doppio per poter essere rappresentato. Per semplicità
moltiplicando e moltiplicatore hanno 5 bits nel nostro
esempio=> risultato scritto in 10 bits. I 5 MSB sono scritti in
B, i 5 LSB sovrascrivono il moltiplicatore.
Il codice
ADDL R0,R2
ORG 400H
LSRL #1,R2
rls EQU 2000h ;addr.parte meno sig.del risult. dopo:
JNC poi
rms EQU 2004h ;addr.parte + sig.del risult.
XORL #80000000h, R3 ;inverto il bit + significativo
A DL 6 ; variabile contenente il moltiplicando
di R3 (d)
D DL 5 ; variabile contente il moltiplicatore
poi: SUBL #1, R1
JNZ mult
MOVL R3, rls
CODE
MOVL A,R0 ; carico il moltiplicando in R0
MOVL D,R3 ; carico il moltiplicatore in R3
MOVL R2,rms
XORL R2,R2 ; azzero R2 (B)
MOVL #32,R1; R1 è il contatore: inizializzo a END
; 32, #bits moltiplicatore
mult:
CLRC
LSRL #1, R3
JNC dopo
; la parte meno significativa
; contenuta in R3 viene caricata
; nella longword di memoria
; di indirzzo rls
; la parte più significativa in rms