Sei sulla pagina 1di 30

CALCOLATORI ELETTRONICI

Esercitazione finale
Non in questo senso…☺

Only one will survive…

…student…

2
Siamo partiti da…
John von Neumann
wrote "First Draft of a CALCOLATORE ELETTRONICO
Report on the EDVAC”,
1945
Memoria Unità di elaborazione
Dispositivi di ingresso: principale (CPU)
Tastiera
Mouse PROGRAMMA ALU
Scanner
Sensori DATI REGISTRI
Ecc..

Dispositivi di uscita:
Monitor
Stampante Bus di sistema Altri
Attuatori CALCOLATORI
Ecc... collegati in rete

Ingressi e REGISTRI DI STATO


uscite Rete
locali REGISTRI DI TRANSITO
Interfacce di I/O
3
…per arrivare a

CS#
Logica di Chip di memoria
memoria
CPU generazione
e (RAM e EPROM)
dei CS
INT INTA I/O

Bus Comandi

Bus Indirizzi
Bus Dati

Interfacce di I/O Interfacce di I/O


8259 gestite a interrupt gestite a polling

INTRs
Sotto-sistema di I/O

4
“IL SISTEMA”

Interfaccia LED Interfaccia OROLOGIO

COM1
Interfaccia CPU
Seriale 1 +
Interfaccia
PIC
COM2 + INTERRUTORI
Interfaccia Memorie
Seriale 2
COM3
Interfaccia
Seriale 3

Fck = 1Hz
5
Funzionamento
Il sistema riceve di continuo dei dati dalla COM1. I dati sono costituiti
da messaggi di dimensione pari ad 1KB. Ricevuto un intero
messaggio, il sistema deve trasferire l’intero messaggio sulla
COM2 o sulla COM3 sulla base del valore corrente degli interruttori
(interpretato come byte senza segno): per valori compresi tra 0 e
127 il messaggio deve essere trasferito verso la COM2, altrimenti
verso la COM3. Durante la trasmissione di un messaggio il sistema
deve essere in grado di ricevere un nuovo messaggio dalla COM1.

Il sistema deve inoltre, sulla base del valore corrente degli interruttori,
eseguire di continuo delle routine (“tasks”). L’indirizzo della
routine corrente da eseguire è memorizzato in una tabella (tabella
dei tasks). L’indice di accesso alla tabella è rappresentato dal valore
letto dagli interruttori (interpretato anche in questo caso come byte
senza segno). A tal proposito si consideri che l’istruzione CALLR,
consente di specificare come operando un registro.

Il valore corrente degli interruttori deve essere riportato in uscita


su 8 led, il cui scopo è appunto quello di visualizzare la
“programmazione corrente” del sistema. 6
IPOTESI
• Le interfacce seriali sono realizzate con 8250 e vengono tutte e tre gestite a
interrupt
• L’orologio deve essere gestito ad interrupt
• La priorità delle routine di interrupt deve essere la seguente:
– RX_COM1
– TX_COM2
– TX_COM3
– CLOCK
• Gli INTERRUTTORI vengono gestiti a polling
• CHIP di memoria (spazio da 4GB)
– 32KB+64KB di EPROM agli indirizzi alti
– 32MB+128MB di RAM agli indirizzi bassi
• Dispositivi di I/0 (spazio da 64KB)
– PIC: 0200-0201H
– Interruttori: FFFFH
– COM1: 01F8-01FFH
– COM2: 02F8-02FFH
– COM3: 03F8-03FFH
– LED: 0000H
– Orologio: 0100-0103H
7
Quesiti
• HARDWARE:
– Chip Select: RAM, EPROM e I/O (Mem: 4 GB, I/O: 64
KB)
– Interfacciamento dei dispositivi di I/0

