Reti Logiche - Il calcolatore
Cerca per parola chiave 0/0

Struttura del calcolatore

Il processore sEP8 descritto in Verilog, memoria e spazio di I/O, interfacce parallele e seriali, conversione A/D e D/A

Questo modulo mette insieme tutto: un calcolatore completo, con processore, memoria e interfacce, descritto in Verilog con gli strumenti dei moduli precedenti. Il punto concettuale è uno: il processore è una rete sequenziale sincronizzata come le altre, con registri operativi, un registro di stato e un μ-programma. È una rete logica capace di eseguire software. Il processore d'esempio è il sEP8 (8-bit simple Educational Processor): elabora byte, rappresenta gli interi in complemento a due, indirizza 16 Mbyte di memoria.

Il calcolatore visto dal programmatore

I blocchi

bus: 24 fili di indirizzo, 8 di dati, /mr /mw /ior /iow, clock, /resetProcessore sEP8esegue i programmiMemoria principaleRAM, EPROM, memoria videoSottosistema di I/Ointerfaccedispositivivideomondofetch → esecuzione, finché non trova HLT16 Mbyte, indirizzi a 24 bit64K porte, offset a 16 bit
Il calcolatore a blocchi. Il processore e la maggior parte delle interfacce sono reti sequenziali sincronizzate con lo stesso /reset; la memoria RAM è una rete asincrona. Il bus è solo un fascio di fili.
  • Il processore preleva ciclicamente un'istruzione dalla memoria (fetch) e la esegue, finché non trova HLT. Le istruzioni operative si susseguono in memoria; quelle di controllo (salti, CALL, RET) cambiano il flusso.
  • La memoria principale contiene istruzioni e dati. Per partire in modo consistente, al reset il processore inizializza IP a un indirizzo preciso, e lì ci deve essere già del codice: quella parte di memoria è una EPROM con il programma di bootstrap.
  • Il sottosistema di I/O scambia informazioni con il mondo. Distinguiamo i dispositivi, che codificano davvero l'informazione, e le interfacce, che li presentano al processore in modo standard, attraverso pochi registri.
  • Il bus collega tutto: indirizzi, dati, comandi, clock.

Registri e spazi di indirizzamento del sEP8

accumulatori (8 bit)AL7 … 0AH7 … 0flag (8 bit)F… OF SF ZF CFpuntatori (24 bit)IP23 … 0DP23 … 0SP23 … 0IP: prossima istruzione · DP: datiSP: cima della pilamemoria (2²⁴ byte)'H000000'H000001…'HFF0000…'HFFFFFFIP al resetI/O (2¹⁶ porte)'H0000'H0001…'HFFFE'HFFFF
Il sEP8 (simple Educational Processor a 8 bit) visto dal programmatore. Al reset IP vale 'HFF0000, il primo indirizzo della EPROM che contiene il programma di bootstrap, e F vale 0.

La memoria è uno spazio lineare di 224 byte; lo spazio di I/O ha 216 = 64K porte, ma solo poche corrispondono a registri reali di interfaccia (qualche decina di interfacce, ognuna con pochi registri). I registri del processore sono di tre tipi: accumulatori AL e AH (8 bit), il registro dei flag F (significativi CF, ZF, SF, OF nei bit 0–3) e tre puntatori a 24 bit: IP, SP e DP, che contiene l'indirizzo degli operandi con indirizzamento indiretto.

Le istruzioni

L'Assembler del sEP8 assomiglia a quello x86 visto nel corso: OPCODE sorgente, destinatario. Le modalità di indirizzamento delle istruzioni operative sono:

modalitàesempiodove sta l'operando
di registroMOV AL, AH, INC DPnei registri
immediatoMOV $0x10, ALnell'istruzione stessa
di memoria direttoADD 0x1010, ALin memoria, all'indirizzo scritto nell'istruzione
di memoria indirettoMOV (DP), ALin memoria, all'indirizzo contenuto in DP
di I/OIN 0x1010, AL, OUT AL, 0x9F10in una porta, con offset scritto nell'istruzione

Un operando in memoria può essere sorgente o destinatario, mai tutti e due. Le istruzioni di controllo sono JMP, Jcon e CALL con un indirizzo, e RET; CALL salva in pila IP (3 byte, l'indirizzo dell'istruzione successiva), RET lo ripristina.

