Decoder Circuito che converte un codice di input a nbit in un codice di output a m bit. Struttura generale del decoder Tipicamente n input, m=2n outputs 2-to-4, 3-to-8, 4-to-16, etc. 1 2 Decoder binari Circuito da-n-a-2n Codice 1-fra-m:contiene m bit con un solo bit asserito ad ogni istante Decoder da-2-a-4: Si noti la notazione “x” (don’t care) 3 4 Diagramma logico del decoder da-2-a-4 con enable 5 Decoder da-2-a-4 in logica negativa • Buffer di input (meno carico) • gate NAND (più veloci) 6 Decoder da-3-a-8 a b c 3-to-8 Line Decoder y0 = a’b’c’ y1 = a’b’c y2 = a’bc’ y3 = a’bc y4 = ab’c’ y5 = ab’c y6 = abc’ y7 = abc a 0 0 0 0 1 1 1 1 b 0 0 1 1 0 0 1 1 c 0 1 0 1 0 1 0 1 Y7 0 0 0 0 0 0 0 1 Y6 0 0 0 0 0 0 1 0 Y5 0 0 0 0 0 1 0 0 Y4 0 0 0 0 1 0 0 0 Y3 0 0 0 1 0 0 0 0 Y2 0 0 1 0 0 0 0 0 Y1 0 1 0 0 0 0 0 0 Y0 1 0 0 0 0 0 0 0 + 7 Decoder da-3-a-8 con codice di input Gray Il codice di input non rappresenta necessariamente gli interi da 0 a 2n-1. Supponiamo che il codice di input sia il codice Gray di un disco di codifica meccanica con otto posizioni. Posizione del disco 0o 45o 90o 135o 180o 225o 270o 315o I2 I1 I0 output del decoder binario 0 0 0 Y0 0 0 1 Y1 0 1 1 Y3 0 1 0 Y2 1 1 0 Y6 a 1 1 1 Y7 b 1 0 1 Y5 c 1 0 0 Y4 3-to-8 Line Decoder DEG0 DEG45 DEG135 DEG90 DEG315 DEG270 DEG180 DEG225 8 Decoder da-3-a-8 74x138 9 Decoder da-2-a-4 controllato da un contatore a 2 bit 10 11 12 Applicazioni dei decoder – Memoria dei microprocessori • Selezione di diversi banchi di memoria – Sistemi di input/output di microprocessori • Selezione di diversi dispositivi – Decodifica di istruzioni di microprocessori • Abilitazione di diverse unità funzionali – Chips di memoria • Abilitazione di diverse righe di memoria a seconda dell’indirizzo – Moltissime altre applicazioni 13 Decoder in verilog 14 multiplexing Multiplexing nella forma più semplice: un tasto (switch) meccanico capace di selezionare fra diverse sorgenti Sorgenti: 4 microfoni che inviano a una stazione remota di ascolto della polizia segrenta Una volta al mese un agente segreto agisce sul tasto per ascoltare uno dei microfoni 15 Sistema multiplexato Sistema telefonico Sistema di periferiche collegate a un computer 16 Multiplexing: hardware Sono necessari due elementi: 1. circuito passa/blocca analogo al tasto chiuso/aperto 2. circuito di decodifica che chiuderà solo uno degli elementi passa/blocca per volta pass/block’ segnale-in segnale-out 0 0 0 0 1 0 1 0 0 1 1 1 gate AND IN pass/block’ OUT pass/ block Multiplexer 2-to-1 17 Il MUX più semplice: 18 Mux a quattro input Circuito che fa “collega” uno dei quattro input all’ouput out a seconda del valore delle due linee di selezione SEL[1..0] 19 Mux a quattro input Circuiti passa/blocca Decoder da-2-a-4 IN0 EN0 IN1 OR dei segnali EN1 Z IN2 EN2 IN3 EN3 20 Progetto 2 Esempio di utilizzo di multiplexer e decoder 21 seven-seg-decoder 22 FPGA seven-seg-decoder Dalla FPGA escono solo 7 linee di controllo dei led comuni ai 4 array E’ necessario interporre un MUX fra i 4 seven-seg-decoder e le linee di uscita 23 24 una cifra diversa 25 26 27 28 29 30 31 32 Un mux a quattro input può implementare qualunque funzione a tre variabili 1 I0 0 I1 T I2 T I3 Esempio: implementiamo la funzione F(R, S, T) = R’S’ + RT Z A B R S A 0 0 1 1 + B 0 1 0 1 Z 1 0 T T F(R,S,T) F(R,S,T) = R’S’•1 + RT•(S+S’) = R’S’•1 + R’S•0 + RS•T + RS’•T 00 01 11 10 Functions of how many input variables can be implemented by an 8-t0-1 MUX? Utilizzare un 8-to-1 MUX per implementare la funzione: F(X,Y,Z,T) = XY’ + Z’T 33 Implementazione “tradizionale” Come implementare la funzione logica con un mux? 34 35 36 37 Tristate Consideriamo una serie di dispositivi collegati a una CPU tramite una linea comune (bus) La CPU può abilitare uno dei dispositivi per volta che accede al bus trasmettendo dati C P U EN0 EN0=1 EN0=0 EN1 EN1=1 out0 out1 out2 EN2 MUX a quattro input? out3 EN3 38 Come facciamo a fare MUX? Problema: è impossibile mettere in OR OUT0, ..., OUT3 IN0 EN0 IN1 EN1 output sul bus? IN2 EN2 NO! IN3 EN3 39 Le uscite del gate logici che abbiamo studiato finora non possono essere collegate assieme I gate si “sparano” uno contro l’altro 40 Come facciamo a fare MUX? Andrebbe bene un sistema tale che se un dispositivo non è abilitato è come se non fosse fisicamente collegato al bus C P U EN0=1 EN0=0 EN1 EN1=1 out0 out1 out2 out3 EN2 buffer tristate: EN A OUT EN3 EN L L H H A L H L H OUT Hi-Z Hi-Z L H Hi-Z: alta impedenza linea scollegata 41 42 43 Mux con buffers tristate periferica EN0 data0 out0 EN1 out1 data1 output sul bus? EN2 out2 data2 SI! EN3 out3 data3 44 data## dati che la periferica ## trasmette se richiesto (EN## asserito dalla CPU) Tristate party line col 74x138 45 Considerazioni sulla temporizzazione Per impedire conflitti, dovrebbero andare nello stato Hi-Z più velocemente di quanto impiegano per andare nello stato Hi-Z (tpLZ e tpHZ dovrebbero essere minori di tpZL tpZH) 46 Per sicurezza, la logica di controllo dovrebbe garantire un tempo morto sulla party line durante il quale nessuno pilota la linea. 47 Esempio motivante: l’unità logico-aritmetica (ALU) Parte importante del percorso dei dati nell’architettura di una CPU operand1 ALU alu_result operand2 ALU operation opcode Come tutto l’hardware, può essere disegnata usando un linguaggio di programmazione orientato all’hardware (HDL) Utile esempio perchè può essere facilmente decomposta 48 Esempio motivante: l’unità logico-aritmetica (ALU) • Insieme di operazioni: operand1 ALU alu_result operand2 ALU operation opcode Logic • AND • OR • XOR • NOT Arithmetic • add • subtract • multiply • negate 49 Struttura della ALU arithmetic operation Modulo aritmetico Arith_result operand1 MUX Alu_result operand0 Modulo logico logic operation Logic_result 2 opcode 1 selection 50 Struttura della ALU ALU Modulo Aritmetico Arith_result operand1 MUX Alu_result operand0 Modulo logico Logic_result 2 opcode 1 selection 51 VERILOG HDL • Disegni organizzati gerarchicamente • Ciascun elemento del disegno ha: – Un’interfaccia ben definita – Una precisa specifica del comportamento usando o: • Una descrizione algoritmica • Una descrizione strutturale dell’hardware • Modella la concorrenza, la temporizzazione, e il clock: – Gestisce circuiti asincroni e sincroni – I disegni possono essere simulati 52 Struttura gerarchica della ALU alu alu_arch arithmetic_module arithmetic_module_arch Arithmetic Functionality logic_module logic_module_arch Logic Functionality mux mux_arch Multiplexer Procedura bottom-up: cominciamo a modellare gli elementi più in basso 53 Mux: introduzione ai moduli e porte Il blocco costruttivo fondamentale di verilog è il modulo elemento o collezione di blocchi di livello più basso. Arith_result MUX Alu_result Sintassi: Logic_result selection module mux(Arith_result, Logic_result, Alu_result); Dichiarazione varibili … Funzionalità endmodule; 54 Dichiarazione di variabili: segnali di input e output Segnali di input: Arith_result, Logic_result, selection porte Segnale di output: Alu_result Arith_result MUX Alu_result Sintassi: Logic_result selection module mux(Arith_result, module modulemux(Arith_result, mux(Arith_result, Logic_result, Logic_result, Logic_result, selection, selection, selection, Alu_result); Alu_result); Alu_result); funzionalità input Logic_result,Alu_result; inputArith_result, Arith_result, … Logic_result,selection; … output Alu_result; endmodule; endmodule; … endmodule; 55 Disegno a livello di gate Verilog supporta i gate logici fondamentali come moduli primitivi predefiniti. Arith_result a1 selection Alu_result Logic_result selection a0 selection_n module mux(Arith_result, Logic_result, selection, Alu_result); net: connessioni fra elementi hardware Le net sono dichiarate con la keyword wire. input Arith_result, Logic_result,selection; Hanno valori pilotati continuamente dagli output Alu_result; output dei dispositivi cui sono collegate wire selection_n, a0, a1; … endmodule; Gli input e output del modulo 56 sono implicitamente wire Instanziamento dei moduli primitivi Arith_result a1 selection Alu_result Logic_result selection a0 selection_n module mux(Arith_result, module mux(Arith_result, Logic_result, module mux(Arith_result, Logic_result, selection, Logic_result, selection, Alu_result); module mux(Arith_result, selection, Alu_result); Logic_result, Alu_result); input Arith_result, Logic_result,selection; selection, input Arith_result, Logic_result,selection; output Alu_result; Alu_result); input outputArith_result, Alu_result; Logic_result,selection; output Alu_result; a1; wire inputselection_n, Arith_result,a0, Logic_result,selection; wire selection_n, a0, a1; output Alu_result;a0, a1; wire selection_n, not (selection_n,selection); not (selection_n,selection); and (a1,selection,Arith_result); wire selection_n, a0, a1; not (a1,selection,Arith_result); and (selection_n,selection); (a0,selection_n,Logic_result); … and (a1,selection,Arith_result); (a0,selection_n,Logic_result); or (Alu_result,a0,a1); endmodule; not (selection_n,selection); 57 endmodule; endmodule; endmodule; Metodo di instanziamento alternativo Arith_result a1 selection Alu_result Logic_result selection a0 selection_n module mux(Arith_result, module mux(Arith_result, Logic_result, module mux(Arith_result, Logic_result, selection, Logic_result, selection, Alu_result); module mux(Arith_result, selection, Alu_result); Logic_result, Alu_result); input Arith_result, Logic_result,selection; selection, input Arith_result, Logic_result,selection; output Alu_result; Alu_result); input outputArith_result, Alu_result; Logic_result,selection; output Alu_result; a1; wire inputselection_n, Arith_result,a0, Logic_result,selection; wire selection_n, a0, a1; output Alu_result;a0, a1; wire selection_n, not not1(selection_n,selection); not (selection_n,selection); and and1(a1,selection,Arith_result); wire selection_n, a0, a1; not (a1,selection,Arith_result); and (selection_n,selection); and0(a0,selection_n,Logic_result); … and (a1,selection,Arith_result); (a0,selection_n,Logic_result); or or1(Alu_result,a0,a1); endmodule; not (selection_n,selection); 58 endmodule; endmodule; endmodule; Un maggiore livello di astrazione: modellazione del flusso dei dati (dataflow) Modellazione a livello di gate: intuitivo tuttavia non efficiente per componenti con un numero di gate grande. Modellazione del flusso dei dati: rappresentazione di un circuito in termini del flusso dei dati fra input e output a un livello più astratto Funzionamento specificato non in termini di gate elementari X1 X2 Z1 Z2 Xm Zm Assegnazione continua assign: istruzione fondamentale per pilotare un valore su una net: wire Z1; assign Z1 = operazione logica su X1, X2, … X1, X2, ... = operandi 59 Operazione logica: operatore Operazioni logiche su coppie di operandi AND: assign Z1 = X1 & X2; OR: assign Z1 = X1 | X2; NOT: assign Z1 = ~ X1; module mux(Arith_result, Logic_result, selection, Alu_result); Arith_result a1 a1 selection input Arith_result, Logic_result,selection; output Alu_result; assign a1 = selection & Arith_result Alu_result assign Alu_result = a0 Logic_result ( ~ selection & Logic_result) | a0 (selection & Arith_result); selection selection_n assign Alu_result = a0 | a1; endmodule; assign a0 = ~ selection & Logic_result 60 Operatore condizionale assign Alu_result = selection ? Arith_result : Logic_result; Espressione condizione: Se vera (1) Alu_result = Arith_result Se falsa (0) Alu_result = Logic_result module mux(Arith_result, Logic_result, selection, Alu_result); input Arith_result, Logic_result,selection; output Alu_result; assign Alu_result = selection ? Arith_result : Logic_result; endmodule; 61 Vettori ALU a 8 bit: Arith_result, Logic_result e ALU_result sono numeri a 8 bit Arith_result Arith_result[7:0] Logic_result Logic_result[7:0] ALU_result ALU_result[7:0] module mux(Arith_result, Logic_result, selection, Alu_result); input [7:0] Arith_result, Logic_result,selection; output [7:0] Alu_result; assign Alu_result = selection ? Arith_result : Logic_result; endmodule; 62 Modulo aritmetico operand1 operand0 Arith_result opcode Operandi: vettori a 8 bit module arith_module(operand0, operand1, opcode, Arith_result); opcode: 4 operazioni vettore a 2 bit input [7:0] operand0, operand1; module arith_module(operand0, output [7:0] Arith_result; input [1:0] opcode; operand1, wire [7:0] zero = 8’b0; opcode, Operazioni: Arith_result); wire [7:0] op0 = operand1 + operand0; opcode = 0 Arith_result = operand0 + operand1 input [7:0] op1 operand0, operand1; wire [7:0] = operand1 – operand0; output wire [7:0] [7:0] op2 Arith_result; = zero – operand0; opcode = 1 Arith_result = operand0 - operand1 input [1:0] op3 opcode; wire [7:0] = operand1 * operand1; wire [7:0] zero = 32’b0; opcode = 2 Arith_result = zero – operand0 … … opcode = 3 Arith_result = operand0 * operand1 endmodule; endmodule; 63 Le quattro operazioni devono essere multiplexate mux 1 di 4 con operatori condizionali annidati module arith_module(operand0, operand1, opcode, Arith_result); input [7:0] operand0, operand1; output [7:0] Arith_result; input [1:0] opcode; wire [7:0] zero = 8’b0; wire [7:0] op0 = operand1 + operand0; wire [7:0] op1 = operand1 – operand0; wire [7:0] op2 = zero – operand0; wire [7:0] op3 = operand1 * operand1; assign Arith_result = opcode[1] ? (opcode[0] ? op3 : op2) : (opcode[0] ? op1 : op0); endmodule; 64 Variabili di tipo registro (reg) I registri rappresentano elementi di memorizzazione dati (data storage) Mantengono il loro valore finchè un altro valore è posto su essi A differenza di una net un registro non necessita un driver e non sono pilotati continuamente Non devono essere confusi con i registri hardware costruiti con flip-flop D e che possono cambiare il loro valore solo sul bordo di un clock possono cambiare valore a un istante qualsiasi. Sono dichiarati con la keyword reg. modulo input output reg o net net net reg o net 65 Statement always always @(condizione) begin … end Ogni volta che è soddisfatta la condizione in parentesi, vengono eseguiti tutti gli stament contenuti all’interno del blocco begin-end Blocco begin-end: analogo a un raggruppamento di istruzioni {} del linguaggio di programmazione C. always @(clk) q=d q=d è eseguito ogni volta che il segnale clk cambia valore always @(posedge clk) q=d q=d è eseguito ogni volta che il segnale clk compie una transizione positiva always @(negedge clk) q=d q=d è eseguito ogni volta che il segnale clk compie una transizione negativa 66 Possono essere presenti più blocchi always in un modulo: tutti i blocchi funzionano simultaneamente e in modo concorrenziale caratteristica fondamentale del funzionamento dei componenti hardware caratteristica distintiva di Verilog rispetto a un linguaggio come il C in cui tutte le istruzioni sono eseguite in modo sequenziale always @(negedge clk) q=d La variabile q a cui è assegnato d a ogni bordo negativo del segnale clk deve essere necessariamente di tipo reg deve mantenere il valore fra due istanti in cui si verifica la condizione negedge clk 67 Statement case sintassi case(espressione) alternativa 0: statement 0; alternativa 1: statement 1; … endcase L’espressione è confrontata alle alternative nell’ordine in cui appaiono Per la prima alternativa per cui c’e’ accordo il corrispondente statement o blocco è eseguito 68 module arith_module(operand0, operand1, opcode, Arith_result); input [7:0] operand0, operand1; output [7:0] Arith_result; reg [7:0] Arith_result; input [1:0] opcode; wire [7:0] zero = 8’b0; always @(operand0 or operand1 or opcode) case(opcode) 2’d0: Arith_result = operand1 + operand0; 2’d1 Arith_result = operand1 – operand0; 2’d2 Arith_result = zero – operand0; 2’d3 Arith_result = operand1 * operand1; endcase endmodule; Esecuzione triggerata da una transizione di uno qualsiasi dei segnali operand o opcode always @(segnale0 or segnale1 or69…) Abbellimenti module arith_module(operand0, operand1, opcode, module arith_module(operand0, Assegamo un nome alle module arith_module(operand0, Arith_result); operand1, operand1, opcode, varie operazioni: opcode, `define Add 2’d0; Arith_result); module arith_module(operand0, Arith_result); `define Sub 2’d1; Opcode = 2’b0 Add operand1, `define `defineNeg Add2’d2; 2’d0; opcode, `define Add 2’d0; `define Mult 2’d3; `define Sub 2’d1; Opcode = 2’d1 Sub Arith_result); `define `defineSub Neg2’d1; 2’d2; input [7:0] operand0, operand1; Opcode = 2’d2 Neg `define Add 2’d0; input operand0, operand1; output [7:0] Arith_result; input[7:0] [7:0] operand0, operand1; input [7:0] operand0, operand1; output [7:0] Arith_result; reg [7:0] Arith_result; output [7:0] Arith_result; output [7:0] Arith_result; Opcode = 2’d3 Mult reg Arith_result; input [1:0] opcode; reg[7:0] [7:0] Arith_result; reg [7:0] Arith_result; input [1:0] opcode; wire = 8’b0; input[7:0] [1:0]zero opcode; input [1:0] opcode; wire wire[7:0] [7:0]zero zero= =8’b0; 8’b0; wire [7:0] zero = 8’b0; always @(operand0 or operand1 or opcode) always case(opcode) always@(operand0 @(operand0ororoperand1 operand1ororopcode) opcode) always @(operand0 or operand1 or opcode) case(opcode) `Add : Arith_result = operand1 + operand0; case(opcode) case(opcode) `Add `Sub operand1+–+operand0; operand0; `Add::Arith_result :Arith_result Arith_result==operand1 operand0; `Add : Arith_result = operand1 + operand0; `Sub – –operand0; `Neg : Arith_result===operand1 zero – operand0; `Sub: Arith_result operand1 operand0; `Mult operand1 * operand0; `Neg :: Arith_result Arith_result == zero – operand0; endcase endcase endcase endcase endmodule; endmodule; endmodule; endmodule; 70 Generalizzare il module arith_module(operand0, codice operand1, opcode, Arith_result); Il nostro progetto richiede una ALU a 8 bit. Un upgrade potrebbe richiedere la processazione di numeri`define a 16 bit. ALU_width 8; modulo generico funzionante entrambi `defineinAdd 2’d0; i casi con modifiche minime `define Sub 2’d1; `define Neg 2’d2; `define Mult 2’d3; Dobbiamo cambiare la larghezza in un solo punto input [`ALU_width-1:0] operand0, operand1; output [`ALU_width-1:0] Arith_result; reg [`ALU_width-1:0] Arith_result; input [1:0] opcode; wire [`ALU_width-1:0] zero = 8’b0; always @(operand0 or operand1 or opcode) case(opcode) `Add : Arith_result = operand1 + operand0; `Sub : Arith_result = operand1 – operand0; `Neg : Arith_result = zero – operand0; `Mult : Arith_result = operand1 * operand0; endcase 71 Modulo logico struttura simile al modulo aritmetico AND OR XOR NOT modulearith_module(operand0, logic_module(operand0, module operand1, operand1, module arith_module(operand0, opcode, opcode, operand1, Arith_result); Arith_result); opcode, module arith_module(operand0, Arith_result); operand1, `defineALU_width ALU_width8; 8; opcode, `define `define ALU_width 8; Arith_result); `defineAND AND2’d0; 2’d0; `define `defineAND OR2’d1; 2’d1; `define OR 2’d0; 8; `define ALU_width `defineXOR XOR 2’d2; `define 2’d2; OR 2’d1; `defineAND NOT2’d0; 2’d3; `define input [`ALU_width-1:0] operand0, operand1; input[`ALU_width-1:0] [`ALU_width-1:0] operand0, operand1; output [`ALU_width-1:0]operand0, Arith_result; input operand1; output [`ALU_width-1:0] Arith_result; reg [`ALU_width-1:0] Arith_result; output [`ALU_width-1:0] Arith_result; reg[`ALU_width-1:0] [`ALU_width-1:0] Arith_result; input [1:0] opcode; Arith_result; reg input[`ALU_width-1:0] [1:0]opcode; opcode; zero = 8’b0; wire input [1:0] wire[`ALU_width-1:0] [`ALU_width-1:0]zero zero==8’b0; 8’b0; wire always @(operand0 or operand1 or opcode) always@(operand0 @(operand0or oroperand1 operand1or oropcode) opcode) case(opcode) always case(opcode) `AND : Arith_result = operand1 & operand0; case(opcode) `AND :::Arith_result Arith_result===operand1 operand1& operand0; `OR operand1 |&operand0; `AND Arith_result operand0; `OR :: Arith_result Arith_result ==operand0 operand1^| operand1; operand0; `XOR `XOR : Arith_result = operand0 ^ operand1; endcase `NOT : Arith_result = ~operand0; endcase endmodule; endcase endmodule; 72 Modulo ALU Input: operand0[7:0], operand1[7:0], opcode[2:0] output: ALU_result[7:0] Unità aritmetica Unità logica Mux module ALU(operand0, operand1, opcode, module ALU(operand0, ALU_result); operand1, opcode, `define ALU_width 8; ALU_result); input [`ALU_width `define ALU_width :0] 8; operand0, operand1; input [2:0] opcode; output [`ALU_width:0] :0]operand0, ALU_result; input [`ALU_width operand1; input [2:0] opcode; wire [`ALU_width :0]:0] Arith_result; output [`ALU_width ALU_result; Arith_module myArith_module(operand0, operand1, … [`ALU_width :0] Arith_result; wire opcode[1:0], Arith_module myArith_module(operand0, Arith_result); endmodule; operand1, opcode[1:0], wire [`ALU_width :0] Logic_result; Arith_result); Logic_module myLogic_module(operand0, operand1, endmodule; wire [`ALU_width :0] Logic_result; opcode[1:0], Logic_module myLogic_module(operand0, Logic_result); operand1, Mux myMux(Arith_result,Logic_result,opcode[2], opcode[1:0], ALU_result); Logic_result); endmodule; endmodule; 73