Sia TAPE una periferica di gestione di nastri

  • Slides: 18
Download presentation
Sia TAPE una periferica di gestione di nastri magnetici in grado di acquisire/fornire dati

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 PD 32. 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 0 AAAh. 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 PD 32; • il software di attivazione per il trasferimento e di gestione dell’interruzione di DMAC.

Logica dell’interfaccia del DMAC per le interruzioni IRQ I/O AB I/O DB I/O CB

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 PD 32 I/O WR CAR-CD MEMORIA INC ADDRESS CAR-TAPE INC DATA

AB DB CB PD 32 I/O WR CAR-CD MEMORIA INC ADDRESS CAR-TAPE INC DATA SELECT DATO/IND SCRITTO I/O WR TEMP WC SCO CD START DECR DATA TC I/O AB I/O DB I/O CB IRQ ADDRESS IND PRONTO SCO DMAC DATO PRONTO SCO TAPE

AB DB CB PD 32 WORD LENGTH INC I/O AB I/O DB I/O CB

AB DB CB PD 32 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 R 0 PUSH R 1 MOVL ARRAY, R 0 MOVB (R 0),

INIT: PUSH R 0 PUSH R 1 MOVL ARRAY, R 0 MOVB (R 0), R 1 OUTB R 1, W_LENGTH MOVL 1(R 0), R 1 OUTL R 1, CAR_TAPE MOVL 5(R 0), R 1 OUTL R 1, CAR_CD MOVL 9(R 0), R 1 OUTL R 1, WC START DMAC POP R 1 POP R 0 RET DRIVER 1, 500 h CLEAR DMAC RTI

Due processori si scambiano messaggi tramite un buffer di memoria condiviso, costituito di 32

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

Banco Registri I/O AB I/O DB I/O CB CPU 2 I/O RD I/O WR SELECT … R 0 SELECT 1 SELECTi SELECT 0 SELECT 32 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 CPU 1 I/O WR SELECT I/O

FULL F/F I/O AB I/O DB I/O CB CPU 1 I/O WR SELECT I/O RD SET RESET From CPU 2 S Q FULL R Q SET From CPU 2 TO CPU 2

Logica per la gestione delle interruzioni IRQ I/O AB I/O DB I/O CB CPU

Logica per la gestione delle interruzioni IRQ I/O AB I/O DB I/O CB CPU 1 CLEAR START IRQ GEN_IRQ Decoder GEN_IRQ FROM CPU 2 R IVN O. C. S Q STATUS R Q CLEAR FROM CPU 2 IACKIN Q DIR S Q IACKOUT

Software: Algoritmo/Strutture Dati Scritture: – la specifica indica che il processore che esegue una

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 PD 32, 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 PD 1 che

Software: Algoritmo/Strutture Dati Letture: – la specifica indica che il processore PD 1 che esegue una scrittura deve notificare il processore PD 2 tramite un IRQ: • • • Per il relativo driver (su PD 2) è possibile pertanto acquisire immediatamente i dati dalla periferica. Tali dati dovranno essere consumati on demand da qualche applicazione in esecuzione su PD 2. 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

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;

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 R 0 ACCETTA L’INDIRIZZO IN RAM DA CUI PRELEVARE

Scrittura ; SUBROUTINE CHE IN R 0 ACCETTA L’INDIRIZZO IN RAM DA CUI PRELEVARE I DATI DA SCRIVERE SULLA PERIFERICA WRITE: PUSH R 1 PUSH R 2 PUSH R 3 BW: INB Full, R 1 ; LEGGO IL F/F FULL CMPL #0, R 1 JNZ BW ; devo accodare dati outb #1, Full MOVL #32, R 2 MOVL #REG 1, R 3 W: MOVL (R 0)+, R 1; LEGGE IL PRIMO DATO DAI PARAMETRI DI INGRESSO ; E LO COPIA IN R 1 OUTL R 1, R 3 ; TRASFERISCE IL DATO VERSO REG_i, IL CUI INDIRIZZO E’ IN R 3 ADDB #1, R 3 ; Assumiamo che i registri della periferica abbiano indirizzi contigui SUBL #1, R 2 ; JNZ W START DEV ; GENERA INTERRUZIONE POP R 3 POP R 2 POP R 1 RET

Lettura: subroutine di livello applicazione SUBROUTINE boolean READ(memory_address) /* input: l’indirizzo di partenza all’interno

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: R 0: indirizzo a

Lettura: subroutine di livello applicazione SUBROUTINE boolean READ(memory_address) /* input: R 0: indirizzo a partire dal quale memorizzare le 32 longwords output: R 1 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 R 0 PUSH R 2 MOVL QHEAD, R 1 CMPL QTAIL, R 1 JZ NO_DATA ; HEAD=TAIL= EMPTY QUEUE COPY: ; COPY FROM DEVICE TO RAM MOVL #32, R 2 MOVL (R 1)+, (R 0)+ SUBL #1, R 2 JNZ COPY ADDL #128, QHEAD; Rimuovo l’elemento in testa MOVL #1, R 1 JMP END NO_DATA: MOVL #0, R 1 END: POP R 2 POP R 0 RET

Lettura: Driver //attivato dopo una scrittura dall’altro processore • Read from device and add

Lettura: 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, 500 h //attivato dopo una scrittura dall’altro processore PUSH R

Lettura: Driver DRIVER 1, 500 h //attivato dopo una scrittura dall’altro processore PUSH R 0 PUSH R 1 PUSH R 2 PUSH R 3 MOVL QTAIL, R 0 MOVL #32, R 2 ; contatore MOVL #REG 1, R 3 ; in R 3 memorizziamo l’indirizzo dell’i-esimo registro L: INL R 3, R 1 ; acquisisce dall’i-esimo registro in R 1 MOVL R 1, (R 0)+ ADDB #1, R 3 ; Assumiamo che i registri della periferica abbiano indirizzi contigui SUBL #1, R 2 JNZ L ; All’uscita dal ciclo R 0 punta alla longword che segue l’ultimo elemento memorizzato MOVL R 0, QTAIL ; Aggiorna il puntatore all’ultimo elem. della coda CLEAR DEV POP R 3 POP R 2 POP R 1 POP R 0 RTI