Il linguaggio macchina: i formati

Per un umano conta il tipo di operazione: MOV AH,AL, MOV $0x10,AL e MOV (DP),AL sono tutte copie in AL. Per il processore conta dove sono gli operandi: nel primo caso li ha già, nel secondo deve leggere un altro byte dell'istruzione, nel terzo deve leggere la memoria all'indirizzo in DP. L'esecuzione è identica (metti qualcosa in AL); la fase di fetch, in cui ci si procura gli operandi, no. Per questo le istruzioni si raggruppano per formato:

F0000 opcodeoperandi nei registri o assenti (HLT, NOP, RET, MOV AL,AH…)F1001 opcode…IN, OUT e MOV con DP o SP: gli operandi li legge l'esecuzioneF2010 opcodesorgente in memoria all'indirizzo DP: MOV (DP),ALF3011 opcodedestinatario in memoria all'indirizzo DP: MOV AL,(DP)F4100 opcodeoperandosorgente immediato: MOV $0x10,ALF5101 opcodeind 7_0ind 15_8ind 23_16sorgente in memoria, indirizzo diretto: ADD 0x1010,ALF6110 opcodeind 7_0ind 15_8ind 23_16destinatario in memoria, indirizzo diretto: MOV AL,0x1010F7111 opcodeind 7_0ind 15_8ind 23_16salti e CALL: JMP, Jcon, CALL indirizzo
Il primo byte di ogni istruzione: tre bit di formato (come procurarsi gli operandi, rilevante per la fase di fetch) e cinque di codice operativo (che cosa fare, rilevante per l'esecuzione). Gli indirizzi a 24 bit stanno su tre byte, dal meno significativo.
formatobyteOPCODESOURCEDEST_ADDR
F01readB @ IP––
F1?readB @ IP––
F21readB @ IPreadB @ DP–
F31readB @ IP–DP
F42readB @ IPreadB @ IP–
F54readB @ IPreadM @ IP, poi readB–
F64readB @ IP–readM @ IP
F74readB @ IP–readM @ IP

Alcune codifiche: HLT = 00000000, NOP = 00000001, MOV $op,AL = 10000000 seguito dall'operando, MOV (DP),AL = 01000000, ADD indirizzo,AL = 10100010 seguito da tre byte di indirizzo, JMP indirizzo = 11100000, CALL indirizzo = 11110011. Il formato F1 raccoglie i casi che non stanno negli altri (IN, OUT, MOV con DP o SP): il fetch legge solo l'opcode e gli operandi li preleva l'esecuzione, istruzione per istruzione.

Bus, memoria e spazio di I/O

I fili del bus

  1. 24 fili di indirizzo, uscite del processore. Per lo spazio di I/O se ne usano solo 16.
  2. 8 fili di dati, pilotati a turno dal processore e dagli altri: tutti li collegano con porte tri-state («forchetta»), e la descrizione deve garantire che non vadano mai in conduzione due sorgenti insieme.
  3. Fili di controllo attivi bassi: /mr, /mw per la memoria, /ior, /iow per l'I/O.
  4. Il clock, e il /reset che arriva a tutti nello stesso istante.

La descrizione in Verilog del calcolatore è solo un insieme di collegamenti:

Lo spazio di memoria e le maschere

RAM'H000000 – 'H09FFFFmemoria video (64 KB)'H0A0000 – 'H0AFFFFRAM'H0B0000 – 'HFEFFFFEPROM (64 KB): bootstrap'HFF0000 – 'HFFFFFFLe maschere guardano a23 … a16:/s_EPROM = 0 se a23…a16 = 11111111/s_VIDEO = 0 se a23…a16 = 00001010/s_RAM = 0 negli altri casiIl chip di RAM copre tutti gli indirizzi,ma la sua maschera non lo selezionaquando rispondono EPROM o video.Sul bus non c'è nessun filo di select:ogni modulo si costruisce il suo /s.
Lo spazio di memoria è un montaggio «in serie» di moduli diversi. Una maschera per modulo, una piccola rete combinatoria, produce il select guardando gli indirizzi più significativi.

I tre moduli (RAM, memoria video, EPROM) si montano «in serie»: ognuno risponde a un intervallo di indirizzi, e la sua maschera genera il select dagli otto bit più alti. Con le variabili in algebra di Boole:

  • /sEPROM = NAND(a23, a22, …, a16): attivo quando sono tutti a 1;
  • /sVIDEO = NAND(a23, a22, a21, a20, a19, a18, a17, a16): attivo con 00001010;
  • /sRAM = NAND(/sEPROM, /sVIDEO): la RAM risponde quando nessuno degli altri due è selezionato.

Lo spazio di I/O

Dal lato del bus un'interfaccia è una piccola RAM di poche locazioni, le porte: select, /ior, /iow, qualche filo di indirizzo per distinguere le porte, i dati. Le differenze: alcune porte si possono solo leggere o solo scrivere (e allora manca uno dei due comandi), e un'interfaccia con una sola porta non ha fili di indirizzo.

/s/ior/iowazione
1––nessuna
011nessuna
001ciclo di lettura
010ciclo di scrittura
000non definita

Esempio: un'interfaccia con due porte agli offset 'H03C8 e 'H03C9 riceve il filo a0, e la sua maschera controlla che a15 … a1 valgano 0000 0011 1100 100. Un'altra con le porte a 'H0060 e 'H0064 (non contigue) riceve a2, l'unico bit in cui differiscono, e la maschera controlla tutti gli altri. Domanda d'esame classica: chi decide l'offset di una porta? Chi progetta la maschera.

Il processore come rete sequenziale

I registri interni e il reset

Oltre ai registri visibili al programmatore, il processore contiene:

STAR e MJR

Il registro di stato e il Multiway Jump Register, per i salti a molte vie e le sottoliste di lettura e scrittura. Con 86 stati bastano 7 bit.

OPCODE, SOURCE, DEST_ADDR

Riempiti dal fetch: il codice operativo, l'operando sorgente se sta in memoria, l'indirizzo del destinatario se sta in memoria.

registri delle uscite

A23_A0, D7_D0, MR_, MW_, IOR_, IOW_, e DIR che abilita la tri-state verso i dati.

APP0…APP3, NUMLOC

Appoggi per le letture e scritture di più byte.

Al reset: IP all'inizio della EPROM, F a zero, tutti i comandi del bus inattivi, DIR a 0 (dati in alta impedenza), STAR al primo stato del fetch. Gli altri registri possono contenere valori casuali: verranno scritti prima di essere usati. Il comportamento è un ciclo fetch → esecuzione, da cui si esce solo con HLT o con un codice operativo non valido: in entrambi i casi il processore resta fermo fino al prossimo reset.

Accanto al μ-programma ci sono alcune reti combinatorie, descritte con function: valid_fetch (il byte è un opcode noto?), first_execution_state (il primo stato dell'esecuzione di quell'opcode), jmp_condition (si salta, dati opcode e flag?), e la ALU con alu_result e alu_flag.

I cicli di bus

Lettura in memoriaclockA23_A0ind/MRDIRd7_d0alta imp.datialta imp.mem_r0mem_r1mem_r2dopoScrittura in memoriaclockA23_A0ind/MWDIRd7_d0alta imp.bytemem_w0mem_w1mem_w2mem_w3Ogni colonna mostra i registri dopo il fronte: ciò che mem_r0 assegnasi vede in mem_r1. In mem_r2 i dati sono buoni e si campionano.La RAM memorizza sul fronte di salita di /mw: indirizzo e datirestano fermi fino a mem_w3, dove DIR torna a 0.
I cicli di bus verso la memoria, scritti come stati del μ-programma. In lettura il processore non pilota i fili di dati (DIR = 0); in scrittura li pilota con DIR = 1 e deve tenerli fermi attorno al fronte di salita di /mw.

In lettura DIR non si porta a 1 subito dopo: le tri-state della RAM vanno in alta impedenza un po' dopo la risalita di /mr, e si rischierebbe un conflitto elettrico. In scrittura DIR non si abbassa in mem_w2, né si cambia l'indirizzo: la RAM memorizza sul fronte di salita di /mw, e lì dati e indirizzi devono essere stabili. D'ora in poi si assume una memoria abbastanza veloce da non richiedere stati di wait.

Lettura nello spazio di I/OclockA23_A0offset/IORd7_d0alta imp.datialta imp.io_r0io_r1io_r2io_r3dopoScrittura nello spazio di I/OclockA23_A0offset/IOWd7_d0alta imp.byteio_w0io_w1io_w2io_w3L'indirizzo è stabile un clock prima che /ior scenda: in I/O ancheuna lettura può cambiare lo stato di un'interfaccia.Molte interfacce memorizzano sul fronte di discesa di /iow:i dati vanno sul bus prima (si assegnano in io_w0).
Gli stessi cicli verso lo spazio di I/O: offset a 16 bit, fili /ior e /iow invece di /mr e /mw (scambiarli è un errore frequente all'esame), e due vincoli in più sui tempi.

Leggere e scrivere più byte: μ-sottoprogrammi

Il processore legge 1 byte (opcode, operandi), 2 (offset di I/O) o 3 (indirizzi). Invece di riscrivere ogni volta i cicli di bus, si usano sottoliste con MJR come indirizzo di ritorno: NUMLOC conta i byte, APP0…APP3 li contengono in ordine di lettura (il byte meno significativo per primo).

La scrittura è duale (writeB … writeL, con D7_D0 caricato da APP0…APP3 e un impulso di /mw per byte). Per scrivere un dato a 16 bit: APP1 <= dato[15:8]; APP0 <= dato[7:0]; A23_A0 <= indirizzo; MJR <= Sx_piu_1; STAR <= writeW;.

La fase di fetch

All'uscita dal fetch: OPCODE contiene il codice operativo; se c'è un sorgente in memoria, il suo valore è in SOURCE, comunque fosse indirizzato (indiretto, immediato, diretto); se c'è un destinatario in memoria, il suo indirizzo è in DEST_ADDR; IP punta già all'istruzione successiva. Per questo l'esecuzione di MOV (DP),AL, MOV $op,AL e MOV indirizzo,AL è un unico stato.

Ecco, clock per clock, il μ-programma che esegue ADD 0x000100, AL (codificata 'HA2 'H00 'H01 'H00 a partire da 'HFF0002), dopo un MOV $0x05, AL, con la cella 'H000100 che contiene 'H2A. La traccia è prodotta simulando proprio gli stati scritti sopra; in giallo i registri appena cambiati.

clockSTARA23_A0/MRd7_d0IPMJROPCODESOURCEALμ-istruzioni eseguite al fronte successivo
prelievo del codice operativo
15fetch0'HFF00021Z'HFF0002ldAL'H80'H05'H05A23_A0<=IP; IP<=IP+1; MJR<=fetch1; STAR<=readB
16readB'HFF00021Z'HFF0003fetch1'H80'H05'H05MR_<=0; NUMLOC<=1
17read0'HFF00020'HA2'HFF0003fetch1'H80'H05'H05APP0<=d7_d0; A23_A0<=A23_A0+1; NUMLOC<=NUMLOC-1
18read4'HFF00030'H00'HFF0003fetch1'H80'H05'H05MR_<=1; STAR<=MJR
19fetch1'HFF00031Z'HFF0003fetch1'H80'H05'H05OPCODE<=APP0
20fetch2'HFF00031Z'HFF0003fetch1'HA2'H05'H05MJR<=(formato F5); STAR<=fetch3 (codice valido)
21fetch3'HFF00031Z'HFF0003fetchF5_0'HA2'H05'H05STAR<=MJR
formato F5: indirizzo (3 byte) e operando
22fetchF5_0'HFF00031Z'HFF0003fetchF5_0'HA2'H05'H05A23_A0<=IP; IP<=IP+3; MJR<=fetchF5_1; STAR<=readM
23readM'HFF00031Z'HFF0006fetchF5_1'HA2'H05'H05MR_<=0; NUMLOC<=3
24read0'HFF00030'H00'HFF0006fetchF5_1'HA2'H05'H05APP0<=d7_d0; A23_A0<=A23_A0+1; NUMLOC<=NUMLOC-1
25read1'HFF00040'H01'HFF0006fetchF5_1'HA2'H05'H05APP1<=d7_d0; A23_A0<=A23_A0+1; NUMLOC<=NUMLOC-1
26read2'HFF00050'H00'HFF0006fetchF5_1'HA2'H05'H05APP2<=d7_d0; A23_A0<=A23_A0+1; NUMLOC<=NUMLOC-1
27read4'HFF00060'H00'HFF0006fetchF5_1'HA2'H05'H05MR_<=1; STAR<=MJR
28fetchF5_1'HFF00061Z'HFF0006fetchF5_1'HA2'H05'H05A23_A0<={APP2,APP1,APP0}; MJR<=fetchF5_2; STAR<=readB
29readB'H0001001Z'HFF0006fetchF5_2'HA2'H05'H05MR_<=0; NUMLOC<=1
30read0'H0001000'H2A'HFF0006fetchF5_2'HA2'H05'H05APP0<=d7_d0; A23_A0<=A23_A0+1; NUMLOC<=NUMLOC-1
31read4'H0001010–'HFF0006fetchF5_2'HA2'H05'H05MR_<=1; STAR<=MJR
32fetchF5_2'H0001011Z'HFF0006fetchF5_2'HA2'H05'H05SOURCE<=APP0
fine del fetch: salto all'esecuzione
33fetchEnd'H0001011Z'HFF0006fetchF5_2'HA2'H2A'H05MJR<=first_execution_state(OPCODE)
34fetchEnd1'H0001011Z'HFF0006aluAL'HA2'H2A'H05STAR<=MJR
esecuzione
35aluAL'H0001011Z'HFF0006aluAL'HA2'H2A'H05AL<=alu_result(OPCODE,SOURCE,AL); F<=…; STAR<=fetch0
36fetch0'H0001011Z'HFF0006aluAL'HA2'H2A'H2FA23_A0<=IP; IP<=IP+1; MJR<=fetch1; STAR<=readB

Ventuno clock per un'istruzione: quasi tutti spesi a parlare con la memoria. Alla fine AL vale 'H2F = 5 + 42.

La fase di esecuzione

L'esecuzione è semplice: parte della complessità l'ha già assorbita il fetch, e le istruzioni aritmetiche si riducono a un assegnamento che usa la ALU. Ogni esecuzione termina con STAR <= fetch0, tranne HLT.

CALL è una push di IP (già incrementato dal fetch, quindi è l'indirizzo di ritorno) più un salto; RET è una pop di 3 byte in IP. Si noti che in tutto il processore i μ-salti sono al più a due vie, tranne i due salti guidati da MJR: chi chiedesse di sintetizzare la parte operativa di IP o la rete di condizionamento troverebbe solo cose già viste. Dopo due mesi di corso, si sa progettare hardware che esegue programmi arbitrariamente complessi.

Le interfacce

Registri di dati e registri di stato

Un'interfaccia con un registro di ingresso RBR e uno di uscita TBR si usa con IN offset_RBR, AL e OUT AL, offset_TBR. Ma così il processore non può sapere se tra due IN il dispositivo ha prodotto un dato nuovo, né se tra due OUT ha consumato il precedente. Servono registri di stato con un flag: FI (buffer di ingresso pieno) e FO (buffer di uscita vuoto), gestiti dall'interfaccia.

interfacciaRBR00byte dal dispositivoRSR01bit 0 = FI (ingresso pieno)TSR10bit 5 = FO (uscita vuota)TBR11byte per il dispositivo/s/ior/iowa1_a0d7_d0lato bus: sempre ugualebyte_in, /davrfdbyte_out, /davrfdlato dispositivo: dipende dal dispositivo
Visione funzionale di un'interfaccia parallela di ingresso/uscita con handshake. Il processore vede quattro porte; i flag FI e FO gli permettono di sincronizzarsi con il dispositivo. Chi decide gli offset delle porte? Il progettista della maschera che produce /s.
  • FI vale 0 al reset; va a 1 quando il dispositivo scrive un dato in RBR; torna a 0 quando il processore legge RBR.
  • FO vale 1 al reset; va a 0 quando il processore scrive in TBR; torna a 1 quando il dispositivo ha prelevato il dato.
Leggere un dato nuovo
Scrivere quando si può

È l'accesso a controllo di programma: il processore cicla in attesa attiva, ed è inefficiente. Le alternative (interruzioni, DMA) si vedono nel corso di Calcolatori Elettronici.

Interfacce parallele

L'interfaccia di ingresso più semplice ha una sola porta di sola lettura: select, /ior, 8 fili di dati, nessun indirizzo. Quando /s e /ior sono entrambi a 0 (inizio di un ciclo di lettura) RBR campiona i fili dal dispositivo e le tri-state vanno in conduzione. Ecco perché in I/O il select non deve «ballare» con /ior a 0: un'altra interfaccia memorizzerebbe un dato nel suo RBR. Quella di uscita è duale e memorizza sul fronte di discesa di /iow.

Ingresso
Uscita

Con l'handshake verso il dispositivo, dentro l'interfaccia c'è una piccola RSS che fa da consumatore (in ingresso) o da produttore (in uscita) e gestisce il flag. Il suo clock va ritardato di qualche nanosecondo rispetto a quello del processore, per non campionare eB proprio mentre cambia.

L'interfaccia seriale start/stop

Un'interfaccia seriale riceve byte dal processore e trasmette sequenze di bit su un filo (più la massa), e viceversa. Il problema è sincronizzare trasmettitore e ricevitore senza un clock comune e senza fili di handshake. La soluzione dello standard EIA-RS232C:

  • i due lati concordano prima il tempo di bit T (il suo inverso è il bitrate) e il numero di bit di una trama (da 5 a 8);
  • a riposo la linea è a 1 (marking); una trama inizia con un bit di start a 0 e finisce con almeno un bit di stop a 1. Con trame di un byte, al massimo 8 bit utili su 10: la velocità netta è l'80% di quella della linea;
  • il ricevitore campiona ogni bit a metà: 3/2 T dopo il fronte dello start, poi ogni T. I clock dei due lati non sono identici: con un errore ΔT, dopo n bit l'errore accumulato non deve superare mezzo bit, quindi ΔT/T ≤ 1/(2n): il 5% con n = 10. Per questo le trame non possono essere lunghe.
riposostartb01b10b21b31b40b51b60b70stopriposomarking (1)spacing (0)3/2 TTIl byte 00101101 ('H2D) parte dal bit meno significativo. Il ricevitore si sincronizza sul fronte di discesa dello starte campiona ogni bit a metà: dopo 3/2 T il primo, poi uno ogni T. Con n bit tra due start serve ΔT/T ≤ 1/(2n).
Una trama sulla linea seriale. Senza clock comune né fili di handshake, trasmettitore e ricevitore si accordano prima su tempo di bit e formato; il bit di start serve solo a dire «comincia una trama», lo stop a riportare la linea a riposo.

Le tensioni dello standard non sono quelle delle reti logiche: l'1 è tra −3 e −25 V, lo 0 tra +3 e +25 V. Dentro l'interfaccia c'è una sotto-interfaccia parallela con handshake, collegata a due RSS: il trasmettitore e il ricevitore. Il trasmettitore ha un clock pari al tempo di bit: preleva un byte con l'handshake, prepara in BUFFER la trama intera (start, dati, stop) e ne trasmette un bit per clock, traslando a destra. COUNT parte da 10 e il test è a 1: dieci giri.

Il ricevitore ha differenze importanti. Non può fermare il trasmettitore dall'altra parte del filo, quindi verso la sotto-interfaccia non gestisce un handshake completo: abbassa /dav quando il byte è pronto e lo rialza dopo il bit di stop, che il dato sia stato letto o no (altrimenti lo sovrascriverà la trama successiva: overrun). E deve campionare a metà bit, quindi il suo clock è più veloce: nella dispensa 16 volte il bitrate, per stimare bene l'istante dello start. Con WAIT inizializzato a k e testato a 1 si fanno k giri, più il clock dello stato che lo inizializza: 23 per i 24 clock di 3/2 T, 15 per i 16 clock di T.

Per poterlo seguire in un diagramma leggibile, qui sotto lo stesso ricevitore ha un clock di soli 4 colpi per bit (WAIT a 5 e 3 invece che 23 e 15). La linea porta la trama di 'H2D; puoi cambiarla cliccando su rxd.

Conversione digitale/analogica e analogica/digitale

Una tensione v su una scala di FSR volt (Full-Scale Range) si associa a un numero x su N bit, con costante K = FSR / 2N: idealmente v = K · x.

  • unipolare: v ∈ [0, FSR], x ∈ [0, 2N − 1]; bipolare: v ∈ [−FSR/2, +FSR/2], x ∈ [−2N−1, 2N−1 − 1], rappresentato in traslazione (binario bipolare): X = x + 2N−1. Per passare dalla traslazione al complemento a 2 basta complementare il bit più significativo;
  • errori: di non linearità (componenti non ideali, sia D/A sia A/D), che deve restare sotto K/2, e di quantizzazione (solo A/D), al più K/2. Esempio: N = 8, FSR = 10,24 V, K = 40 mV; x = +127 dà 5,08 V ± 20 mV.

Il convertitore D/A è una rete di resistenze (scala R-2R) con interruttori comandati dai bit e un amplificatore operazionale che tiene a zero il nodo di somma: la corrente è i = (K/R) · X, e la tensione V = K · X − Vpol, unipolare con Vpol = 0, bipolare con Vpol = FSR/2. È in pratica combinatorio, quindi velocissimo, ma ha transizioni spurie (da 01111111 a 10000000 cambiano tutti i bit): a valle si mette un filtro passa-basso. Due resistenze tarabili correggono gli errori di offset e di guadagno. L'interfaccia è un'interfaccia di uscita senza handshake: il processore scrive in TBR quando vuole.

Il convertitore A/D ad approssimazioni successive contiene una RSS, il SAR (Successive Approximation Register), un convertitore D/A e un comparatore. Fa una ricerca per bisezione sul byte da produrre, un bit per clock dal più significativo; dialoga con l'esterno con un handshake soc/eoc, e un latch analogico tiene ferma la tensione durante la conversione.

064128192256vclock 110000000α = 1clock 211000000α = 0clock 310100000α = 1clock 410110000α = 0clock 510101000α = 1clock 610101100α = 0clock 710101010α = 1clock 810101011α = 0Risultato: 10101010 = 170. Ogni clock dimezza l'intervallo e fissa un bit, dal più significativo: 8 bit, 8 confronti.
Il convertitore A/D ad approssimazioni successive fa una ricerca per bisezione: prova 10000000, il comparatore (α) dice se la tensione è più alta o più bassa, e il bit resta 1 o torna 0. Il tempo di conversione dipende dal numero di bit, non dalla tensione.

L'interfaccia di conversione ha un registro di stato e controllo (SOC scrivibile nel bit 1, EOC leggibile nel bit 0) e RBR con il risultato. Il software di gestione, da non confondere con il μ-programma del convertitore:

Siccome il convertitore inizia la conversione molto in fretta, nel software si può saltare l'attesa di EOC = 0. Non così in un esercizio di descrizione: una rete che comanda un convertitore deve sempre rispettare l'handshake, cioè scrivere qualcosa come S2: begin SOC <= eoc; STAR <= (eoc==1) ? S2 : S3; end, e mai abbassare SOC alla cieca.

Buone norme ed errori tipici

  • Nello spazio di I/O si usano /ior e /iow, non /mr e /mw, e gli indirizzi sono a 16 bit ({'H00, offset}).
  • In lettura di I/O l'indirizzo è stabile un clock prima che /ior scenda, e non cambia finché /ior non risale: una lettura può modificare lo stato dell'interfaccia.
  • In scrittura di I/O i dati sono sul bus prima del fronte di discesa di /iow; in memoria devono restare fermi attorno al fronte di salita di /mw.
  • DIR vale 1 solo durante le scritture, e torna a 0 solo dopo che il comando di scrittura è risalito.
  • Sul bus non c'è un filo di select: i select li producono le maschere, e l'offset di una porta lo decide chi le progetta.
  • Le interfacce sono RSS: hanno il loro /reset e, se campionano segnali del processore, un clock leggermente ritardato.
  • In un esercizio con un convertitore o un'altra rete asincrona, gli handshake si rispettano sempre per intero.
  • Nei ricevitori seriali conta l'istante di campionamento: la regola k − j + 1 e il clock perso nello stato che inizializza il contatore.

Verifica