Sia TAPE una periferica di gestione di nastri magnetici in grado di
acquisire/fornire dati a 8 bit, e sia CD una periferica di masterizzazione in
grado di acquisire dati a 8/16/32 bit. TAPE è indirizzabile tramite 32 bit ed
è visibile ad un DMAC interfacciato al processore PD32. CD è anch’essa
indirizzabile tramite 32 bit e visibile allo stesso DMAC.
Il DMAC deve poter supportare operazioni di trasferimento dati da TAPE
verso CD. La programmazione di DMAC per il trasferimento avviene
tramite una opportuna routine di inizializzazione che utilizza 4
informazioni memorizzate in un buffer di memoria di 13 byte ad indirizzo
0AAAh. Dei 13 byte, il primo identifica il codice operativo per il
trasferimento (ovvero se il trasferimento verso CD deve avvenire al byte,
alla word o alla longword), i rimanenti byte, a gruppi di quattro identificano
rispettivamente: l’indirizzo di TAPE, l’indirizzo di CD e la quantità di byte
coinvolti nel trasferimento. Si ipotizzi che al termine del trasferimento il
DMAC avverte il processore tramite interruzione.
Progettare:
•il SCA dell’interfaccia tra DMAC e PD32;
•il software di attivazione per il trasferimento
dell’interruzione di DMAC.
e
di
gestione
Logica dell’interfaccia del DMAC per le
interruzioni
IRQ
I/O AB
I/O DB
I/O CB
CLEAR
START
IRQ
STARTD
Decoder
CPU
IACKIN
IVN
O.C.
SELECT
R
Q
STATUS
S
Q
COMPLETE
STARTDEV
SCO DMAC
IACKOUT
AB
DB
CB
PD32
I/O WR
CAR-CD
MEMORIA
INC
ADDRESS
I/O WR
CAR-TAPE
INC
DATA
SELECT
DATO/IND
SCRITTO
TEMP
SCO
CD
START
DECR
I/O WR
WC
DATA
TC
I/O AB
I/O DB
I/O CB
IRQ
ADDRESS
IND PRONTO
SCO
DMAC
DATO
PRONTO
SCO
TAPE
AB
DB
CB
PD32
WORD
LENGTH
INC
I/O AB
I/O DB
I/O CB
IRQ
WORD
LENGTH
SELECT
I/O WR
MEMORIA
SCO
DMAC
SCO
TAPE
INIT:
PUSH R0
PUSH R1
MOVL ARRAY, R0
MOVB (R0), R1
OUTB R1, W_LENGTH
MOVL 1(R0),R1
OUTL R1, CAR_TAPE
MOVL 5(R0),R1
OUTL R1, CAR_CD
MOVL 9(R0),R1
OUTL R1, WC
START DMAC
POP R1
POP R0
RET
DRIVER 1,500h
CLEAR DMAC
RTI
Due processori si scambiano messaggi tramite un buffer di memoria
condiviso, costituito di 32 registri da 32 bit ciascuno . Il buffer di
memoria condiviso è visto da entrambi i processori come una
periferica. I processori possono essere sia produttori che
consumatori di messaggi. Un processore può memorizzare un
messaggio solo se il buffer è vuoto (ovvero il consumatore del
vecchio messaggio l’ha già letto). A tal fine si ipotizzi di utilizzare un
flip/flop che indica se il buffer è pieno o vuoto. Il processore che
scrive il messaggio avverte l’altro dell’avvenuta scrittura tramite un
interrupt. Quando il processore consumatore ha letto il messaggio
setta opportunamente il flip/flop associato al buffer.
Progettare il buffer di memoria con le relative interfacce verso i due
processori. Il software per la scrittura e lettura dei dati dal buffer e
l’handshaking tra i due processori. Si supponga che in fase di
accensione del sistema il flip/flop di handshaking venga inizializzato
opportunamente per indicare che il buffer è vuoto e che non si
verifichino conflitti tra i processori nell’accesso al flip/flop associato
al buffer.
Banco Registri
I/O AB
I/O DB
I/O CB
CPU 2
I/O RD
I/O WR
SELECT
…
R0
SELECT1 SELECTi
SELECT0
SELECT32
I/O WR
I/O DB
I/O CB
I/O AB
I/O RD
CPU 1
FULL F/F
I/O AB
I/O DB
I/O CB
CPU1
I/O WR
SELECT
I/O RD
SET
RESET
RESET
From CPU2
S
Q
FULL
R Q
SET
From CPU2
TO CPU2
Logica per la gestione delle interruzioni
IRQ
I/O AB
I/O DB
I/O CB
CPU1
CLEAR START
IRQ
GEN_IRQ
Decoder
GEN_IRQ
FROM CPU2
R
IVN
O.C.
S
Q
STATUS
R
Q
CLEAR
FROM CPU2
IACKIN
Q
DIR
S
Q
IACKOUT
Software: Algoritmo/Strutture Dati
Scritture:
– la specifica indica che il processore che
esegue una lettura deve resettare il F/F
FULL:
•
•
dal momento che non è richiesto l’utilizzo di
interruzioni per la notifica dell’avvenuta lettura
all’altro PD32, quest’ultimo dovrà testare in busy
wait lo stato del F/F FULL prima di poter avviare
una scrittura.
Questo rende di fatto la subroutine di scrittura
bloccante: ritorna solo dopo aver trasferito i dati
alla periferica.
Software: Algoritmo/Strutture Dati
Letture:
–
la specifica indica che il processore PD1 che
esegue una scrittura deve notificare il processore
PD2 tramite un IRQ:
•
•
•
Per il relativo driver (su PD2) è possibile pertanto acquisire
immediatamente i dati dalla periferica.
Tali dati dovranno essere consumati on demand da
qualche applicazione in esecuzione su PD2.
Pertanto dobbiamo prevedere un buffer in memoria sul
quale il driver vada a scaricare i dati acquisiti dalla
periferica:
–
–
–
coda con puntatore all’inizio e alla fine: READ_QUEUE
quando viene ricevuto un IRQ, il driver accoda il messaggio
nel buffer.
Il buffer è svuotato dalla subroutine di livello applicazione per
la lettura, che ritorna il messaggio in cima alla coda (se
presente) e lo rimuove dalla coda.
Software: Algoritmo/Strutture Dati
Letture:
Coda con puntatore all’inizio e alla fine: READ_QUEUE
Puntatore al primo elemento: QHEAD
Puntatore all’ultimo elemento: QTAIL
Politica di inserimento:
FIFO
Inserimento:
Aggiungo un elemento in fondo alla coda:
QTAIL=QTAIL+ELEM_SIZE
Lettura:
Estraggo il primo elemento dalla CODA:
QHEAD=QHEAD+ELEM_SIZE
NOTA: Nel codice assembly useremo delle variabili per memorizzare
QHEAD e QTAIL.
Subroutine di Scrittura
(pseudo-codice)
WHILE (FULL)
{ NOP; }
set FULL_FLAG;
for (i=0; i<32; i++) {
out dev[i], buf[i];
}
start dev;
Scrittura
; SUBROUTINE CHE IN R0 ACCETTA L’INDIRIZZO IN RAM DA CUI PRELEVARE I DATI DA
SCRIVERE SULLA PERIFERICA
WRITE:
PUSH R1
PUSH R2
PUSH R3
BW:
INB Full,R1 ; LEGGO IL F/F FULL
CMPL #0,R1
JNZ BW
;devo accodare dati
outb #1, Full
MOVL #32,R2
MOVL #REG1,R3
W: MOVL (R0)+,R1; LEGGE IL PRIMO DATO DAI PARAMETRI DI INGRESSO
; E LO COPIA IN R1
OUTL R1,R3 ; TRASFERISCE IL DATO VERSO REG_i, IL CUI INDIRIZZO E’ IN R3
ADDB #1,R3 ; Assumiamo che i registri della periferica abbiano indirizzi contigui
SUBL #1,R2 ;
JNZ W
START DEV
; GENERA INTERRUZIONE
POP R3
POP R2
POP R1
RET
Lettura: subroutine di livello applicazione
SUBROUTINE boolean READ(memory_address)
/* input:
l’indirizzo di partenza all’interno del quale memorizzare le 32
longwords
output:
1) se non ci sono messaggi nel buffer, ritorna 0
2) se ci sono messaggi nel buffer, memorizza 32 longwords nel
buffer e ritorna 1*/
if (READ_BUF_FULL==0) //no data to read
return 0;
else {
copia primo messaggio in memory_address;
aggiorna puntatore alla testa della coda;
return 1;
}
Lettura: subroutine di livello applicazione
SUBROUTINE boolean READ(memory_address)
/* input:
R0: indirizzo a partire dal quale memorizzare le 32 longwords
output: R1
1) se non ci sono messaggi nel buffer, ritorna 0
2) se ci sono messaggi nel buffer, memorizza 32 longwords nel buffer e ritorna 1*/
PUSH R0
PUSH R2
MOVL QHEAD, R1
CMPL QTAIL,R1
JZ NO_DATA
; HEAD=TAIL= EMPTY QUEUE
COPY:
;COPY FROM DEVICE TO RAM
MOVL #32,R2
MOVL (R1)+,(R0)+
SUBL #1, R2
JNZ COPY
ADDL #128, QHEAD; Rimuovo l’elemento in testa
MOVL #1,R1
JMP END
NO_DATA:
MOVL #0,R1
END:
POP R2
POP R0
RET
Lettura: Driver
Driver
//attivato dopo una scrittura dall’altro processore
•
Read from device and add a new element to
READ_BUF
•
Update READ_BUF’s tail pointer (+32*4)
•
clear dev
•
rti
Lettura: Driver
DRIVER 1,500h
//attivato dopo una scrittura dall’altro processore
PUSH R0
PUSH R1
PUSH R2
PUSH R3
MOVL QTAIL,R0
MOVL #32, R2
; contatore
MOVL #REG1, R3 ; in R3 memorizziamo l’indirizzo dell’i-esimo registro
L: INL R3, R1
; acquisisce dall’i-esimo registro in R1
MOVL R1, (R0)+
ADDB #1,R3 ; Assumiamo che i registri della periferica abbiano indirizzi contigui
SUBL #1,R2
JNZ L
;All’uscita dal ciclo R0 punta alla longword che segue l’ultimo elemento memorizzato
MOVL R0, QTAIL ; Aggiorna il puntatore all’ultimo elem. della coda
CLEAR DEV
POP R3
POP R2
POP R1
POP R0
RTI
Scarica

Document