CALCOLATORI ELETTRONICI II
Gestione delle subroutine
SUBROUTINES / 1
Vantaggi delle subroutines
In maniera analoga alle funzioni/metodi dei linguaggi ad alto
livello, anche in assembly le subroutines garantiscono una
maggiore semplicità, modularità e riusabilità del software.
Inoltre riducono il consumo di memoria necessario per la
memorizzazione del codice, nel caso in cui un determinato insieme
di istruzioni debba essere richiamato più volte durante
l’elaborazione.
SUBROUTINES / 2
Salto a sottoprogramma
L’istruzione di salto a subroutine (JSR) permette di saltare da un
programma – programma principale – ad un altro programma –
sottoprogramma.
Esempio
JSR moltiplicazione
;salta al sottoprogramma “moltiplicazione”
L’esecuzione del sottoprogramma termina con l’istruzione RET, con
la quale si ritorna ad eseguire il programma principale, o meglio il
programma chiamante.
SUBROUTINES / 3
Programma principale
Sottoprogramma A
1. chiamata
JSR A
2. chiamata
1. risposta
JSR A
2. risposta
RET
JMP e JSR / 1
La sintassi di JSR (Jump To Subroutine) è la stessa dell’istruzione di salto
incondizionato JMP, cioè:
JSR <dest>
dove dest è l’indirizzo di memoria della prima istruzione della subroutine
espresso sotto forma di numero binario a 32 bit o di riferimento simbolico(label).
JMP e JSR / 2
Differenza tra JMP e JSR
A differenza dell’istruzione JMP, il microprogramma associato
all’istruzione JSR, prima di rimpiazzare il contenuto del PC con
l’indirizzo <dest>, deve memorizzarne il valore in memoria.
In questo modo, al termine della subroutine, l’esecuzione può
riprendere dall’istruzione successiva alla JSR.
L’area di memoria preposta alla memorizzazione degli indirizzi
di ritorno delle subroutines deve permettere di gestire
efficentemente anche situazioni più complesse, in cui i
sottoprogrammi chiamano a loro volta altri sottoprogrammi
(nested subroutines).
SUBROUTINES ANNIDATE
Programma
principale
Sottoprogr.
A
Sottoprogr.
C
Sottoprogr.
B
1
2
JSR A
3
JSR B
6
5
JSR C
4
JSR A
RET
RET
RET
STACK / 1
La gestione dei sottoprogrammi è basata su una struttura dati
chiamata stack (pila), gestita con una tecnica LIFO (Last In First
Out): gli elementi vengono prelevati a partire dall’ultimo che è
stato memorizzato.
L’operazione di inserimento di un elemento alla sommità (top)
dello stack è chiamata push, mentre l’operazione inversa è
chiamata pop.
STACK / 2
Le operazioni di PUSH e POP, sebbene non disponibili nel set di
istruzioni del PD32, vengono comunque implementate come
pseudoistruzioni di movimento dati.
Le pseudoistruzioni sono non sono implementate a livello hardware,
ma sono messe a disposizione dall’assemblatore che provvede a
mapparle nelle istruzioni del microprocessore equivalenti.
GESTIONE STACK PD32 / 1
Nel PD32 lo stack è costituito da
longword e ad esso è associato un
particolare registro detto SP (Stack
Pointer) che nel PD32 coincide con il
registro R7. Tale registro punta sempre
alla cima (top) dello stack.
STACK
BASE
elem.1 byte 4 LSB
elem.1 byte 3
elem.1 byte 2
elem.1 byte 1 MSB
elem.2 byte 4 LSB
elem.2 byte 3
elem.2 byte 2
S
S-1
S-2
S-3
S-4
S-5
S-6
Per “ragioni storiche”, nel PD32 lo
stack cresce verso indirizzi di memoria
decrescenti. Sia S l’indirizzo iniziale
S-7
dello stack (base), allora gli n elementi
elem.2 byte 1 MSB S-8
presenti sono
memorizzati nelle
locazioni consecutive:
TOP
S, S-4, S-8,…,S-4*n
S-8
R7
GESTIONE STACK PD32 / 2
Come detto in precedenza le istruzioni PUSH e POP non sono vere e
proprio istruzioni che appartengono al set del PD32, bensì sono
istruzioni che il compilatore traduce in particolari MOV.
BASE S
e_b4
PUSH:
e_b3
e_b2
e_b1
inserisce elemento “e” in pila
S
S-1
S-2
S-3
S-4
S-5
S-6
S-7
S-8
R7
GESTIONE STACK PD32 / 2
Come detto in precedenza le istruzioni PUSH e POP non sono vere e
proprio istruzioni che appartengono al set del PD32, bensì sono
istruzioni che il compilatore traduce in particolari MOV.
BASE S
e_b4
POP:
e_b3
e_b2
e_b1
estrae l’elemento “e” dalla pila
S-4
S-1
S-2
S-3
S-4
S-5
S-6
S-7
S-8
R7
STACK & PD32 / 2
Le pseudoistruzioni per la gestione dello stack
PSEUDOISTRUZIONE
OP.
COMMENTO
PUSH
S
Inserisce in cima allo stack una longword indirizzata
dall’operando sorgente S. Viene tradotta come: MOVL S, -(R7)
POP
D
Estrae dallo stack una longword e la pone nella locazione
indicata dall’operando D. Viene tradotta come: MOVL (R7)+, D
PUSHSR
POPSR
-
Inserisce lo Status Register in cima allo stack. Viene tradotta
come: MOVRFRSR -(R7)
-
Ripristina lo Status Register con la longword presente in cima
allo stack. Viene tradotta come: MOVTOSR (R7)+
ESEMPIO PUSH
… E DOPO
PRIMA DI ESEGUIRE PUSH R6…
000027FC BASE
78
56
34
000027F8
12
TOP
000027FC BASE
78
56
34
000027F8
12
44
000027F4
R6
PC
R7
11223344
00000410
000027F8
R6
PC
R7
33
22
11
11223344
00000414
000027F4
TOP
ESEMPIO POP
… E DOPO
PRIMA DI ESEGUIRE POP R5…
000027FC BASE
78
56
34
000027F8
12
44
000027F4
R5
PC
R7
33
22
11
FFFFFFFF
00000414
000027F4
000027FC BASE
78
56
34
000027F8
12
TOP
R5
PC
R7
11223344
00000418
000027F8
TOP
STACK E SUBROUTINE
L’istruzione JSR inserisce (PUSH) in cima allo stack il valore del
PC, ovvero l’indirizzo di ritorno della subroutine. In maniera
analoga, l’istruzione RET estrae dalla cima dello stack una
longword che memorizza all’interno del PC. Nella successiva fase
di fetch sarà quindi caricata nell’IR l’istruzione che segue la JSR.
Lo stack è inoltre utilizzato dalla subroutine chiamata per salvare i
registri che saranno utilizzati e quindi sovrascritti, così da poterne
ripristinare il valore originale prima di eseguire il RET. Questa
operazione assicura che la funzione chiamante trovi i registri
inalterati una volta terminata l’esecuzione della subroutine.
(OPERAZIONE MOLTO UTILE!!!!!!!)
STACK E PARAMETRI
Esistono diverse tecniche per il passaggio di parametri ad una
subroutine:
•La soluzione più efficiente è prevedere l’utilizzo di uno o più
registri per il passaggio diretto dei parametri alla subroutines. In
tal modo si evitano completamente accessi alla memoria. Il
limite di tale tecnica è legato al ristretto numero di registri
disponibili.
•Nel caso in cui i parametri da passare alla subroutine non
possano essere memorizzati direttamente all’interno dei registri
del PD32 è comunque possibile utilizzare i registri per
indirizzare una o più aree di memoria nelle quali siano state
preventivamente memorizzate i parametri da scambiare.
Direttive di definizione variabili
Sintassi: label dl/dw/db n {,nj}
Dichiara una variabile di nome label inizializzata al valore n.
Eventuali altri numeri specificati oltre il primo sono allocati
consecutivamente in memoria a partire dall’indirizzo associato a
label. Tale indirizzo è scelto dall’assemblatore!
var1
DW
4
var1 è un place-holder per una word collocata in memoria
in una locazione scelta dall’assemblatore ed inizializzata a 4.
var2
DL
4, 22h, 3
alloca 3 longwords inizializzate a 4, 22h e 3. var2 punta
alla prima locazione
PD32 (esercizio)
Sintassi/Semantica Istruzioni:
MicroOpGen
Esercizio 1:
Dati due operandi X e Y definiti attraverso
longword all’interno di variabili,
implementare attraverso una subroutine
l’algoritmo che produce come output la
moltiplicazione X*Y
PD32 / 1 (soluzione)
INTERFACCIA DELLA SUBROUTINE
MOLTIPLICAZIONE
;subroutine per la moltiplicazione
;Pre-condizioni:
; moltiplicando e moltiplicatore in R0 e R1
; indirizzo di memoria per risultato in R2
;Post-condizioni:
; Il risultato della moltiplicazione e' memorizzato nella longword indirizzata
da R2
; In caso di overflow ritorna con il flag di carry settato e non aggiorna la
memoria
PD32 / 2 (soluzione)
MOLTIPLIACAZIONE:
push r1
push r3
xorl r3,r3
loop:
cmpl #0,r1
jz update
addl r0,r3
jc overflow
subl #1,r1
jmp loop
update: movl r3,(r2)
overflow:
pop r3
pop r1
ret
end
Nella subroutine definita vado a “sporcare”
i registri R1 e R3…..allora li salvo nello
stack per poi ripristinarli alla terminazione.
L’output del metodo è restituito nell’indirizzo
puntato da R2 in memoria
PD32 / 3 (soluzione)
org 400h
baseadd equ 1000h
moltiplicando DL ?
moltiplicatore DL ?
;conterra' il risultato
code
;inizia programma
movl moltiplicando,R1
;carica il moltiplicando in R1
movl moltiplicatore,R0
;carica il moltiplcatore in R0
movl baseadd,r2 ;carica l'indirizzo dove memorizzare il risultato in R2
jsr MOLTIPLICAZIONE ;invoca la subroutine per la moltiplicazione
HALT
Codice del “chiamante” della subroutine
MOLTIPLICAZIONE
PD32 / 4 (soluzione)
Come fa tutto a funzionare ed il flusso di esecuzione
del programma a continuare l’esecuzione anche dopo
la chiamata alla subroutine MOLTIPLICAZIONE???
Come mai effettivamente l’istruzione HALT viene
eseguita dalla CPU dopo aver terminato
MOLTIPLICAZIONE???
Suggerimento: come evolve il PC??
PD32 (esercizio casa)
Sintassi/Semantica Istruzioni:
MicroOpGen
Esercizio Casa:
Implementare l’algoritmo per il Selection Sort
in maniera modulare, sfruttando la
metodologia delle subroutine.
Utilizzo subroutine mondo reale
1. Implementazione di chiamate a funzioni /
metodi
2. Interruzione asincrona del flusso di
esecuzione di un programma
3. Implementazione di porzioni di codice per la
gestione di eventi (Gestione driver )
4. ….un milione di altri usi……
Istruzioni I/O PD32 Classe 7
TIPO
0
CODICE
INs
OPERANDI
dev, D0
CNZV P I
------
COMMENTO
Il dato contenuto nel
buffer del device dev è
trasferito nella
destinazione D0.
dev ->d0
1
OUTs
S,dev
------
Il dato sorgente S
viene trasferito nel
buffer del device dev.
S->dev
2
START
dev
------
3
JR
dev, D1
------
4
JNR
dev, D1
------
Viene azzerato il flipflop STATUS del dev e
viene avviata
l'operazione.
Se STATUS=1 salta
alla destinazione D1
Se STATUS=0 salta
alla destinazione D1
Per la destinazione D0 sono ammessi tutti i tipi di indirizzamento tranne quello immediato.
Per la destinazione D1 sono ammessi tutti i tipi di indirizzamento tranne quello con registro e
immediato.
Formato istruzioni I/O
Per l’operando dev sono ammessi solo due modi di indirizzamento: diretto
con registro ed assoluto. Per la codifica di questo campo sono usati i campi
I/O e k.
Il campo I/O può assumere solo due valori:
• 01 => indica che il contenuto di k è l’indirizzo del device
• 10 => indica che l’indirizzo del device è contenuto nel registro generale
specificato dai primi 3 bit del campo k
Poichè i campi modo sorgente e sorgente sono inutilizzati, la sorgente S
viene specificata nei campi modo destinazione e destinazione.
CLASSE
111
31
TIPO
29 28
24 23
k
I/O
s
16 15 14 13 12 11
-----
-----
9 8
MODO
6 5
DEST
32
0
Scarica

Gestione delle subroutine