• SOFTWARE:
– Main
– Tabella degli interrupt
– Tabella dei tasks (subito dopo la fine della tabella
degli interrupt)
– Routine di gestione degli interrupt
– Esempio della struttura del codice di un task
8
CS Memorie
EPROM1 64KB FFFFFFFFH
128 MB  27 bit  5 bit costanti
32 MB  25 bit  7 bit costanti
FFFF0000H 64 KB  16 bit  16 bit costanti
EPROM2 32KB FFFEFFFFH 32 KB  15 bit  17 bit costanti
FFFE8000H

Decodifica completa:



CS_EPROM1 = BA31 .. BA16
RAM2 09FFFFFFH
CS_EPROM2 = BA31 .. BA17 /BA16 BA15
32 MB 08000000H
CS_RAM1 = /BA31 .. /BA27
RAM1 07FFFFFFH
128MB
CS_RAM2 = /BA31.. /BA28 BA27 /BA26 /BA25

00000000H Può essere invertito il mapping di RAM1 e


RAM2? E di EPROM1 e EPROM2? Perchè?
9
CS Memorie

BA 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16

EPROM1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

EPROM2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0

RAM1 0 0 0 0 0 x x x x x x x x x x x

RAM2 0 0 0 0 1 0 0 x x x x x x x x x

Decodifica semplificata:

CS_EPROM1 = BA31 BA16  CS_EPROM1# = /BA31 + /BA16


CS_EPROM2 = BA31 /BA16  CS_EPROM2# = /BA31 + BA16
CS_RAM1= /BA27  CS_RAM1#= BA27
CS_RAM2 = /BA31 BA27  CS_RAM2# = BA31 + /BA27

10
CS dispositivi di I/O
Decodifica semplificata:

1. SWITCH: FFFFH (1 byte)  CS_SWITCH# = /BA15


2. CLOCK: 0100-0103H (4 bytes)  CS_CLOCK# = /BA8 + BA7
3. PIC: 0200-0201H (2 bytes)  CS_PIC# = /BA9 + BA7
4. LED: 0000H (1 byte)  CS_LED# = BA9 + BA8
5. COM1: 01F8-01FFH (8 bytes)  CS_COM1# = BA9 + /BA7
6. COM2: 02F8-02FFH (8 bytes)  CS_COM2# = BA8 + /BA7
7. COM3: 03F8-03FFH (8 bytes)  CS_COM3# = BA15 + /BA9 + /BA8

BA 1 1 1 1 1 1 9 8 7 6 5 4 3 2 1 0
5 4 3 2 1 0
CLOCK 0 0 0 0 0 0 0 1 0 0 0 0 0 0 x x
PIC 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 x
SWITCH 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
LED 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
COM1 0 0 0 0 0 0 0 1 1 1 1 1 1 x x x
COM2 0 0 0 0 0 0 1 0 1 1 1 1 1 x x x
COM3 0 0 0 0 0 0 1 1 1 1 1 1 1 x x x
11
Interruttori: input
CS_SWITCH#
Vcc Vcc Vcc

IORDC# S7 S6 S0

IN[7..0]
EN1*
244
EN2*
OUT[7..0]

BD[7]
BD[6]

BD[0]
12
Led: output

L7 L6 L0

CS_LED#

O[7..0]
CK 373 OE*
D[7..0]
IOWRC#

BD[7]
BD[6]

BD[0] 13
Interfacce seriali 8250 (COM1, COM2,
COM3)

CS_COM1#
CS_COM2# CS* TX
CS_COM3# BA[2..0] A[2..0] RX
IOWRC# WR*
IORDC# RD*
BD[7..0] D[7..0]
IR_COM1
IR_COM2 INT 8250
IR_COM3

Sarà presente un 8250 per ogni porta seriale presente nel


sistema (in questo caso 3)
14
Interfaccia verso il clock
CS_CLOCK# CS*
BA[1..0] A[1..0]
IOWRC# WR* Interfaccia
orologio

BD[7..0] D[7..0]

A[1..0]
Ore 00
Minuti 01
Secondi 10

Mapping dei registri interni dell’interfaccia

