RACCOLTA ESERCIZI Modellazione Verilog
Transcript
RACCOLTA ESERCIZI Modellazione Verilog
RACCOLTA ESERCIZI Modellazione Verilog Eserciziio 1 Scrivere una u descriizione verilog del cirrcuito disegnato in fiigura, dove e i blocchi hanno la a funzionalità descritta a di seguito o. REG: Reg gistro a 16 6 bit con re eset (rst) asincrono a attivo bassso e con u un uscita ZERO Z che e indica se il contenutto del regisstro è pari a zero (ZE ERO=1 se ili contenutto è zero) MUX: mulltiplexer co on due ingrressi a 16 bit, 1 bit dii selezione e ed un’usccita a 16 biit c due ing gressi (ope erandi A e B) da 16 b bit, 3 bit dii selezione e ALU: unittà aritmeticco/logica con (Sel[2:0]) un’uscita Y determin nata dalla tabella t seg guente: sel[2 [2] 0 0 0 1 1 1 sel[1 1] 0 0 1 0 0 1 sel[[0] 0 1 0 0 1 1 Op perazioni ALU A Operazion ne Y<= A Y<=A+1 Y<=A+B B Y<=A and dB Y<= A norr B Y A xnorr B Y<= Fun nzione Trasfe ferimento Increm menta A So omma AND bit a bit NOR R bit a bit XNOR R bit a bit Si scriva un modulo o per ogni blocco ba ase (ALU, MUX e REG) R ed un n modulo di più alto o livello (myy_MODULE) con l’isttanziazione e dei tre bllocchi base e. Si consiglia di imp plementare e la ALU con c un un nico case per quell che rigu uarda la generazion g ne dell’usc cita Y. Sii implemen ntino i 3 mo oduli base in stile alg goritmico (tranne ( eve entualmen nte il MUX, per cui sii lascia sce elta libera) e, ovviame ente, quello a più alto o livello in stile struttu urale. ED – Esercizi sulla modellazio m one Verilog g Massim mo Barbaro o Soluzione module REG(din, clk, rst, dout, zero); input clk, rst; input [15:0] din; output zero; output [15:0] dout; wire clk, rst, zero; wire [15:0] din; reg [15:0] dout; always @(posedge clk or negedge rst) if(~rst) dout=16’b0; else dout=din; assign zero=(dout==0)?1:0; endmodule module MUX(a, b, sel, out); input sel; input [15:0] a,b; output [15:0] out; wire sel; wire [15:0] a,b,out; assign out=sel?b:a; endmodule module ALU(a, b, sel, y); input [2 :0] sel ; input [15 :0] a,b ; output [15:0] y; wire [2:0] sel; wire [15:0] a,b; reg [15:0] y; always @(a or b or sel) case(sel) 3’b000: y=a; 3’b001: y=a+1; 3’b010: y=a+b; 3’b100: y=a&b; 3’b101: y=~(a|b); 3’b111: y=a~^b; default : y=16’bx ; endcase endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro module my_MODULE (A, B, RST, CLK, SEL, ZERO, Z); input CLK, RST; input [3:0] SEL; input [15:0] A, B; output ZERO; output [15:0] Z; wire CLK, RST, ZERO; wire [3:0] SEL; wire [15:0] A, B, Z,outMUX,outALU; REG i_reg(outALU,CLK,RST,Z,ZERO); MUX i_mux(B,Z,SEL[3],outMUX); ALU i_alu(A,outMUX,SEL[2 :0],outALU); endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro Esercizio 2 Scrivere un modello verilog di un registro a 16 bit con i seguenti segnali di ingresso: din: ingresso parallelo a 16 bit clk: ingresso di clock attivo sul fronte negativo rst: ingresso di reset, asincrono, attivo basso e l’uscita: dout: uscita a 16 bit Scrivere inoltre il testbench per testare il funzionamento del modulo, verificando, in particolar modo, le operazioni di reset e di scrittura. Il testbench dovrà verificare il corretto funzionamento del reset (che funzioni in modo asincrono) e che la scrittura avvenga solo in assenza di reset. Soluzione module reg16(din, clk, rst, dout); input clk, rst; input [15:0] din; output [15:0] dout; reg [15:0] dout; always @(negedge clk or negedge rst) if(~rst) dout=16’b0; else dout=din; endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro module tb_reg16; reg clk, rst; reg [15:0] din; wire [15:0] dout; // Istanziazione modulo da testare (UUT) reg16 UUT(din, clk, rst, dout); // Generazione clock (periodo 10) always #5 clk= ~clk; initial begin clk=1; // Reset inattivo rst=1; din=16’hFFFF; #5; // Dopo 5 il clock va basso ed il dato è memorizzato #3 rst=0; // Il reset è andato basso ed il registro è resettato #1 din=16’h00FF; #16; // Il clock va bassa ma il dato non viene memorizzato perché il reset è basso #1 rst=1; #20 $finish; end initial $monitor($time,,“Din=”,din,,”Clk=”,clk,,”Rst=”,rst,,”Dout=”,dout); endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro Esercizio 3 Dato il modulo verilog descritto nel riquadro successivo: a) Dire se implementa logica combinatoria o sequnziale e spiegare il perché b) Data la sequenza di ingressi indicata nel riquadro soluzione (b) tracciare la forma d’onda d’uscita (si ricordi che inizialmente il valore dei reg è sempre pari a x) module my_module (A, B, C, Z); input A, B, C; output Z; wire A, B, C; reg Z; always @(A or B) Z=(A|B)&C; endmodule a) Tipo di logica SEQUENZIALE Perché: La sensitivity list non è completa. Al variare dell’ingresso C l’always non viene attivato quindi l’uscita non viene aggiornata. Si vede infatti dalla risposta alla seconda domanda che l’uscita NON corrisponde alla funzione Z=(A or B) and C ma a qualcosa di diverso. ED – Esercizi sulla modellazione Verilog Massimo Barbaro b) Forma d’onda in uscita A B C Z t Z non è uguale a (A or B) and C Le variazioni di C sono ignorate ED – Esercizi sulla modellazione Verilog Massimo Barbaro Esercizio 4 Dato il modulo verilog descritto nel riquadro successivo: a) Dire se implementa logica combinatoria o sequenziale e spiegare il perché b) Data la sequenza di ingressi indicata nel riquadro soluzione (b) tracciare la forma d’onda d’uscita (si ricordi che inizialmente il valore dei reg è sempre pari a x) module my_module (A, B, C, Z); input A, B, C; output Z; wire A, B, C; reg Z; always @(A or B or C) if(B) Z=A&C; endmodule a) Tipo di logica Sequenziale Perché Non viene sempre assegnato un valore a Z in quanto manca il ramo else del if. In realtà il modulo rappresenta un latch il cui segnale di ENABLE è il segnale B. Con B alto il latch memorizza il valore della and fra A e C. ED – Esercizi sulla modellazione Verilog Massimo Barbaro b) Forma d’onda in uscita A B C Z t ED – Esercizi sulla modellazione Verilog Massimo Barbaro Esercizio 5 a) Si scriva il modulo verilog che implementa una ALU con 2 operandi (A, B) ed un ingresso di selezione a 3 bit (SEL). Le operazioni implementate sono: sel[2] 0 0 0 1 1 1 sel[1] 0 0 1 0 0 1 sel[0] 0 1 0 0 1 1 Operazioni ALU Operazione Y<= A+1 Y<=B+1 Y<=A+B Y<=A or B Y<= A xnor B Y<= A and B Funzione Incrementa A Incrementa B Somma OR bit a bit XNOR bit a bit AND bit a bit b) Scrivere un testbench per verificare il corretto funzionamento della ALU al variare dell’ingresso SEL a) Implementazione verilog module ALU(a, b, sel, y); input [2 :0] sel ; input [7 :0] a,b ; output [7:0] y; wire [2:0] sel; wire [7:0] a,b; reg [7:0] y; always @(a or b or sel) case(sel) 3’b000: y=a+1; 3’b001: y=b+1; 3’b010: y=a+b; 3’b100: y=a|b; 3’b101: y=~(a^b); 3’b111: y=a&b; default : y=8’bx ; endcase endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro b) Testbench module tb_ALU; wire [7:0] Y; reg [7:0] A,B; reg [2:0] SEL; // Istanziazione DUT ALU dut(A,B,SEL,Y); // Utilizzo un solo initial per verificare tutte le combinazioni di SEL, dovrei verificare // anche tutti i valori di A e B ma la cosa non è richiesta dal testo dell’esercizio // quindi inizializzerò A e B con due valori scelti a caso. // Potrei ovviamente anche utilizzare altri metodi, come un always che genera tutte // le combinazioni di SEL tramite un ciclo FOR. initial begin A=4; B=5; SEL=3’b000; #5 SEL=3’b001; #5 SEL=3’b010; #5 SEL=3’b011; #5 SEL=3’b100; #5 SEL=3’b101; #5 SEL=3’b110; #5 SEL=3’b111; #5 $finish; end // Monitor dei risultati initial $monitor( “SEL=%b A=%b B=%b => Y=%b\n“,SEL,A,B,Y); endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro Esercizio 6 Realizzare un modulo verilog che implementi un registro contatore. Il registro ha i seguenti ingressi: Ingressi Nome Numero di bit Funzione 8 Ingresso parallelo din 1 Segnale di reset, asincrono, attivo basso clear 1 Segnale di clock clk 1 Segnale di selezione dell’operazione di conteggio count 1 Segnale di selezione dell’operazione di caricamento parallelo load e le seguenti uscite: Uscite Nome Numero di bit Funzione 8 Uscita parallela (contenuto del registro contatore) dout 1 Uscita (combinatoria) pari a 1 quando il contatore è abilitato co a contare ed il suo contenuto è pari a 8’hFF (tutti 1) Il reset (clear) è attivo basso ed asincrono. In assenza di reset, ad ogni colpo di clock, se load=1 il registro memorizza il dato parallelo in ingresso (din), altrimenti se count=1 il contatore è abilitato a contare ed il suo contenuto viene incrementato di 1. L’uscita co è un’uscita combinatoria pari a 1 solo quando il contatore è abilitato a contare ed il registro contiene tutti 1. Soluzione module counter(din, clk, clear, load, count, dout, co); input clk, clear, load, count; input [7:0] din; output co; output [7:0] dout; wire clk, load, count, clear, co; wire [7:0] din; reg [7:0] dout; // Parte combinatoria assign co=(~load)&(count)&(dout==8’b11111111); // Parte sequenziale (registro) always @(posedge clk or negedge clear) if(~clear) dout=0; else if(load) dout=din; else if(count) dout=dout+1’b1; endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro Esercizio 7 Implementare la descrizione verilog di un modulo digitale costituito da due sottocircuiti: una ALU ed un registro. La ALU ha un’uscita a 8 bit (Y) ed in ingresso due operandi a 8 bit (A e B) ed un ingresso di selezione (SEL) a 3 bit che definisce le seguenti operazioni: sel[2] 0 0 0 1 1 1 sel[1] 0 0 1 0 1 1 sel[0] 0 1 0 0 0 1 Operazioni ALU Operazione Y<= A+1 Y<=A+B Y<=A-B Y<=A or B Y<= A xnor B Y<= A nand B Funzione Incrementa A Somma Differenza OR bit a bit XNOR bit a bit NAND bit a bit Il registro ha un ingresso D a 8 bit, l’ingresso di clock (CLK), un ingresso di reset (RST) sincrono attivo alto ed un uscita Q a 8 bit. Il modulo digitale da implementare è mostrato in Figura, se ne richiede una descrizione gerarchica, quindi vanno realizzati due moduli distinti per la ALU e per il registro e poi istanziati in un modulo ad più alto livello di gerarchia (denominato MY_MOD). opA MY_MOD ALU opB opSel clk rst CLK REG RST out Si richiede inoltre di scrivere un testbench che effettui la seguente sequenza di operazioni: Reset del registro e predisposizione degli operandi della ALU rispettivamente con A=8’hA0 e B=8’h22 Somma di A e B e memorizzazione Differenza di A e B e memorizzazione Or bit a bit di A e B e memorizzazione Ogni operazione è svolta in corrispondenza di un colpo di clock. ED – Esercizi sulla modellazione Verilog Massimo Barbaro Moduli module ALU(A, B, SEL, Y); input [2 :0] SEL ; input [7 :0] A,B ; output [7:0] Y; wire [2:0] SEL; wire [7:0] A,B; reg [7:0] Y; always @(A or B or SEL) case(SEL) 3’b000: Y=A+1; 3’b001: Y=A+B; 3’b010: Y=A-B; 3’b100: Y=A|B; 3’b101: Y=~(A^B); 3’b111: Y=~(A&B); default : Y=8’bx ; endcase endmodule module REG(D, CLK, RST, Q); input CLK, RST; input [7 :0] D; output [7:0] Q; wire [7:0] D; wire CLK, RST; reg [7:0] Q; always @(posedge CLK) if(RST) Q=8’b0; else Q=D ; endmodule module MY_MOD(opA, opB, sel, clk, rst, out); input clk, rst; input [7:0] opA, opB; input [2:0] sel; output [7:0] out; wire clk, rst; wire [2:0] sel; wire [7:0] opA, opB, int_Y, out; // Istanziazione ALU ALU i_alu(opA, opB, sel, int_Y); // Istanziazione registro REG i_reg(int_Y, clk, rst, out); endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro Testbench Testbench module tb_my_mod; reg clk, rst; reg [2:0] sel; reg [7:0] opA, opB; wire [7:0] out; // Istanziazione modulo MY_MOD dut(opA, opB, sel, clk, rst, out); // Generazione clock always begin clk=0; #5 clk=1; #5 clk=0; end // Sequenza operazioni initial begin rst=1; // Al primo colpo di clock ($time=5) il registro è resettato (rst=1) #7 rst=0; sel=3’b001; opA=8’hA0; opB=8’h22; // Eseguito a $time=7 // Al secondo colpo di clock ($time=15) viene effettuata la somma #10 sel=3’b010; // Questo assegnamento è eseguito a $time=17 // Al terzo clock ($time=25) viene effettuata la differenza #10 sel=3’b100; // Questo assegnamento è eseguito a $time=27 // Al quarto clock ($time=35) OR bit a bit #10 $stop; end // Monitor risultati initial $monitor(“$time,,opA,,opB,,sel,,clk,,rst,,out); endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro Esercizio 8 Scrivere il modulo verilog che implementa un priority encoder. Il priority encoder è un codificatore (blocco combinatorio) che prende in ingresso N bit e mette in uscita M=log2N bit che rappresentano la codifica binaria di quale fra i bit di ingresso è attivo (basso). Se più di un bit in ingresso è basso utilizzare una priorità crescente (i bit meno significativi hanno priorità maggiore dei bit più significativi, quindi se ad esempio il bit 2 ed il bit 5 sono entrambi bassi l’uscita è la codifica binaria di 2). Utilizzare come dimensioni N=8. Si scriva un opportuno testbench che testi tutte le possibili combinazioni di ingresso. Soluzione module pri_enc8(IN, OUT); input [7:0] IN; output [2:0] OUT; wire [7:0] IN; reg [2:0] OUT; always @(IN) casex(IN) 8’bxxxxxxx0: OUT=0; 8’bxxxxxx01: OUT=1; 8’bxxxxx011: OUT=2; 8’bxxxx0111: OUT=3; 8’bxxx01111: OUT=4; 8’bxx011111: OUT=5; 8’bx0111111: OUT=6; 8’b01111111: OUT=7; default: OUT=8’bx; endcase endmodule module tb_pri_enc8; reg [7:0] in; wire [2:0] out; integer i; pri_enc8 UUT(in, out); initial begin for(i=0; i<256;i=i+1) #5 in=i; #5 $stop; end initial $monitor($time,,in,,out); endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro Esercizio o9 Scrivere un u modulo verilog (M MY_DP) che e implementi lo schematico nellla Figura seguente. s Il modulo,, nel suo complesso c , ha gli ing gressi: opA A[15:0], op pB[15:0], o opC[7:0], s[[4:0], rst e clk e le uscite u Y[15 5:0] e resC COMP. Sccrivere un testbench che eseg gue, in seq quenza, le e seguenti operazioni o : 1) reset del registro 2) somm ma di opA= =2 e opB=5 5 e memo orizzazione e 3) xor bit a bit del co ontenuto del registro e di opB=2 20 e memo orizzazione e MUX: Multiplexer co on 2 ingresssi a 16 bit, 1 ingres sso di selezzione a sin ngolo bit (in Figura è indicato quale q dei due d ingresssi deve passare a se econda del valore de el bit di sellezione), 1 uscita ad 16 bit ALU: Uniità logico/a aritmetica con due operandi o A e B (16 6 bit) e 3 bit di sele ezione che e determina ano le operrazioni com me segue (l’operando ( o A è quello di sinistrra in Figura a): S Sel[2:0] Ope erazione 000 Tras sferimento di A in usccita 001 A+B B 011 A-B 100 xor bit b a bit 101 and bit a bit 110 nor bit a bit COMP: Un U modulo COMBINA ATORIO che c con du ue ingresssi A e B (1 16 bit) e le e uscite Y (16bit) e resCOMP r (1bit). Y è sempre uguale u al maggiore m frra A e B m mentre resC COMP è 1 se A è strrettamente maggiore di B (A è l’ingresso di d sinistra in i Figura) REG: Reg gistro a scorrimento a 16 bit co on un ingre esso di resset (rst) sin ncrono attiv vo alto, un n clock (clk) attivo sull fronte negativo ed un ingress so di shift (sh). Finch hé sh è altto, ad ognii colpo di clock, c il contenuto de el registro scorre di una u posizione verso sinistra, altrimenti a ill contenuto o del registtro viene ag ggiornato col c dato in ingresso. ED – Esercizi sulla modellazio m one Verilog g Massim mo Barbaro o Modulo MUX module MUX(A,B,sel,Y); input sel; input [15:0] A,B; output [15:0] Y; wire sel; wire [15:0] A,B; reg [15:0] Y; always @(A or B or sel) if(sel) Y=A; else Y=B; endmodule Modulo ALU module ALU(A,B,sel,Y); input [2:0] sel; input [15:0] A,B; output [15:0] Y; wire [2:0] sel; wire [15:0] A,B; reg [15:0] Y; always @(A or B or sel) case (sel) 3’b000: Y=A; 3’b001: Y=A+B; 3’b011: Y=A-B; 3’b100: Y=A^B; 3’b101: Y=A&B; 3’b110: Y=|(A|B); default: Y=16’bX; endcase endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro Modulo COMP module COMP(A,B,Y,resCOMP); input [15:0] A,B; output resCOMP; output [15:0] Y; wire [15:0] A,B; reg resCOMP; reg [15:0] Y; always @(A or B) begin Y=B; resCOMP=0; if(A>B) begin Y=A; resCOMP=1; end end endmodule Modulo REG module REG(clk,rst,sh,Din,Dout); input clk,rst,sh; input [15:0] Din; output [15:0] Dout; wire clk,rst,sh; wire [15:0] Din; reg [15:0] Dout; always @(negedge clk) if(rst) Dout=16’b0; else if(sh) Dout=Dout<<1; else Dout=Din; endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro Modulo MY_DP (top) module MY_DP(clk, rst, s, opA, opB, opC, Y, resCOMP); input clk, rst; input [4:0] s; input [15:0] opA,opB,opC; output resCOMP; output [15:0] Y; wire clk, rst, resCOMP; wire [4:0] s; wire [15:0] opA,opB,opC,Y,outMUX,outALU,ooutCOMP; MUX i_mux(opA,Y,s[3],outMUX); ALU i_alu(outMUX, outCOMP, s[2:0], outALU); COMP i_comp(opB,opC,outCOMP,resCOMP); REG i_reg(clk,rst,s[4],outALU,Y); endmodule Testbench module tb_MY_DP; reg clk, rst; reg [4:0] s; reg [15:0] A,B,C; wire resCOMP; wire [15:0] Y; // Istanziazione modulo MY_DP UUT(clk,rst,s,A,B,C,Y,resCOMP); // Generazione clock always begin clk=0; #5 clk=1; #5 clk=0; end // Stimoli initial begin $monitor($time,,clk,,rst,,s,,A,,B,,C,,Y,,resCOMP); rst=1; #12 A=2; B=5; C=0; s=5’b01001; #10 B=20; s=5’b00100; #10 $stop; end endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro Esercizio 10 Dato il modulo verilog seguente: module MY_MOD(A,B,C,Z); input A,B,C; output Z; wire A,B,C,Z; reg Z_int; always @(A or B) case ({A,B}) 2’b00: Z_int = 0; 2’b01: Z_int = 1; 2’b10: Z_int = 1; endcase assign Z = Z_int & C; endmodule a) Dire se implementa logica combinatoria o sequenziale e spiegare perché b) Completare il grafico della pagina successiva disegnando la forma d’onda Z c) Scrivere un testbench per verificare il funzionamento del modulo con gli ingressi definiti nel grafico della pagina successiva a) Tipo di logica La logica è evidentemente sequenziale perché l’always, sebbene abbia, correttamente, la sensitivity list completa (vi compaiono A e B che sono gli unici ingressi che influenzano l’always) contiene un case incompleta che non contempla tutte le combinazioni (manca A=1, B=1). Perciò, quando A=1, B=1 l’uscita Z_int non viene aggiornata e quindi non viene aggiornata neanche Z. Dunque in presenza di A=1, B=1 la porta (se C=1) mantiene il valore di uscita assunto con la combinazione precedente quindi dipende dalla sequenza degli ingressi. ED – Esercizi sulla modellazione Verilog Massimo Barbaro b) Uscita A B C A seconda del simulatore l’uscita fra 0 e 1 potrebbe anche essere pari a 0 (anzi che X) a seconda che gli assegnamenti fatti nel testbench all’istante 0 siano presi come variazioni oppure no Disegnare qua l’uscita Z Z 0 1 2 3 4 5 6 7 8 Time (nsec) ED – Esercizi sulla modellazione Verilog Massimo Barbaro c) Testbench module tb; reg A,B,C; wire Z; // Istanziazione Unit Under Test MY_MOD UUT(A,B,C,Z); initial begin // Monitor dei risultati $monitor($time,, A,B,C,,Z); A=0; B=0; C=1; #1 B=1; #1 A=1; #1 B=0; #1 A=0; #1 A=1; B=1; #1 B=0; C=0; #1 A=0; #2 $stop; end endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro Esercizio o 11 Si scriva la descrizzione verillog, in stille algoritm mico/RTL, di una rette COMBIINATORIA A chiamata display7 con c gli ingre essi e le usscite mostrate in Figu ura. Quando la rete è abilitata dal segna ale EN, pilota un display d a sette segmenti perr visualizza are quale, fra le 10 linee di ing gresso (A[9 9:0]), risultta alta. Se e più di un na linea in n ingresso risultasse r alta, sul display verrrà visualizz zato il num mero corrisspondente a quella a massima priorità do ove la priorità è defin nita dalla sequenza s 0246813579 (quindi la linea 0 ha massim ma priorità, poi viene e la linea 2, poi la 4, la 6, la 8, la a 1, la 3 e così via). Quando Q la a rete è dissabilitata (EN=0), op ppure quan ndo nessu una delle linee in ing gresso è alta, a viene e visualizza ato sul disp play un tratttino (-). La codifica del display a sette segmenti è data in fiigura: egmento de el display è acceso se s il segnale che lo p pilota è bas sso (0). E’’ Si ricorda che un se mentazione gerarchicca che se epari il mo odulo per l’identifica azione dell richiesta un’implem segnale in n ingresso attivo (pri_ _enc10) da al modulo che c pilota il display (driver7seg g). ED – Esercizi sulla modellazio m one Verilog g Massim mo Barbaro o Modulo verilog // Priority-encoder module pri_enc10(A,Z,idle); input [9:0] A; output idle; output [3:0] Z; reg idle; reg [3:0] Z; always @(A) begin idle=0; casex (A) 10'bxxxxxxxxx1: Z=4'b0000; 10'bxxxxxxx1x0: Z=4'b0010; 10'bxxxxx1x0x0: Z=4'b0100; 10'bxxx1x0x0x0: Z=4'b0110; 10'bx1x0x0x0x0: Z=4'b1000; 10'bx0x0x0x010: Z=4'b0001; 10'bx0x0x01000: Z=4'b0011; 10'bx0x0100000: Z=4'b0101; 10'bx010000000: Z=4'b0111; 10'b1000000000: Z=4'b1001; default: begin Z=4'bxxxx; idle=1; end endcase end endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro // Driver display a 7 segmenti module driver7seg(EN,A,a,b,c,d,e,f,g); input EN; input [3:0] A; output a,b,c,d,e,f,g; wire EN; wire [3:0] A; reg a,b,c,d,e,f,g; // La visualizzazione delle cifre si basa sullo schema seguente // // aaaaa a=1 (segmento spento) // f b a=0 (segmento acceso) // f b // f b // ggggg // e c // e c // e c // ddddd // // Quindi la codifica in uscita dei segnali a,b,c,d,e,f,g è: // // A=0 A=1 A=2 A=3 A=4 A=5 A=6 A=7 A=8 A=9 // // 00 11 00 00 11 00 00 00 00 00 // 0 0 1 0 1 0 1 0 0 0 0 1 0 1 1 0 0 0 0 0 // 0 0 1 0 1 0 1 0 0 0 0 1 0 1 1 0 0 0 0 0 // 11 11 00 00 00 00 00 11 00 00 // 0 0 1 0 0 1 1 0 1 0 1 0 0 0 1 0 0 0 1 0 // 0 0 1 0 0 1 1 0 1 0 1 0 0 0 1 0 0 0 1 0 // 00 11 00 00 11 00 00 11 00 00 // always @(EN or A) if(EN) case (A) 0: {a,b,c,d,e,f,g}=7'b0000001; 1: {a,b,c,d,e,f,g}=7'b1001111; 2: {a,b,c,d,e,f,g}=7'b0010010; 3: {a,b,c,d,e,f,g}=7'b0000110; 4: {a,b,c,d,e,f,g}=7'b1001100; 5: {a,b,c,d,e,f,g}=7'b0100100; 6: {a,b,c,d,e,f,g}=7'b0100000; 7: {a,b,c,d,e,f,g}=7'b0001111; 8: {a,b,c,d,e,f,g}=7'b0000000; 9: {a,b,c,d,e,f,g}=7'b0000100; default: {a,b,c,d,e,f,g}=7'bxxxxxxx; endcase else {a,b,c,d,e,f,g}=7'b1111110; endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro // Modulo DISPLAY, VERSIONE GERARCHICA module DISPLAY_hierarchy(EN,A,a,b,c,d,e,f,g); input EN; input [9:0] A; output a,b,c,d,e,f,g; wire EN,ENdriver,a,b,c,d,e,f,g,idlePRI; wire [3:0] outPRI; wire [9:0] A; // Ho scelto di visualizzare l'uscita nel // caso in cui nessun ingresso è valido con // un trattino, come nel caso in cui EN=0. // In questo modo, il driver del display deve // essere NON abilitato (ENdriver=0) quando il modulo NON è selezionato (EN=0) // OPPURE l'encoder è inattivo (idlePRI=1) assign ENdriver = ~ ( ~EN | idlePRI ); // Istanziazione priority-encoder pri_enc10 i_enc(A,outPRI,idlePRI); // Istanziazione driver 7 segmenti driver7seg i_driver(ENdriver,outPRI,a,b,c,d,e,f,g); endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro Esercizio 12 Dato il modulo verilog seguente: module MY_MOD(A,B,C,Z); input A,B,C; output Z; wire A,B,C,Z; reg Z_int; always @(A or B) case ({A,B}) 2’b00: Z_int = 0; 2’b01: Z_int = 1; 2’b10: Z_int = 1; endcase assign Z = Z_int | C; endmodule a) Dire se implementa logica combinatoria o sequenziale e spiegare perché b) Completare il grafico della pagina successiva disegnando la forma d’onda Z c) Scrivere un testbench per verificare il funzionamento del modulo con gli ingressi definiti nel grafico della pagina successiva a) Tipo di logica Logica sequenziale, infatti il case non è completo dunque esiste una combinazione di ingresso per cui non è definito un nuovo valore di Z_int che memorizza quindi il valore precedentemente assunto. Se Z_int ha comportamento sequenziale lo ha di conseguenza anche Z che è ottenuta combinatoriamente da Z_int stesso. ED – Esercizi sulla modellazione Verilog Massimo Barbaro b) Uscita A B C A seconda del simulatore l’uscita fra 0 e 1 potrebbe anche essere pari a 1 (anzi che X) a seconda che gli assegnamenti fatti nel testbench all’istante 0 siano presi come variazioni oppure no Disegnare qua l’uscita Z Z 0 1 2 3 4 5 6 7 8 Time (nsec) ED – Esercizi sulla modellazione Verilog Massimo Barbaro c) Testbench module tb; reg A,B,C; wire Z; // Istanziazione Unit Under Test MY_MOD UUT(A,B,C,Z); initial begin // Monitor dei risultati $monitor($time,, A,B,C,,Z); A=0; B=0; C=1; #1 A=0; B=0; C=1; #1 A=0; B=1; C=1; #1 A=1; B=1; C=1; #1 A=1; B=0; C=1; #1 A=0; B=0; C=1; #1 A=1; B=1; C=1; #1 A=1; B=0; C=0; #1 A=0; B=0; C=0; #1 $stop; end endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro Esercizio 13 a) Dare una descrizione verilog di un modulo MY_MOD in grado di prendere in ingresso un dato (D) a 8 bit e memorizzarlo sul fronte positivo del clock (clk) dopo averne fatto uno shift verso destra o verso sinistra a seconda del valore del segnale di ingresso dir_shift (se dir_shift è 1 lo shift è verso destra, se dir_shift è 0 verso sinistra). Un quarto ingresso pos_shift stabilisce di quante posizioni dovrà essere effettuato lo shift (il numero massimo di posizioni di shift è ovviamente pari al numero di bit del registro). Lo shift è di tipo aritmetico quindi vengono inseriti degli zeri per riempire le posizioni rimaste vuote nel caso che lo shift sia fatto a sinistra, se invece lo shift viene fatto verso destra bisogna mantenere il segno del dato in ingresso (rappresentato in complemento a 2). Infine, il modulo dovrà prevedere un ingresso di reset asincrono attivo basso in grado di azzerare il dato memorizzato. E’ preferibile una descrizione gerarchica, che separi la parte combinatoria di shift da quella sequenziale di memorizzazione in due moduli separati. b) Scrivere un testbench per verificare le seguenti operazioni (un’operazione per colpo di clock): 1) Scrittura nel registro del dato D=16 2) Scrittura nel registro di D=-24 shiftato a sinistra di 2 posizioni 3) Scrittura nel registro di D=1 shiftato a destra di 1 posizione 4) Reset del registro 5) Scrittura nel registro di D=3 shiftato a destra di 3 posizioni a) Modulo // Modulo top module MY_MOD(clk, rst, dir_shift, pos_shift, D, Q); input clk, rst, dir_shift; input [2:0] pos_shift; input [7:0] D; output [7:0] Q; wire [7:0] outshift; // Istanziazione shifter shifter I_SH(dir_shift, pos_shift, D, outshift); // Istanziazione registro reg8 I_REG(clk, rst, outshift, Q); endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro // Modulo shifter module shifter(dir_shift, pos_shift, D, out); input dir_shift; input [2:0] pos_shift; input [7:0] D; output [7:0] out; reg [7:0] out; always @(dir_shift or pos_shift or D) if(dir_shift) case(pos_shift) 0: out = D; 1: out = {1{D[7]},D[7:1]}; 2: out = {2{D[7]},D[7:2]}; 3: out = {3{D[7]},D[7:3]}; 4: out = {4{D[7]},D[7:4]}; 5: out = {5{D[7]},D[7:5]}; 6: out = {6{D[7]},D[7:6]}; 7: out = {7{D[7]},D[7]}; endcase // Non c’è bisogno del default perché ho elencato tutti i casi possibili else case(pos_shift) 0: out = D; 1: out = {D[6:0],1’b0}; 2: out = {D[5:0],2’b0}; 3: out = {D[4:0],3’b0}; 4: out = {D[3:0],4’b0}; 5: out = {D[2:0],5’b0}; 6: out = {D[1:0],6’b0}; 7: out = {D[0],7’b0}; endcase // Non c’è bisogno del default perché ho elencato tutti i casi possibili endmodule module reg8(clk, rst, D, Q); input clk, rst; input [7:0] D; output [7:0] Q; reg [7:0] Q; // Registro, reset asincrono attivo alto always @(posedge clk or posedge rst) if(rst) Q=8’b0; else Q=D; endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro b) Testbench module tb_MY_MOD; reg clk, rst, dir_shift; reg [2:0] pos_shift; reg [7:0] D; wire [7:0] Q; // Istanziazione Unit Under Test MY_MOD UUT(clk,rst, dir_shift, pos_shift, D, Q); // Generazione clock always // clk deve essere inizializzato a 0!!!!!! #5 clk=~clk; // Generazione stimoli e visualizzazione risultati initial begin // Monitor dei risultati $monitor($time,, clk,,rst,,dir_shift,,pos_shift,,D,,,,Q); clk=0; rst=0; dir_shift=0; pos_shift=0; D=16; // Aspetto il clock (arriva a 5) e memorizzo D (pos_shift=0) #6 dir_shift=0; pos_shift=2; D=-24; #5 dir_shift=1; pos_shift=1; D=1; #4 rst=1; #2 rst=0; dir_shift=1; pos_shift=3; D=3; #5 $stop; end endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro Esercizio 14 a) Scrivere il modulo verilog che implementa uno shifter (COMBINATORIO). Lo shifter ha un ingresso D a 16 bit, un ingresso dir_shift a 1 bit, un ingresso pos_shift a 2 bit. L’uscita Y è a 16 bit e rappresenta l’ingresso D spostato di un numero di posizioni pari a quello indicato da pos_shift verso destra (se dir_shift è 1) oppure verso sinistra se (dir_shift è 0). Lo shift è di tipo logico quindi vengono inseriti degli zeri per riempire le posizioni rimaste vuote. b) Scrivere il modulo verilog che implementa un registro a 16 bit con reset asincrono attivo basso e sensibile ai fronti negativi del clock c) Scrivere un modulo verilog (MY_DP) che implementi un blocco logico costituito dallo shifter e dal registro dei punti a) e b). Gli ingressi dello shifter sono ingressi del modulo, mentre l’uscita dello shifter va in ingresso al registro. d) Scrivere un testbench per verificare le seguenti operazioni (un’operazione per colpo di clock): 1) Scrittura nel registro del dato D=16 2) Scrittura nel registro di D=24 shiftato a sinistra di 2 posizioni 3) Scrittura nel registro di D=1 shiftato a destra di 1 posizione 4) Reset del registro 5) Scrittura nel registro di D=3 shiftato a destra di 3 posizioni b) Modulo REG module REG(clk, rst, Din, Dout); input clk, rst; input [15:0] Din; output [15:0] Dout; reg [15:0] Dout; // Registro con reset ASINCRONO (dunque nella sensistivity-list) attivo BASSO // sensisibile ai fronti NEGATIVI del clock always @(negedge clk or negedge rst) if(~rst) Dout = 16’b0; else Dout = Din; endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro a) Modulo SHIFTER module SHIFTER(D, dir_shift, pos_shift, Y); input dir_shift; input [1:0] pos_shift; input [15:0] D; output [15:0] Y; reg [15:0] Y; // Blocco procedurale per implementare lo shift always @(D or dir_shift or pos_shift) if(dir_shift) case(pos_shift) 0: Y = D; 1: Y = D>>1; 2: Y = D>>2; 3: Y = D>>3; endcase // Oppure, al posto del case, Y = D>>pos_shift; else case(pos_shift) 0: Y = D; 1: Y = D<<1; 2: Y = D<<2; 3: Y = D<<3; endcase // Oppure, al posto del case, Y = D<<pos_shift; endmodule c) Modulo MY_DP module MY_DP(clk, rst, Din, dir_shift, pos_shift, Dout); input clk, rst, dir_shift; input [1:0] pos_shift; input [15:0] Din; output [5:0] Dout; wire [15:0] Y; // Istanziazione moduli SHIFTER I_SHIFT(Din, dir_shift, pos_shift, Y); REG I_REG(clk, rst, Y, Dout); endmodule d) Testbench ED – Esercizi sulla modellazione Verilog Massimo Barbaro module tb_MY_DP; reg clk, rst, dir_shift; reg [1:0] pos_shift; reg [15:0] Din; wire [15.0] Dout; // -- Istanziazione UUT -MY_DP UUT(clk, rst, Din, dir_shift, pos_shift, Dout); // -- Generazione stimuli – // Clock (bisogna INIZIALIZZARLO!!!) always #5 clk = ~ clk; // Altri stimoli initial begin // Valori iniziali clk=1; // Il registro NON deve essere resettato rst=1; // Per scrivere 16 nel registro metto 16 in ingresso e faccio uno shift di 0 posizioni Din = 16; dir_shift=0; pos_shift=0; // Aspetto il colpo di clock poi mi preparo per la prossima operazione #7 D=24; pos_shift=2; // Aspetto un altro colpo poi mi preparo alla prossima operazione #10 D=1; dir_shift=1; pos_shift=1; // Aspetto un altro colpo poi mi resetto #10 rst=0; // Aspetto il colpo di clock poi mi preparo per la prossima operazione #10 D=3; pos_shift=3; // Aspetto un altro colpo poi interrompo #10 $stop; end endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro Esercizio o 15 Modellare in verilog il modulo m MIPS S_DP rappre esentato in Figura F che ha h i seguentti segnali di ingresso ed d uscita: Nome Direzione N Numero di bit Clk Input 1 RegWrite Input 1 Instr Input 32 ALUsrc Input 6 OV Output 1 Zero Output 1 DataOut Output 32 I blocchi che e compongo ono il modulo o hanno le se eguenti funzio onalità. MUX: Mutlip plexer 2x1 co on due ingressi a 32 bit ed e un bit di selezione. ALU: Unità logico/aritme etica con due e operandi (A A e B) a 32 bit b in ingresso ed un’uscitta a 32 bit (A ALU_result) il cui valore è definito da alle operazioni definite da alla tabella se eguente: ALUsel Functio on Spiegazio one 000 AND bit a bit fra gli operandi o AeB AND 001 OR bit a bit fra gli operandi A e B OR 010 Somma a dei due op perandi (A+B) Add 110 Differenz za fra i due operandi o (A-B B) Subtracct Se A<B 111 A l’uscita è composta da d tutti 0 tran nne il bit men no significativ vo che è a Set on le ess 1, se invece A>=B A tutti i bit b dell’uscita a sono 0 than Le uscite OV e zero son no alte, rispettivamente, quando q l’ope erazione della a ALU ha da ato overflow e quando il risultato dell’operazione e è pari a 0. Sign_exten nd: prende in n ingresso un n segnale di 16 bit e lo es stende in usccita su 32 bitt mantenendone il segno o (il numero è espresso in compleme ento a 2, mantenere il segno s signiffica semplice emente replicare il bit dii segno, a sin nistra) ALU_contrrol: genera gli opportuni segnali s di selezione per l’ALU in base e ad un segn nale di ingres sso a 6 bit (Instr[31:26]) ed alla tab bella seguentte: Ins str[31:26] Funzio one della AL LU desideratta 6’’b00xxxx Add 6’’b01xxxx Subtracct 6’b100000 Add 6’b100010 Subtracct 6’b100100 AND 6’b100101 OR 6’b101010 Set on lesss than Register: banco b di 32 registri attivo o sul fronte positivo del clock. Le usscite DataOu ut1 e DataO Out2, ad ognii colpo di clo ock, risultano o uguali al co ontenuto dell registro ind dirizzato rispe ettivamente dagli ingress si DataIn1 e DataIn2. Ino oltre se Write eEnable è altto, al colpo di d clock viene e memorizza ato sul registrro indirizzato o da Addresss il segnale in n ingresso su u WriteData. ED – Esercizi sulla modellazio m one Verilog g Massim mo Barbaro o Modulo MIPS_DP // Multiplexer 2x1 module MUX(sel, A, B, Y) ; input sel ; input [31 :0] A, B ; output [31 :0] Y ; // Continuous assignment per implementare logica combinatoria assign Y = (sel) ? A : B; endmodule // ALU module ALU(sel, A, B, OV, zero, Y) ; input [2:0] sel ; input [31 :0] A, B ; output OV, zero; output [31 :0] Y ; reg [31 :0] Y ; // Logica combinatoria : stile algoritmico // Utilizzo istruzioni procedurali dentro un blocco always. // Tutti gli ingressi nella sensitivity-list e l’uscita sempre assegnata always @(A or B or sel) case(sel) 3’b000: Y = A & B; 3’b001: Y = A | B; 3’b010: Y = A + B; 3’b110: Y = A - B; 3’b111: Y = (A < B) ? 32’b1 : 32’b0; default: Y = 32’bx; endcase // L’uscita zero è un semplice continuous assignment assign zero = (Y==0) ? 1 : 0 ; // Descrizione algoritmica dell'uscita OV always @(A[31] or B[31] or sel or Y[31]) case({sel,A[31],B[31],Y[31]}) 6'b010001: OV=1; 6'b010110: OV=1; 6'b110011: OV=1; 6'b110100: OV=1; default: OV=0; endcase endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro module REGFILE(clk, WriteEnable, DataIn1, DataIn2, Address, WriteData, DataOut1, DataOut2); input clk, WriteEnable; input [4:0] DataIn1, DataIn2, Address; input [31:0] WriteData; output [31:0] DataOut1, DataOut2; // Banco di registri implementato con un array di reg reg [31:0] RegFile [0:31], DataOut1, DataOut2; // Scrittura e lettura sono sincrone, sul colpo di clock always @(posedge clk) begin DataOut1 = RegFile[DataIn1]; // Metto in uscita il registro indirizzato da DataIn1 DataOut2 = RegFile[DataIn2]; // Metto in uscita il registro indirizzato da DataIn2 // Memorizzo WriteData sul registro indirizzato da Address if(WriteEnable) RegFile[Address] = WriteData; end endmodule module SignExtend(DataIn, DataOut); input [15:0] DataIn; output [31:0] DataOut; // Basta un continuous assignment con l’operatore replica e l’operatore concatenazione assign DataOut = {{16{DataIn[15]}},DataIn}; endmodule module ALUcontrol(OpCode, ALUsel); input [5:0] OpCode; output [2:0] ALUsel; reg [2:0] ALUsel; // Descrizione algoritmica di un circuito combinatorio: // richiede un always nella cui sensitivity-list compaiano // tutti gli ingressi del blocco combinatorio ed in cui // per ogni combinazione di ingresso venga assegnato un valore // all'uscita always @(OpCode) casex (OpCode) 6’b00xxxx: ALUsel = 3'b010; 6'b01xxxx: ALUsel = 3'b110; 6'b100000: ALUsel = 3'b010; 6'b100010: ALUsel = 3'b110; 6'b100100: ALUsel = 3'b000; 6'b100101: ALUsel = 3'b001; 6'b101010: ALUsel = 3'b111; default: ALUsel = 3'bxxx; endcase endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro moduleMIPS_DP(clk, RegWrite, ALUsrc, Instr, OV, zero, DataOut); input clk, RegWrite, ALUsrc; input [31:0] Instr; output OV, zero; output DataOut; wire [2:0] ALUsel; wire [31:0] RegDataOut1, RegDataOut2, outMUX, outSignExtend // Instaziazione moduli // Register file REGFILE i_REGFILE(clk, RegWrite, Instr[25:21], Instr[20:16], Instr[15:11], DataOut, RegDataOut1, RegDataOut2); // MUX MUX i_MUX(ALUsrc, outSignExtend, RegDataOut2, outMUX); // ALU ALU i_ALU(ALUsel, RegDataOut1, outMUX, OV, zero, DataOut); // SignExtend SignExtend i_SIGEXT(Instr[15:0], outSignExtend); // ALU control ALUcontrol i_ALUcontrol(Instr[31:26], ALUsel); endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro Esercizio o 16 Modellare in verilog ili modulo BOOTH_MO B OD_DP (data apath del moltiplicatore m e di Booth modificato)) rappresenta ato in Figura che ha i seg guenti segnali di ingresso o ed uscita: Direzione N Numero di bit Nome clk Input 1 rst Input 1 load Input 1 en Input 1 multiplican nd Input 16 multiplier Input 16 product Output 32 I blocchi che e compongo ono il modulo o hanno le se eguenti funzio onalità. MUX_EXT: Mutliplexer 2x1 con un ingresso i a 16 6 bit (IN1, un no a 17 (IN0, un bit di sellezione (sel) ed un’uscita a a 17 bit. Qu uando il bit dii selezione è pari a 1passsa l’ingresso o IN1 che vie ene esteso a 17 bit aggiu ungendo uno o 0 a destra (in ( posizione e meno signifficativa) men ntre quando ili bit di selezzione è 0 passsa l’ingresso o IN0 (che è già a 17 bit e non deve essere estesso). Mult_AND: Registro a 16 1 bit con ing gresso di clock (clk) attivo o sul fronte positivo, p rese et asincrono attivo basso (rst) ed ingrresso di abilittazione (en) attivo alto (il registro memorizza solo o se abilitato)). Mult_ER: Registro R a 17 7 bit con ingrresso di clocck (clk) attivo o sul fronte positivo, p rese et asincrono attivo basso o (rst) ed ingrresso di abilittazione (en) attivo alto (il registro memorizza solo o se abilitato)). Shifter: Blo occo combin natorio che esegue lo shift s del seg gnale di ingresso (a 17 7 bit) verso destra di 2 posizioni. BOOTH_SH H_ADD: un blocco com mbinatorio che c compie delle opporrtune operazzioni di shifft&add suglii operandi A e B in base ad a un segna ale di selezion ne (code) se econdo la seg guente tabella: code Operazio one 00 00 o 111 Trassferimento in uscita di A 010 o 001 A+B 110 o 101 A-B 011 A+2B ((*) 100 A-2B (**) (*) La moltiiplicazione per 2 si fa con n uno shift ve erso sinistra ACC: Regisstro a 32 bit con c ingresso o di clock (clkk) attivo sul fronte f positivvo, reset asin ncrono attivo o basso (rst),, ingresso di abilitazione (en) attivo alto a (il registtro memorizz za solo se abilitato) ed ingresso di azzeramento a o n è 1) ed il segnale di azzeramento a o è alto il re egistro deve azzerarsi (ill (clear). Se il registro è abilitato (en nza del resett, è sincrono)). segnale clear, a differen ED – Esercizi sulla modellazio m one Verilog g Massim mo Barbaro o Modulo BOOTH_MOD_DP (SCRIVERE IN STAMPATELLO ED AGGIUNGERE GLI OPPORTUNI COMMENTI AL CODICE) // Compito di ESD1 // Datapath del moltiplicatore di Booth modificato // Author: M. Barbaro // 02/03/2005 module BOOTH_MOD_DP(clk, rst, en, load, multiplicand, multiplier, product); input clk, rst, en, load; input [15:0] multiplicand, multiplier; output [15:0] product; reg [15:0] mult_and, booth_sh_add; reg [16:0] mer; reg [31:0] product; wire [16:0] mer_in, out_shift; // -- Registri – // Moltiplicando always @(posedge clk or negedge rst) if(~rst) mult_and = 16’b0; // Reset else if(load) mult_and = multiplicand; // Memorizzazione // Moltiplicatore always @(posedge clk or negedge rst) if(~rst) mer= 17’b0; // Reset else if(en) mer= mer_in; // Memorizzazione // Accumulatore always @(posedge clk or negedge rst) if(~rst) product = 32’b0; // Reset else if(en) if(clr) product = 32’b0; // Clear else product = booth_sh_add; // Memorizzazione // -- Logica – // Multiplexer assign mer_in = (load) ? {multiplier,1’b0} : out_shift ; // Shifter assign out_shift = mer >> 2; ED – Esercizi sulla modellazione Verilog Massimo Barbaro // Booth_sh_add always @ ( mult_and or product or mer[2:0] ) case (mer[2:0] ) 3’b000, 3’b111: booth_sh_add = product; 3’b010, 3’b001: booth_sh_add = product + mult_and; 3’b110, 3’b101: booth_sh_add = product - mult_and; 3’b011: booth_sh_add = product + {mult_and,0}; 3’b100: booth_sh_add = product - {mult_and,0}; // Non c’è bisogno di default perché tutti i casi sono contemplati endcase endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro Esercizio 17 a) Modellare in verilog il register file (REGFILE) di un processore MIPS. Tale modulo costituisce l’insieme di registri interni del processore ed ha i seguenti segnali di ingresso ed uscita: Nome Direzione Numero di bit clk Input 1 we Input 1 raddrA Input 5 raddrB Input 5 waddr Input 5 dataIn Input 32 dataOutA Output 32 dataOutB Output 32 Il modulo è costituito da un banco di 31 registri effettivi ed un registro fittizio (il registro 0) che non può essere scritto e che quando viene letto fornisce in uscita una parola nulla (32 bit pari a 0). Il registro 0, quindi, non è realizzato veramente come elemento di memoria ma implementato solo tramite la logica di lettura. La scrittura è SINCRONA quindi avviene sul colpo di clock: se il segnale write enable (we) è alto viene memorizzato sul registro indirizzato da waddr (quindi il registro di posizione waddr) il dato in ingresso su dataIn. La lettura, viceversa, non è sincronizzata sul clock ma sulle porte di uscita dataOutA e dataOutB viene messo il dato contenuto nel registro indirizzato da, rispettivamente, raddrA e raddrB in qualsiasi momento cambi uno qualsiasi dei segnali in ingresso b) Scrivere un testbench per la verifica del funzionamento del modulo al punto a) eseguendo, in successione, la scrittura su ciascun registro di un dato (il numero del registro stesso, ad esempio) e poi leggendo in successione i dati memorizzati prima tramite la porta dataOutA e poi tramite la dataOutB. a) Modulo REGFILE (SCRIVERE GLI OPPORTUNI COMMENTI PER LA COMPRENSIONE DEL CODICE) module REGFILE(clk,we,raddrA,raddrB,waddr,dataIn,dataOutA,dataOutB); input clk,we; input [4:0] raddrA, raddrB, waddr; input [31:0] dataIn; output [31:0] dataOutA, dataOutB; reg [31:0] mem[1:31]; // Memorizzazione always @(posedge clk) // Scrittura sincrona if(we && (waddr!=5’b0)) // Verifica se il registro è abilitato alla scrittura e non sto scrivendo il registro 0 mem[waddr] = dataIn; // Scrive dataIn alla locazione puntata da waddr // Lettura porta A always @(raddrA or mem) if(raddrA) dataOutA=mem[raddrA]; // Se l’indirizzo non è 0 mette in uscita il contenuto del registro opportuno else dataOutA=32’b0; // Altrimenti mette in uscita una parola nulla // Lettura porta B always @(raddrB or mem) if(raddrB) dataOutB=mem[raddrB]; // Se l’indirizzo non è 0 mette in uscita il contenuto del registro opportuno else dataOutB=32’b0; // Altrimenti mette in uscita una parola nulla endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro b) Testbench (SCRIVERE GLI OPPORTUNI COMMENTI PER LA COMPRENSIONE DEL CODICE) module tb_REGFILE; reg [4:0] raddrA, raddrB, waddr; reg [31:0] dataIn; reg clk, we; wire [31:0] dataOutA, dataOutB; integer K; // Istanziazione modulo da testare REGFILE DUT(clk,we,raddrA,raddrB,waddr,dataIn,dataOutA,dataOutB); // Generazione clock always #5 clk=~clk; // Bisogna però inizializzare clk in un initial !!!! // Il clock ha periodo 10 // Generazione stimoli initial begin clk=0; // Inizializzo il clock a 0 waddr=0; raddrA=0; raddrB=0; #3; // Mi disallineo dal fronte del clock in modo da presentare gli ingressi // sempre 2 unità di tempo prima del fronte stesso we=1; // Abilito alla scrittura // Scrivo in ogni registro del register file un numero che corrisponde all’indirizzo // di quel registro for(K=0;K<32;K=K+1) begin waddr=K; dataIn=K; #10; // Aspetto il colpo di clock e procedo end we=0; // Disabilito la scrittura // Leggo sulla porta A for(K=0;K<32;K=K+1) begin raddrA=K; #10; // Aspetto il colpo di clock e procedo end // Leggo sulla porta B for(K=0;K<32;K=K+1) begin raddrB=K; #10; // Aspetto il colpo di clok e procedo end end endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro Esercizio o 18 a) Modellarre in verilog il modulo Sw witch_1x4 ra appresentato o in Figura. Tale T modulo ha i seguen nti segnali dii ingresso ed d uscita: Nome Clk flit_IN out_flit_N out_flit_S out_flit_W W out_flit_E Direzione Input Input Output Output Output Output N Numero di bit 1 32 32 32 32 32 Il modulo rappresenta uno switch per applicazzioni di netw work-on-chip,, ossia il ma attone costitutivo di una a topologia di interconnessione fra blocchi b di ela aborazione. La rete è costituita dall’interconnes ssione di più ù switch. In pratica p il blo occo da mod dellare riceve e in ingress so un dato a 32 bit sull’unica porta di ingresso o (flit_IN) ed instrada talle dato su una u della 4 porte d’usc cita (out_flit_ _N(orth), S(o outh), W(estt), E(ast)) a seconda de el contenuto del d dato stessso. Il dato in ingresso (flit_IIN) ha infattii la struttura di Figura 2:: è costituito da 32 bit, i 24 bit meno o significativii contengono o l’informazio one vera e propria p da in nstradare (da ata) e ciascu uno dei 4 gru uppi di 2 bitt (dst0, dst1,, dst2 e dst3)) rappresenta a il percorso su cui deve essere instra adato il dato. Ad ogni collpo di clock, il modulo prende p il dato o in ingresso o, verifica su u quale porta a deve esse ere messo in n uscita in ba ase al codice e presente nel campo dsst0 (out_flit_N N è codificatta con 0, outt_flit_S con 1, 1 out_flit_W W con 2 e out_flit_E con 3) 3 e lo pone in uscita spo ostando i campi destinazzione verso ssinistra (ossia trasferisce e il campo dsst1 in dst0, dsst2 in dst1, dts3 d in dst2 e riempie dst3 di zeri). In n questo mod do inizialmen nte i 4 campii dst vengono riempiti co on il percorsso che dovrà à prendere il dato e po oi, ad ogni ccolpo di cloc ck, il dato sii sposterà di switch in sw witch, opportu unamente. Si faccia un’implementtazione a singolo modulo, ma si se epari opporttunamente la a parte com mbinatoria (ill riconoscime ento della po orta di uscita e lo shift) da alla parte seq quenziale (la a memorizzazzione, sul clo ock, del dato o in ingresso opportunamente shiftato o sulla porta di d uscita des siderata). scita devono o quindi ess sere presen nti 4 registri ri, uno per ogni o porta d di uscita (tu utte le porte e N.B.: In us sono registrate)l b) Scrivere un testbencch che imple ementi una re ete 3 livelli di d switch (al primo livello o c’è un unic co switch, all secondo livello i 4 switcch pilotati da quello del primo p livello, al terzo i 16 6 switch pilota ati da quelli del secondo o livello) face endo in mod do che un dato a scelta a presentato in ingresso o al primo sswitch segua a il percorso o NORD-OVE EST-OVEST in tre colpi di d clock successivi. Figura 1 Figura 2 ED – Esercizi sulla modellazio m one Verilog g Massim mo Barbaro o a) Moduli Switch_1x4 (SCRIVERE GLI OPPORTUNI COMMENTI PER LA COMPRENSIONE DEL CODICE) // Una versione del modulo che sfrutta un multiplexing degli ingressi dei registri per // scrivere solo su quello selezionato: sul registro selezionato si mette in ingresso // il dato con i campi destinazione opportunamente shiftati mentre sugli altri si mette in // in ingresso la loro stessa uscita, sovrascrivendo quindi il registro col suo stesso // contenuto module Switch_1x4(clk,flit_IN,out_flit_N,out_flit_S,out_flit_W,out_flit_W); input clk; input [31:0] flit_IN; output [31:0] out_flit_N, out_flit_S, out_flit_W, out_flit_E; reg [31:0] out_flit_N, out_flit_S, out_flit_W, out_flit_E, in_N, in_S, in_W, in_E; // Parte combinatoria always @(flit_IN or out_flit_N or out_flit_S or out_flit_W or out_flit_E) begin // Di default l’ingresso dei registri (in_N, in_S, in_W, in_E) // è posto uguale all’uscita in modo da riscrivere solo il registro interessato in_N=out_flit_N; in_S=out_flit_S; in_W=out_flit_W; in_E=out_flit_E; // Case per la scelta del registro su cui instradare il dato case(flit_IN[31:30]) 2’b00: in_N={flit_IN[29:24],2’b00,flit_IN[23:0])}; 2’b01: in_S={flit_IN[29:24],2’b00,flit_IN[23:0])}; 2’b10: in_W={flit_IN[29:24],2’b00,flit_IN[23:0])}; 2’b11: in_E={flit_IN[29:24],2’b00,flit_IN[23:0])}; endcase end // Parte sequenziale : 4 registri always @(posedge clk) begin out_flit_N=in_N; out_flit_S=in_S; out_flit_W=in_W; out_flit_E=in_E; end endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro // Una versione alternative del modulo, che utilizza registri con enable module Switch_1x4_v2(clk,flit_IN,out_flit_N,out_flit_S,out_flit_W,out_flit_W); input clk; input [31:0] flit_IN; output [31:0] out_flit_N, out_flit_S, out_flit_W, out_flit_E; reg en_reg_N, en_reg_S, en_reg_W, en_reg_E; reg [31:0] out_flit_N, out_flit_S, out_flit_W, out_flit_E, in_reg; // Parte combinatoria always @(flit_IN) begin // Di default nessuno dei registri è abilitato // e l’ingresso di tutti i registri è posto uguale al flit in ingresso con // l’opportuno shift dei campi destinazione en_reg_N=1’b0; en_reg_S=1’b0; en_reg_W=1’b0; en_reg_E=1’b0; in_reg={flit_IN[29:24],2’b00,flit_IN[23:0])}; // Case per la scelta del registro da abilitare case(flit_IN[31:30]) 2’b00: en_reg_N=1’b1; 2’b01: en_ reg_S=1’b1; 2’b10: en_ reg_W=1’b1; 2’b11: en_ reg_E=1’b1; // Uno solo dei registri è abilitato alla scrittura endcase // Da notare che i segnali di enable sono combinatori perché sono sempre comunque // assegnati e tutti gli inglessi (flit_IN) sono nella sensitività-list end // Parte sequenziale : 4 registri always @(posedge clk) begin // Scriverò solo sul registro abilitato if(en_reg_N) out_flit_N=in_N; if(en_reg_S) out_flit_S=in_S; if(en_reg_W) out_flit_W=in_W; if(en_reg_E) out_flit_E=in_E; end endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro b) Testbench // Modulo contenente tutte le istanze di switch da testare (la topologia) module topology(clk, flit_IN, f3_1_N, f3_1_S, f3_1_W, f3_1_E, f3_2_N, f3_2_S, f3_2_W, f3_2_E, f3_3_N, f3_3_S, f3_3_W, f3_3_E, f3_4_N, f3_4_S, f3_4_W, f3_4_E, f3_5_N, f3_5_S, f3_5_W, f3_5_E, f3_6_N, f3_6_S, f3_6_W, f3_6_E, f3_7_N, f3_7_S, f3_7_W, f3_7_E, f3_8_N, f3_8_S, f3_8_W, f3_8_E, f3_9_N, f3_9_S, f3_9_W, f3_9_E, f3_10_N, f3_10_S, f3_10_W, f3_10_E, f3_11_N, f3_11_S, f3_11_W, f3_11_E, f3_12_N, f3_12_S, f3_12_W, f3_12_E, f3_13_N, f3_13_S, f3_13_W, f3_13_E, f3_14_N, f3_14_S, f3_14_W, f3_14_E, f3_15_N, f3_15_S, f3_15_W, f3_15_E, f3_16_N, f3_16_S, f3_16_W, f3_16_E); input clk; input [31:0] flit_IN; output [31:0] f3_1_N, f3_1_S, f3_1_W, f3_1_E, f3_2_N, f3_2_S, f3_2_W, f3_2_E, f3_3_N, f3_3_S, f3_3_W, f3_3_E, f3_4_N, f3_4_S, f3_4_W, f3_4_E, f3_5_N, f3_5_S, f3_5_W, f3_5_E, f3_6_N, f3_6_S, f3_6_W, f3_6_E, f3_7_N, f3_7_S, f3_7_W, f3_7_E, f3_8_N, f3_8_S, f3_8_W, f3_8_E, f3_9_N, f3_9_S, f3_9_W, f3_9_E, f3_10_N, f3_10_S, f3_10_W, f3_10_E, f3_11_N, f3_11_S, f3_11_W, f3_11_E, f3_12_N, f3_12_S, f3_12_W, f3_12_E, f3_13_N, f3_13_S, f3_13_W, f3_13_E, f3_14_N, f3_14_S, f3_14_W, f3_14_E, f3_15_N, f3_15_S, f3_15_W, f3_15_E, f3_16_N, f3_16_S, f3_16_W, f3_16_E; wire [31:0] f1_1_N, f1_1_S, f1_1_W, f1_1_E, f2_1_N, f1_1_S, f2_1_W, f2_1_E, f2_2_N, f1_2_S, f2_2_W, f2_2_E, f2_3_N, f1_3_S, f2_3_W, f2_3_E, f2_4_N, f1_4_S, f2_4_W, f2_4_E; // Istanziazione primo livello Switch_1x4 SW1_1(clk, flit_IN, f1_1_N, f1_1_S, f1_1_W, f1_1_E); // Istanziazione secondo livello Switch_1x4 SW2_1(clk, f1_1_N, f2_1_N, f1_1_S, f2_1_W, f2_1_E), SW2_2(clk, f1_1_S, f2_2_N, f1_2_S, f2_2_W, f2_2_E), SW2_3(clk, f1_1_W, f2_3_N, f1_3_S, f2_3_W, f2_3_E), SW2_4(clk, f1_1_E, f2_4_N, f1_4_S, f2_4_W, f2_4_E); // Istanziazione terzo livello Switch_1x4 SW3_1(clk, f2_1_N, f3_1_N, f3_1_S, f3_1_W, f3_1_E), SW3_2(clk, f2_1_S, f3_2_N, f3_2_S, f3_2_W, f3_2_E), SW3_3(clk, f2_1_W, f3_3_N, f3_3_S, f3_3_W, f3_3_E), SW3_4(clk, f2_1_E, f3_4_N, f3_4_S, f3_4_W, f3_4_E) SW3_5(clk, f2_2_N, f3_5_N, f3_5_S, f3_5_W, f3_5_E), SW3_6(clk, f2_2_S, f3_6_N, f3_6_S, f3_6_W, f3_6_E), SW3_7(clk, f2_2_W, f3_7_N, f3_7_S, f3_7_W, f3_7_E), SW3_8(clk, f2_2_E, f3_8_N, f3_8_S, f3_8_W, f3_8_E). SW3_9(clk, f2_3_N, f3_9_N, f3_9_S, f3_9_W, f3_9_E), SW3_10(clk, f2_3_S, f3_10_N, f3_10_S, f3_10_W, f3_10_E), SW3_11(clk, f2_3_W, f3_11_N, f3_11_S, f3_11_W, f3_11_E), SW3_12(clk, f2_3_E, f3_12_N, f3_12_S, f3_12_W, f3_12_E), SW3_13(clk, f2_4_N, f3_13_N, f3_13_S, f3_13_W, f3_13_E), SW3_14(clk, f2_4_S, f3_14_N, f3_14_S, f3_14_W, f3_14_E), SW3_15(clk, f2_4_W, f3_15_N, f3_15_S, f3_15_W, f3_15_E), SW3_16(clk, f2_4_E, f3_16_N, f3_16_S, f3_16_W, f3_16_E); Endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro // Testbench vero e proprio module tb_topology; reg clk; reg [31:0] flit_IN; wire [31:0] f3_1_N, f3_1_S, f3_1_W, f3_1_E, f3_2_N, f3_2_S, f3_2_W, f3_2_E, f3_3_N, f3_3_S, f3_3_W, f3_3_E, f3_4_N, f3_4_S, f3_4_W, f3_4_E, f3_5_N, f3_5_S, f3_5_W, f3_5_E, f3_6_N, f3_6_S, f3_6_W, f3_6_E, f3_7_N, f3_7_S, f3_7_W, f3_7_E, f3_8_N, f3_8_S, f3_8_W, f3_8_E, f3_9_N, f3_9_S, f3_9_W, f3_9_E, f3_10_N, f3_10_S, f3_10_W, f3_10_E, f3_11_N, f3_11_S, f3_11_W, f3_11_E, f3_12_N, f3_12_S, f3_12_W, f3_12_E, f3_13_N, f3_13_S, f3_13_W, f3_13_E, f3_14_N, f3_14_S, f3_14_W, f3_14_E, f3_15_N, f3_15_S, f3_15_W, f3_15_E, f3_16_N, f3_16_S, f3_16_W, f3_16_E; // Istanziazione blocco topology DUT(clk,flit_IN, f3_1_N, f3_1_S, f3_1_W, f3_1_E, f3_2_N, f3_2_S, f3_2_W, f3_2_E, f3_3_N, f3_3_S, f3_3_W, f3_3_E, f3_4_N, f3_4_S, f3_4_W, f3_4_E, f3_5_N, f3_5_S, f3_5_W, f3_5_E, f3_6_N, f3_6_S, f3_6_W, f3_6_E, f3_7_N, f3_7_S, f3_7_W, f3_7_E, f3_8_N, f3_8_S, f3_8_W, f3_8_E, f3_9_N, f3_9_S, f3_9_W, f3_9_E, f3_10_N, f3_10_S, f3_10_W, f3_10_E, f3_11_N, f3_11_S, f3_11_W, f3_11_E, f3_12_N, f3_12_S, f3_12_W, f3_12_E, f3_13_N, f3_13_S, f3_13_W, f3_13_E, f3_14_N, f3_14_S, f3_14_W, f3_14_E, f3_15_N, f3_15_S, f3_15_W, f3_15_E, f3_16_N, f3_16_S, f3_16_W, f3_16_E); // Generazione clock always #5 clk=~clk; // Bisogna però inizializzare clk in un initial !!!! // Il clock ha periodo 10 // Generazione stimoli initial begin clk=0; // Inizializzo il dato in ingresso con il percorso necessario per muoversi N-W-W // la quarta destinazione la scelgo a caso tanto non c’è il corrispondente livello nella // topologia #2 flit_IN={2’b00,2’10,2’b10,2’b11,{3{8’b01100011}}); #30 $stop; // Aspetto 3 colpi di clock end ED – Esercizi sulla modellazione Verilog Massimo Barbaro Esercizio o 19 a) Modellarre in verilog il modulo selBlock s rappresentato in Figura. Ta ale modulo ha i seguen nti segnali dii ingresso ed d uscita: Direzione N Numero di bit Nome clk Input 1 enShift Input 1 dirShift Input 1 serial_In Input 1 enReg Input 1 rst Input 1 wordLine Output 64 Il modulo è costituito da d 2 sottom moduli (shiftR REG e word dREG) cha hanno h il fun nzionamento descritto dii seguito. shiftREG: si s tratta di un n registro a scorrimento (shift registe er) a 64 bit. Quando è a abilitato (enS Shift alto), ad d ogni colpo di d clock (clk)), fa scorrere e tutti i bit me emorizzati ve erso sinistra (dirShift alto o) oppure destra (dirShiftt basso) di una posizione e. Se lo scorrrimento è ve erso sinistra nella posizio one meno siignificativa viene v inserito o l’ingresso serial_In, altrimenti, se lo scorrimento è verso des stra, si inserissce in posiziione più sign nificativa uno o zero. wordREG: si tratta di un u registro a 64 bit, con ingresso di abilitazione a ( (enReg) attivvo alto e reset asincrono o (rst) attivo alto. a Si realizzi in nfine un mod dulo testbencch per testare e il funzionam mento del mo odulo top. Il ttestbench de eve: a) Ressettare il worrdREG b) Farre scorrere ve erso sinistra il contenuto dello shiftRE EG inserendo 3 bit pari a 1 consecutiivi c) Trasferire il contenuto di shiiftREG in wo ordREG d) Farre scorrere ve erso destra di d 2 posizioni lo shiftREG G e) Trasferire il contenuto di shiiftREG in wo ordREG STA UN’IMPL LEMENTAZIIONE GERAR RCHICA, CO OSTITUITA DA D 3 MODUL LI: 1 PER IL REGISTRO O E’ RICHIES A SCORRIIMENTO, UN NO PER IL L REGISTRO O NORMAL LE ED UNO O PER IL M MODULO TO OP CHE LII CONTIENE E. ED – Esercizi sulla modellazio m one Verilog g Massim mo Barbaro o a) Moduli selBlock, shiftREG e wordREG (SCRIVERE GLI OPPORTUNI COMMENTI PER LA COMPRENSIONE DEL CODICE) module shiftREG(clk,en,dir,sin,outshift); input clk,en,dir,sin; output [63:0] outshift; reg [63:0] outshift; always @(posedge clk) if(en) if(dir) outshift={outshift[62:0],sin}; else outshift=outhisft>>1; // Sul fronte del clock // se il registro è abilitato // e se lo scorrimento è a sinistra // scorro verso sinistra ed inserisco sin a destra // altrimenti // scorro a destra ed inserisco 0 a sinistra endmodule module wordREG(clk, rst, en, dataIn, dataOut); input clk, rst, en; input [63:0] dataIn; output [63:0] dataOut; reg [63:0] dataOut; always @(posedge clk or posedge rst) // Reset asincrono nella sensitivity list if(rst) // Se il reset è attivo outData=64’b0; // azzero il contenuto del registro else // altrimenti if(en) // se il registro è abilitato outData=dataIn; // memorizzo il dato in ingresso endmodule module selBlock(clk, rst, enShift, dirShift, enReg, serial_In, wordLine); input clk, rst, enShift, dirShift, enReg, serial_In; output [63:0] wordLine; reg [63:0] wordLine; wire [63:0] out_shifter; // Istanziazione shift register shiftREG i_shifter(clk,enShift,dirShift,serial_In,out_shifter); // Istanziazione registro wordREG i_reg(clk,rst,enReg,out_shifter,wordLine); endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro b) Testbench (SCRIVERE GLI OPPORTUNI COMMENTI PER LA COMPRENSIONE DEL CODICE) module tb_selBlock; reg clk,rst,enShift,dirShift,enReg,serial_In; wire [63:0] wordLine; // Istanziazione componente selBlock DUT(clk, rst, enShift, dirShift, enReg, serial_In, wordLine); // Generazione clock always #5 clk=~clk; // Bisogna però inizializzare clk in un initial !!!! // Il clock ha periodo 10 // Generazione stimoli initial begin clk=0; rst=0; enShift=0; dirShift=0; enReg=0; serial_In=0; #3 rst=1; // Reset #5 rst=0; // Reset terminato // Sono passate 8 unità di tempo, da ora in poi modificherò i segnali in ingresso // con step temporali di 10 unità di tempo in modo da presentare i segnali in ingresso // sempre PRIMA del colpo di clock per rispettare i tempi di setup enShift=1; // Abilito lo shift register serial_In=1; // Metto in ingresso degli 1 dirShift=1; // Lo shift è verso sinistra // Aspetto 3 colpi di clock (30 unità di tempo) per inserire i 3 uno richiesti #30 enShift=0; enReg=1; // Disabilito lo shift ed abilito il registro alla scrittura // Aspetto un colpo di clock (10 unità di tempo) e poi faccio gli altri due shift #10 enReg=0; enShift=1; dirShift=0; // Disabilito il registro, abilito lo shift a destra ed aspetto due colpi di clock (20 unità) #20 enShift=0; enReg=1; // Disabilito lo shift ed abilito il registro alla scrittura #10 $stop; end endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro Esercizio 20 Si modelli, in verilog, il modulo RAM_interface del sistema mostrato in Figura 1: Figura 1 Il sistema si compone di un processore, due memorie RAM ed un modulo di interfaccia (COMBINATORIO) che si incarica di convertire opportunamente i segnali di controllo del processore per adattarli al meccanismo di comunicazione delle memorie. In particolare, il processore si aspetta di comunicare con una memoria organizzata in 1024 locazioni da un byte, indirizzate tramite il bus indirizzi (AddrBus). Il bus dati bidirezionale (DataBus), però, è un bus a 32 bit. Per un accesso in lettura (RnW alto), il processore si aspetta di trovare sul bus dati, rispettivamente 4 byte (word) alla volta, 2 byte (half-word) oppure singoli byte, a seconda del valore del segnali di controllo Opcode, secondo lo schema indicato in Figura 2a (la notazione @[AddrBus] indica il dato contenuto alla locazione indirizzata da AddrBus). Per un accesso in scrittura (RnW basso), invece, non c’è differenza fra signed/unsigned e debbono comunque essere scritti in memoria, tutti i 4 byte (accesso word), i due byte meno significativi (accesso tipo half-word, signed o unsigned) oppure solo il byte meno significativo (accesso tipo byte, signed o unsigned) presenti sul bus dati. Figura 2a Figura 2b Le due memorie sono però organizzate in 256 locazioni (ciascuna) da 16 bit, dunque i byte indirizzati dal processore devono essere mappati sulle memorie secondo lo schema di Figura 2b. Il meccanismo di accesso alle memorie è simile a quello del processore, quindi per accedere in lettura RnWRAM1(2) è alto, mentre è basso per accedere in scrittura. Un segnale di controllo di 2 bit (OpcodeRAM1(2)) decide se l’accesso avviene su un’intera parola da 16 bit (OpcodeRAM1(2)=00) oppure sul byte meno significativo (OpcodeRAM1(2)=01) o più significativo (OpcodeRAM1(2)=10). Nel caso delle memorie non c’è differenza fra accesso byte signed ed unsigned, quindi il byte viene messo nella metà opportuna (più o meno significativa) del bus dati (DataBusRAM1(2)) ed il resto del bus viene riempito da zeri. Ovviamente il bus indirizzi delle memorie è AddrBusRAM1(2). Tutti i bus dati (memorie e processore) sono bidirezionali e gestiscono la bidirezionalità con il tri-state. Il modulo deve essere COMBINATORIO. ED – Esercizi sulla modellazione Verilog Massimo Barbaro Modulo RAM_interface (INSERIRE TUTTI I COMMENTI PER LA COMPRENSIONE DEL CODICE) module RAM_interface(RnW, Opcode, AddrBus, DataBus, RnWRAM1, OpcodeRAM1, AddrBusRAM1, DataBusRAM1, RnWRAM2, OpcodeRAM2, AddrBusRAM2, dataBusRAM2); // ** INTERFACCIA ** // Segnali di ingresso input RnW; input [2:0] Opcode; input [9:0] AddrBus; // Segnali di ingresso/uscita (i bus bidirezionali) inout [31:0] DataBus; inout[15:0] DataBusRAM1, DataBusRAM2; // Segnali di uscita ouput RnWRAM1, RnWRAM2; output [1:0] OpCodeRAM1, OpCodeRAM2; output [7:0] AddrBusRAM1, AddrBUSRAM2; // ** REG ** reg RnWRAM1, RnWRAM2; reg [1:0] OpcodeRAM1, OpcodeRAM2; // Questi 3 reg interni sono usati per la gestione del tri-state reg [15:0] DataBusRAM1_int, DataBusRAM2_int; reg [31:0] DataBus_int; // ** Gestione del tri-state ** // Se siamo in operazione di lettura (RnW alto) assegna il valore opportuno al DataBus // diretto verso il processore e lascia in alta impedenza i DataBusRAM1(2) in quanto // si suppone che siano le RAM stesse a dovere pilotare tali bus. // Altrimenti, se l’operazione è di scrittura (RnW basso) lascia in alta impedenza il // DataBus che proviene dal processore (per consentirgli di fissare il valore del bus) // ed impone il valore opportuno sui DataBusRAM1(2) diretti verso le RAM. assign DataBus = (RnW) ? DataBus_int : 32’bz; assign DataBusRAM1 = (RnW) ? 32’bz : DataBusRAM1_int; assign DataBusRAM2 = (RnW) ? 32’bz : DataBusRAM2_int; // I bit di indirizzo per le RAM sono gli 8 più significativi perché i byte 0,1,2,3 (multipli) // si trovano tutti allo stesso indirizzo ma in diverse porzioni della word oppure in // una diversa ram assign AddrBusRAM1=AddrBus[9:2]; assign AddrBusRAM2=AddrBus[9:2]; // Blocco always per la gestione dell’interfaccia, si occupa di generare: // 1) I segnali di controllo per le memorie (RnWRAM1(2) e OpcodeRAM1(2) // 2) I valori da propagare in uscita sui bus delle memorie in caso // di scrittura (DataBusRAM1_int e DataBusRAM2_int) // 3) Il valore da propagare verso il bus del processore in caso di lettura (DataBus_int) // Bisogna assicurarsi che tutti gli ingressi siano nella sensitivity-list e che // queste 7 uscite siano sempre assegnate ED – Esercizi sulla modellazione Verilog Massimo Barbaro always @(RnW or Opcode or AddrBus or DataBus or DataBusRAM1 or DataBusRAM2) if(RnW) // Accesso in lettura begin // Sono in lettura, assegno un valore qualsiasi a DataBusRAM1(2)_int tanto // non verranno utilizzati (ma devo assegnare comunque un valore perché si tratti // di logica combinatoria DataBusRAM1_int=16’b0; DataBusRAM2_int=16’b0; // Per la stessa ragione assegna un valore qualsiasi a OpcodeRAM1(2) OpcodeRAM1=2’b0; OpcodeRAM2=2’b0; // Metto le RAM in lettura RnWRAM1=1; RnWRAM2=1; // In base a Opcode decido come leggere case(Opcode) // Accesso per WORD 3’b000: DataBus_int = {DataBusRAM1, DataBusRAM2}; // Accesso UNSIGNED per HALF-WORD 3’b001: // Se l’indirizzo è divisibile per 4 si trova sulla RAM1 altrimenti sulla RAM2 // Si da per scontato che l’indirizzo sia correttamente allineato sulle half-word // quindi sia un multiplo di 2 e perciò AddrBus[0]=0 if (AddrBus[1]) DataBus_int = {16’b0, DataBusRAM2}; else DataBus_int = {16’b0, DataBusRAM1}; // Accesso SIGNED per HALF-WORD 3’b010: if (AddrBus[1]) DataBus_int = {{16{DataBusRAM2[15]}}, DataBusRAM2}; else DataBus_int = {{16{ DataBusRAM1[15]}}, DataBusRAM1}; // Accesso UNSIGNED per BYTE 3’b101: // A seconda dei due bit meno significativi dell’indirizzo decido come // comporre il dato da mettere sul bus del processore case (AddrBus[1:0]) 2’b00: DataBus_int = {24’b0, DataBusRAM1[15:8]}; 2’b01: DataBus_int = {24’b0, DataBusRAM1[7:0]}; 2’b10: DataBus_int = {24’b0, DataBusRAM2[15:8]}; 2’b11: DataBus_int = {24’b0, DataBusRAM2[7:0]}; endcase // Accesso SIGNED per BYTE 3’b110: case (AddrBus[1:0]) 2’b00: DataBus_int = {{24{DataBusRAM1[15]}}, DataBusRAM1[15:8]}; 2’b01: DataBus_int = {{24{DataBusRAM1[7]}}, DataBusRAM1[7:0]}; 2’b10: DataBus_int = {{24{DataBusRAM2[15]}}, DataBusRAM2[15:8]}; 2’b11: DataBus_int = {{24{DataBusRAM2[7]}}, DataBusRAM2[7:0]}; endcase ED – Esercizi sulla modellazione Verilog Massimo Barbaro // Il default è necessario per il comportamento combinatorio default: DataBus_int = 32’bx; endcase end else // Accesso in scrittura begin // Assegno un valore qualsiasi a DataBus_int che non verrà usato (sono in scrittura) // ma deve comunque essere assegnato per il comportamento combinatorio DataBus_int = 32’b0; // Tutti gli altri segnali li assegno in base a Opcode casex(Opcode) // Accesso per WORD 3’b000: begin {DataBusRAM1_int, DataBusRAM2_int} = DataBus; RnWRAM1=0; RnWRAM2=0; // RAM in scrittura OpcodeRAM1=2’b00; OpcodeRAM2=2’b00; // Scrivo tutti i 16 bit end // Accesso per HALF-WORD 3’b0xx: // Se l’indirizzo è divisibile per 4 si trova sulla RAM1 altrimenti sulla RAM2 // Si da per scontato che l’indirizzo sia correttamente allineato sulle half-word // quindi sia un multiplo di 2 e perciò AddrBus[0]=0 if (AddrBus[1]) begin DataBusRAM2_int = DataBus[15:0]; // L’altro bus viene assegnato comunque ma ad un valore qualsiasi // tanto non conta DataBusRAM1_int = 16’b0; RnWRAM1=1; RnWRAM2=0; // RAM1 in lettura e RAM2 in scrittura // La RAM2 va scritta interamente, per la RAM1 non fa differenza OpcodeRAM1=2’b00; OpcodeRAM2=2’b00; end else begin DataBusRAM1_int = DataBus[15:0]; // L’altro bus viene assegnato comunque ma ad un valore qualsiasi // tanto non conta DataBusRAM2_int = 16’b0; RnWRAM1=0; RnWRAM2=1; // RAM1 in scrittura e RAM2 in lettura // La RAM1 va scritta interamente, per la RAM2 non fa differenza OpcodeRAM1=2’b00; OpcodeRAM2=2’b00; end // Accesso per BYTE 3’b1xx: // A seconda dei due bit meno significativi dell’indirizzo decido cosa // mettere sui bus delle RAM e quali abilitare case (AddrBus[1:0]) 2’b00: begin // Sto scrivendo nel byte più significativo di RAM1 DataBusRAM1_int = {DataBus[7:0],8’b0}; ED – Esercizi sulla modellazione Verilog Massimo Barbaro // L’altro bus viene assegnato comunque (combinatorio) // tanto non conta DataBusRAM2_int = 16’b0; RnWRAM1=0; RnWRAM2=1; // RAM1: scrivi, RAM2: leggi // RAM1: scrivi byte più significativo, RAM2: don’t care OpcodeRAM1=2’b10; OpcodeRAM2=2’b00; end 2’b01: begin // Sto scrivendo nel byte meno significativo di RAM1 DataBusRAM1_int = {8’b0,DataBus[7:0]}; // L’altro bus viene assegnato comunque (combinatorio) // tanto non conta DataBusRAM2_int = 16’b0; RnWRAM1=0; RnWRAM2=1; // RAM1: scrivi, RAM2: leggi // RAM1: scrivi byte meno significativo, RAM2: don’t care OpcodeRAM1=2’b01; OpcodeRAM2=2’b00; end 2’b10: begin // Sto scrivendo nel byte più significativo di RAM2 DataBusRAM2_int = {DataBus[7:0],8’b0}; // L’altro bus viene assegnato comunque (combinatorio) // tanto non conta DataBusRAM1_int = 16’b0; RnWRAM1=1; RnWRAM2=0; // RAM1: leggi, RAM2: scrivi // RAM1: don’t care, RAM2: scrivi byte più significativo OpcodeRAM1=2’b00; OpcodeRAM2=2’b10; end 2’b11: begin // Sto scrivendo nel byte meno significativo di RAM2 DataBusRAM2_int = {8’b0,DataBus[7:0]}; // L’altro bus viene assegnato comunque (combinatorio) // tanto non conta DataBusRAM1_int = 16’b0; RnWRAM1=1; RnWRAM2=0; // RAM1: leggi, RAM2: scrivi // RAM1: don’t care, RAM2: scrivi byte più significativo OpcodeRAM1=2’b00; OpcodeRAM2=2’b01; end endcase default: begin // Tutti i segnali sono don’t care DataBusRAM1_int = 16’bx; DataBusRAM2_int=16’bx; RnWRAM1=1’bx; RnWRAM2=1’bx; OpcodeRAM1=2’bx; OpcodeRAM2=2’bx; end endcase end endmodule ED – Esercizi sulla modellazione Verilog Massimo Barbaro