15
PIC (Programmable Interrupt Controller)
8259

CS_PIC# CS* IR0 IR_COM1


BA0 A0 IR_COM2
IR1
IOWRC# WR* IR_COM3
IR2
IORDC# RD* IR_CLOCK
IR3
BD[7..0] D[7..0]
Fck = 1Hz
Alla CPU INT
Dalla CPU INTA* 8259

16
Tabella degli interrupt
Valore di Interrupt types Indirizzo Indirizzo in memoria
ICW2 simbolico
della routine
F8H F8H..FFH
… 3FC-3FFH
F0H F0H..F7H
… 3F8-3FBH
E8H E8H..EFH
… 3F4-3F7H
E0H E0H..E7H
… 3F0-3F3H
… …
INT_CLOCK 3EC-3EFH
18H 18H..1FH
INT_COM3 3E8-3EBH
10H 10H..17H
INT_COM2 3E4-3E7H
08H 08H..0FH
INT_COM1 3E0-3E3H
00H 00H..07H
… …
ES: se programmiamo il PIC con ICW2 = F8H,
… 004-007H
avremo che gli interrupt type associati ai vari
dispositivi risulteranno essere: … 000-003H
COM1 : n = F8H
COM2 : n = F9H Frammento della IVT
COM3 : n = FAH
CLOCK: n = FBH
F8H * 4  1111 1000 00  3E0H 17
Tabella dei tasks
Supponiamo che la tabella inizi subito dopo la fine della IVT. Ogni
elemento della tabella contiene l’indirizzo in memoria del task da
eseguire. Ogni elemento sarà quindi costituito da 4 byte e la tabella
di 256 elementi risulterà quindi di dimensione pari a 1KB.
Per eseguire un determinato task, la
… … CPU sulla base di un indice i di 1 byte,
… … accederà alla tabella per recuperare
Indirizzo Task255 7FFH l’indirizzo della routine da eseguire ed
eseguirà una CALLR a quell’indirizzo:
7FCH
… … taskIndex DB 1
… … taskTable EQU 400H
Indirizzo Task0 403H
400H
LB R1,taskIndex(R0)
ANDI R1,R1,FFH Byte senza segno!
3FFH MULTI R1,R1,4
IVT LW R2,taskTable(R1)
000H CALLR R2 18
Dispositivi di I/O: PIC, CLOCK, SWITCH, LED
;Nomi simbolici dei registri del PIC
ICW1 EQU 200H
ICW2 EQU 201H
ICW4 EQU 201H
OCW1 EQU 201H
OCW2 EQU 200H

;Parole di comando del PIC


RESET EQU 13H ; l’interrupt viene rilevato sul fronte (1BH = a livello)
ADDRESS EQU F8H ; 5 bit più significativi dell’interrupt type
EN_AEOI EQU 1H ; AEOI disabilitato (3H = abilitato)
MASK EQU 0H ; 8 bit di maschera (0: non mascherato,1: mascherato)
EOI EQU 20H ; da inviare per segnalare la fine della routine

;Nomi simbolici per i registri del CLOCK


CLOCK_S EQU 100H
CLOCK_M EQU 101H
CLOCK_H EQU 102H

;Indirizzo degli SWITCH


SWITCH EQU FFFFH

;Indirizzo dei LED


LED EQU 0000H 19
Dispositivi di I/O: COM1, COM2, COM3
; nomi simbolici per i registri di COM1
RBR1 EQU 01F8H ;DLAB = 0
THR1 EQU 01F8H ;DLAB = 0
DLL1 EQU 01F8H ;DLAB = 1
DLM1 EQU 01F9H ;DLAB = 1
IER1 EQU 01F9H ;DLAB = 0
LCR1 EQU 01FBH
LSR1 EQU 01DFH

; nomi simbolici per i registri di COM2


RBR2 EQU 02F8H ;DLAB = 0
THR2 EQU 02F8H ;DLAB = 0
DLL2 EQU 02F8H ;DLAB = 1
DLM2 EQU 02F9H ;DLAB = 1
IER2 EQU 02F9H ;DLAB = 0
LCR2 EQU 02FBH
LSR2 EQU 02FDH

; nomi simbolici per i registri di COM3


RBR3 EQU 03F8H ;DLAB = 0
THR3 EQU 03F8H ;DLAB = 0
DLL3 EQU 03F8H ;DLAB = 1
DLM3 EQU 03F9H ;DLAB = 1
IER3 EQU 03F9H ;DLAB = 0
LCR3 EQU 03FBH
LSR3 EQU 03FDH

20
Ricezione e trasmissione “simultanee”
Double buffering
COM_TX
COM_RX Buffer0 Buffer1

Trasmissione: Buffer1
Ricezione: Buffer0

SWAP

COM_RX COM_TX

Ricezione: Buffer1 Trasmissione: Buffer0

I ruoli dei due buffer vengono alternativamente scambiati: mentre un buffer viene
usato per memorizzare i dati attualmente ricevuti (es. Buffer0), l’altro (es. Buffer1)
viene usato per trasferire i dati precedentemente ricevuti. Una volta che il buffer di
ricezione risulta pieno, il ruolo dei buffer viene scambiato (swap). Sotto quali ipotesi
questo meccanismo funziona?
21
Dichiarazione delle variabili e costanti
; Orologio
Ore DB 1
Minuti DB 1
Secondi DB 1
; Buffer: doppio buffer in memoria per consentire invio e ricezione contemporanei
buffer0 DB 1024
buffer1 DB 1024
;Flag: 0=buffer di ricezione buffer0; 1=buffer di ricezione buffer1
RxBuffer DB 1
;Indice dell’elemento corrente da mettere nel buffer corrente di ricezione
RxIndex DB 2
;Indice dell’elemento corrente da trasmettere
TxIndex DB 2
DOPPIO BUFFER

TxIndex RxIndex
RxIndex TxIndex

RxBuffer RxBuffer
0 1

buffer0 buffer1 buffer0 buffer1 22


Inizializzazione delle periferiche: PIC
PROC init_PIC
PUSH R1

; interrupt rilevati a fronte


ADDI R1,R0, RESET
OUT ICW1(R0), R1

;5 bit più significati dell’interrupt type (F8H)


ADDI R1,R0, ADDRESS
OUT ICW2(R0), R1

;AEOI disabilitato
ADDI R1,R0, EN_AEOI
OUT ICW4(R0), R1

POP R1
RET
ENDP

23
Inizializzazione delle periferiche: COM1,2,3
PROC init_com1 Ipotesi:
; La procedura inizializza COM1 : bit-rate 4800, 8 bit per F=1.8432 MHz
; carattere, parita' pari, 1 stop bit
PUSH R1 COM1 @ 4800
; DLAB = 1 per accedere a DLM e DLL (DL=DLM##DLL) COM2 @ 9600
ADDI R1,R0, 80H COM3 @ 9600
OUT LCR1(R0), R1
; bit rate = 4800  DL = 0018H ; 9600  DL=000CH
OUT DLM1(R0), R0 Le procedure di
ADDI R1,R0,18H inizializzazione di
OUT DLL1(R0), R1 COM2 e COM3
; 8 bit per car., 1 stop bit,parita` pari,DLAB=0 ->LCR=1BH differanno da COM1
ADDI R1,R0,1BH per questo valore e
OUT LCR1(R0), R1 accederanno ai
; “clear” di IER per disabilitare le interruzioni registri della propria
OUT IER1(R0), R0 interfaccia, e.s.
;lettura iniziale per svuotare il buffer di ricezione LCR2, IER3,…
IN R1, RBR1(R0)
POP R1
RET
ENDP

24
Main e struttura di un generico task
Main: CLI Loop: IN R1, SWITCH(R0)
//INIZIALIZZAZIONE VARIABILI
LB RxBuffer(R0),R0 SB TaskIndex(R0),R1
LH RxIndex(R0),R0 OUT LED(R0),R1
LH TxIndex(R0),R0 LB R1,taskIndex(R0)
LB Ore(R0),R0
ANDI R1,R1,FFH
LB Minuti(R0),R0
LB Secondi(R0),R0 MULTI R1,R1,4
LW R2,taskTable(R1)
// INIZIALIZZAZIONE PERIFERICHE CALLR R2
CALL init_PIC J Loop
CALL init_COM1
CALL init_COM2 Abilitazione interrupt di
CALL init_COM3 ricezione sulla COM1
PROC TASKn
// ABILITAZIONE DEGLI INTERRUPT
PUSH …
ADDI R1,R0,1
PUSH …
OUT IER1(R0), R1
ADDI R1,R1,F0H
;CODICE DEL TASK
OUT OCW1(R0),R1 Generico Task:
STI
POP …
POP …
Smacheramento degli interrupt RET
IR0,IR1,IR2,IR3 sul PIC ENDP 25
Routine di interrupt dell’orologio (Interrupt Type FBH)

INT_CLOCK:
STI
N.B.Gestione End: SB Secondi(R0),R1
vettorizzata e annidata
PUSH R1 in Fully Nested Mode SB Minuti(R0),R2
PUSH R2 SB Ore(R0),R3
PUSH R3
PUSH R4 OUT CLOCK_S(R0),R1
LB R1,Secondi(R0)
OUT CLOCK_M(R0),R2
LB R2,Minuti(R0) OUT CLOCK_H(R0),R3
LB R3,Ore(R0)
ADDI R1,R0,EOI
ADDI R1,R1,1 OUT OCW2(R0),R1
SEQI R4,R1,60
BEQZ R4,end
POP R4
ADD R1,R0,R0
POP R3
ADDI R2,R2,1 POP R2
SEQI R4,R2,60 POP R1
BEQZ R4,end
ADD R2,R0,R0 RFE
ADDI R3,R3,1
SEQI R4,R3,24
BEQZ R4,end 26
ADD R3,R0,R0
COM1 (Interrupt type F8H)
INT_COM1: STI
PUSH R1 ;PROLOGO
PUSH R2
PUSH R3

IN R2, RBR1(R0) ;Lettura del byte ricevuto da COM1

LH R1, RxIndex(R0) ;Lettura dell’indice corrente


LB R3, RxBuffer(R0)
BEQZ R3,buf0 ;Controllo di quale sia il buffer di ricezione corrente
SB buffer1(R1),R2 ;Scrittura in buffer1
J check1K
Buf0: SB buffer0(R1),R2 ;Scrittura in buffer0

check1K: ADDI R1,R1,1


SEQI R2,R1,1024 ;Fine trasferimento di 1KB?
BNEZ R2,1kdone
SH RxIndex(R0),R1 ;NO
J com1_end
1kdone: SH RxIndex(R0),R0 ;Fine trasferimento di 1KB
XORI R3,R3,1 ;Inversione del buffer corrente di ricezione
SB RxBuffer(R0),R3

IN R1,SWITCH(R0) ;Lettura stato corrente degli interruttori


ANDI R1,R1,0FFH
SGTU R2,R1,127
ADDI R1,R0,2
BNEZ R2,com3
OUT IER2(R0), R1 ;Smaschera TX su COM2
J com1_end
com3: OUT IER3(R0),R1 ;Smaschera TX su COM3

com1_end: ADDI R1,R0,EOI ; EOI


OUT OCW2(R0),R1
POP R3 ; EPILOGO
POP R2
POP R1
RFE 27
COM2 (Interrupt type F9H)
INT_COM2: STI
PUSH R1 ;PROLOGO
PUSH R2

LH R1,TxIndex(R0) ;Aumento indice e controllo fine


SEQI R2,R1,1024 ;trasmissione
BEQZ Continue
SH TxIndex(R0),R0
OUT IER2(R0),R0 ;maschera TX COM2
J com2_end

Continue: LB R2,RxBuffer(R0) ;Verifica del buffer di trasmissione


BNEZ R2,TxFromBuf0 ;e prelievo del byte da inviare
LB R2,buffer1(R1)
J send
TxFromBuf0 : LB R2,buffer0(R1)

send: OUT THR2(R0),R2 ;Trasferimento e incremento


ADDI R1,R1,1 ; dell’indice
SH TxIndex(R0),R1

com2_end: ADDI R1,R0,EOI


OUT OCW2(R0),R1
POP R2 ; EPILOGO
POP R1
RFE
28
COM3 (Interrupt type FAH)
INT_COM3: STI
PUSH R1 ;PROLOGO
PUSH R2

LH R1,TxIndex(R0) ;Aumento indice e controllo fine


SEQI R2,R1,1024 ;trasmissione
BEQZ Continue
SH TxIndex(R0),R0
OUT IER3(R0),R0 ;maschera TX COM3
J com2_end

Continue: LB R2,RxBuffer(R0) ;Verifica del buffer di trasmissione


BNEZ R2,TxFromBuf0 ;e prelievo del byte da inviare
LB R2,buffer1(R1)
J send Unica differenza rispetto a COM2
TxFromBuf0 : LB R2,buffer0(R1)

send: OUT THR3(R0),R2 ;Trasferimento e incremento


ADDI R1,R1,1 ; dell’indice
SH TxIndex(R0),R1

com2_end: ADDI R1,R0,EOI


OUT OCW2(R0),R1
POP R2 ; EPILOGO
POP R1
RFE
29
I 10 quesiti…
1. Cosa cambierebbe se l’interfaccia verso l’ orologio funzionasse in modo diverso? Ovvero: riceve
2 byte in sequenza, dove il primo indica il parametro da settare (ore
=FFH,minuti=FEH,secondi=FDH) e il secondo il valore.
2. Quali sono gli interrupt type associati alle varie routine programmando il PIC con ICW2= 38H?
3. Considerando 0-stati di wait, calcolare quando durano i vari frammenti di codice
4. Quali sono le istruzioni da inserire nelle routine di interrupt affinchè si possa operare in “fully
nested mode”?
5. Cosa cambierebbe nel caso in cui si vogliano gestire la COM2 e la COM3 a polling? Dove
andrebbe inserito il codice a tal riguardo?
6. Come si potrebbe gestire a polling la forma d’onda periodica in modo da rilevare ogni secondo
trascorso? Dove andrebbe inserito il codice a tal riguardo?
7. Volendo prevedere un task che una volta ricevuto 1KB provveda a controllare quanti byte sono
uguali al carattere “A” come si dovrebbe agire? Chi lo fa partire? Deve lavorare ad interrupt
disabilitati?
8. Si vuole introdurre anche un cicalino che si attiva quando riceve in ingresso un valore logico alto.
Un task deve controllare delle variabili che rappresentano l’ora a cui è impostata una sveglia. Nel
momento in cui rileva che l’ora corrente coincide con l’ora della sveglia deve attivare il cicalino.
La disattivazione del cicalino avvine mediante un pulsante gestito ad interrupt. Scrivere il codice
del task che si occupa di questo, la routine di gestione del tasto ed interfacciare le due nuove
periferiche al sistema.
9. Supponiamo che se nel momento in cui è stato ricevuto 1KB il valore degli interruttori vale FFH,
quello che si vuole fare è mandare in uscita il KB ad entrambe le COM2 e COM3. Quali modifiche
occorre apportare al sistema? Solo software o anche hardware?
10. Si vuole che nel momento in cui il valore degli interruttori vale 0 il sistema si comporti come
segue: cerca di capire a che baud rate funziona la COM1 ed imposta di conseguenza la stessa
baud rate sulle COM2 e COM3.
30