Programowalne układy logiczne kod kursu: ETD008270 Podstawy języka Verilog W2 2.03.2018 mgr inż. Maciej Rudek
2 Tematyka kursu wykład
Poziom abstrakcji systemów opisu sprzętu
Historia Verilog został stworzony w pierwotnej wersji rzez Phil a Moorby ego w latach 80. w firmie Gateway Design Automotion. 1984 roku dochodzi do sprzedawania oprogramowania pod nazwą Verilog jako symulator układów logicznych 1987 roku firma Synopsys wykorzystała język Verilog do specyfikacji projektu dla narzędzi syntezy. W tym samym roku VHDL zostaje zatwierdzony przez IEEE jako standard. 1989 firma Gateway została wykupiona przez Codence 1990 udostępniono Veriloga publicznie. 1995 roku Verilog uzyskał standard IEEE #1364.
Historia 2001 kolejna realizacja języka Verilog IEEE #1364-2001 Grupa Accelera tworzy dodatek do System Verilog 3.0 2004 Accelera dodaje kilka rozszerzeń do poprzedniej wersji IEEE 2005 ukazanie się standardu z wersji Verilog-2005 IEEE 1364-2005 oraz System Verilog 2005 IEEE #1800-2005 2007 dokonanie połączenia języka Verilog z System Verilog-2005 zdecydowane przez IEEE, Następstwem było rozwiązanie grupy IEEE 1364 na rzecz grupy IEEE #1800.
Przykładowa realizacja Deklaracja wejść Deklaracja sygnałów wewnętrznych module suma( input A,B,Cin, output Y, Cout); wire g1_o, g2_o, g3_o, g4_o; and g1(g1_o,a,b); xor g4(g4_o,a,b); and g2(g2_o,cin,g4_o); or g3(cout, g1_o,g2_o); xor g5(y,cin,g4_o); endmodule Opis struktury
Pojęcia podstawowe Indentyfikatory nadaje się je modułom, instancjom, zmiennym, funkcjom, itd. Znaki alfabetu (a-z, A-Z), cyfry (0-9), znak podkreślenia (_), znak dolara ($). Identyfikator musi zacząć się od znaku litery lub znaku podkreślenia odróżnia małe i wielkie litery! Znaki białe spacja, tabulator, nowa linia
Pojęcia podstawowe Komentarze wyróżniamy jednoliniowe oraz format blokowy. Podobnie jak w języku C i C++: // - komentarz jednej linii /* */ - komentarz blokowy dla wielu linii kodu
Pojęcia podstawowe Poziomy wartości każdy bit może przyjmować 4 wartości: 0 logiczne 0. FAŁSZ 1 logiczna 1. PRAWDA X wartość nieznana, nieistotna Z stan wysokiej impedancji
Reprezentacja liczbowa W celu przedstawianie liczb wykorzystuje się odpowiednią notację do ich reprezentacji: <rozmiar>`<podstawa><wartość> `b, `B podstawa binarna `d, `D podstawa dziesiętna `h, `H podstawa szesnastkowa `o, `O podstawa ósemkowa
Reprezentacja liczbowa <rozmiar>`<podstawa><wartość> 4 b1111 //4-bitowa liczba w systemie binarnym 12 habd //12-bitowa liczba w systemie szesnastkowym 8 d132 //8-bitowa liczba w systemie dziesiętnym 12 h13x //12-bitowa liczba szesnastkowa z 4 ostatnimi bitami nieokreślona -6 d3 //6-bitowa liczba ujemna 12 b1111 _ 0000 _ 1010 //podkreślenia zwiększają czytelność
Typy danych wire reprezentuje fizyczne połączenia, często nazywane są sieciami (nets), ten typ danych NIE przechowuje wartości. Jest to typ domyślny. Typy pochodne: wand, wor, tri, triand, trior, tril, tri0, trireg, supply1, supply0 np.: wand, triand funkcja jak bramki AND wor, trior funkcja jak bramki OR tri1, tri0 domyślne sygnały 1 i 0 (słabe 0 lub 1) supply1, supply0 modelują linię zasilania (zawsze 0 lub 1) trireg stosowany w modelowaniu na poziomie przełączników
Typy danych reg są wykorzystywane do reprezentacji zmiennych w języku Verilog. wire a; wire [3:0] b; // 4-bitowy wektor reg c,d; reg [15:0] e; // 16-bit zmienna reg [7:0] mem [0:127]; // pamięć o pojemności 128 słów 8-bit
Typy danych integer przechowuje wartości numeryczne ze znakiem o rozmiarze 32 bitów, real typ danych zmiennoprzecinkowej liczby rzeczywistej, o wielkości 32 bitów Do celów symulacji wykorzystuje się: time realtime Określenie zachowania otoczenia projektowego systemu cyfrowego
Łączenie elementów logicznych module suma( input A,B,Cin, output Y, Cout); module suma( input A,B,Cin, output Y, Cout); wire g1_o, g2_o, g3_o, g4_o; and g1(g1_o,a,b); and g2(g2_o,cin,g4_o); xor g4(g4_o,a,b); xor g5(y,cin,g4_o); or g3(cout, g1_o,g2_o); endmodule and g1(g1_o,a,b); g2(g2_o,cin,g4_o); xor g4(g4_o,a,b); g5(y,cin,g4_o); or g3(cout, g1_o,g2_o); endmodule
Łączenie elementów logicznych module suma( input a,b, output wand c, output d); not (c,a), (c,b); not (d,a), (d,b); endmodule a b c d 0 0 0 0 0 1 0 X 1 0 0 X 1 1 1 1 wand wire
Moduły module suma( input A,B,Cin, output Y, Cout); module suma( input A,B,Cin, output Y, Cout); and g1(g1_o,a,b); g2(g2_o,cin,g4_o); and g1(g1_o,a,b); xor g4(g4_o,a,b); g2(g2_o,cin,g4_o); g5(y,cin,g4_o); xor g4(g4_o,a,b); or g3(cout, g1_o,g2_o); g5(y,cin,g4_o); endmodule or g3(cout, g1_o,g2_o); endmodule 2
Moduły
Moduły module suma( input A,B,Cin, output Y, Cout); and g1(g1_o,a,b); g2(g2_o,cin,g4_o); xor g4(g4_o,a,b); g5(y,cin,g4_o); or g3(cout, g1_o,g2_o); endmodule
Moduły module sumator_2( input [1:0] P,Q, output [1:0] S, input CI, output CO); suma modul_1(.a(p[0]),.b(q[0]),.y(s[0]),.cout(cy0),.cin(ci)); suma modul_2(.a(p[1]),.b(q[1]),.y(s[1]),.cout(co),.cin(cy0)); module suma( input A,B,Cin, output Y, Cout); [ ] endmodule
Moduły module suma( input A,B,Cin, output Y, Cout); [ ] Połączenie terminali instancji z portami modułu poprzez nazwę Suma modul_1(.a(p[0]),.b(q[0]),.y(s[0]),.cout(cy0),.cin(ci)); Wykorzystanie notacji pozycyjnej Suma modul_1 (P[0], Q[0], CI, S[0], CY0);
Tablice instancji module suma( input [1:8] in, oe, output [1:8] out); bufif0 ( out[1], in[1],oe[1] ), ( out[2], in[2],oe[2] ), ( out[3], in[3],oe[3] ), ( out[4], in[4],oe[4] ), ( out[5], in[5],oe[5] ), ( out[6], in[6],oe[6] ), ( out[7], in[7],oe[7] ), ( out[8], in[8],oe[8] ); endmodule 8-bitowy moduł bufora trójstanowego module suma( input [1:8] in, oe, output [1:8] out); bufif0 b[1:8] (out, in, oe); endmodule
Tablice instancji module dff8( input [7:0] D, output [7:0] Q, input clk, rst); FDC d7 (.Q(Q[7]],.C(clk),.CLR(rst),.D(D[7]) ), d6 (.Q(Q[6]],.C(clk),.CLR(rst),.D(D[6]) ), d5 (.Q(Q[5]],.C(clk),.CLR(rst),.D(D[5]) ), d4 (.Q(Q[4]],.C(clk),.CLR(rst),.D(D[4]) ), d3 (.Q(Q[3]],.C(clk),.CLR(rst),.D(D[3]) ), d2 (.Q(Q[2]],.C(clk),.CLR(rst),.D(D[2]) ), d1 (.Q(Q[1]],.C(clk),.CLR(rst),.D(D[1]) ), d0 (.Q(Q[0]],.C(clk),.CLR(rst),.D(D[0]) ); endmodule FDC d[7:0] (.Q(Q),.C(clk),.CLR(rst),.D(D) );
Przypisanie ciągłe W momencie gdy nie znamy struktury kombinacyjnej układu lecz znana jest funkcja zapisana równaniem algebry Boole a możliwe jest opisanie tego układu bez znajomości układu na poszczególnych bramkach, wykorzystując następujące operatory: & operator iloczynu logicznego operator sumy logicznej ^ operacja XOR Jest to tak zwane przypisanie ciągłe (continuios assignment)
Przypisanie ciągłe module suma( input A,B,Cin, output Y, Cout); and g1(g1_o,a,b); g2(g2_o,cin,g4_o); xor g4(g4_o,a,b); g5(y,cin,g4_o); or g3(cout, g1_o,g2_o); endmodule & operator iloczynu logicznego operator sumy logicznej ^ operacja XOR module suma( input A,B,Cin, output Y, Cout); assign Y = A ^ B ^ Cin; assign Cout = (A & B) ((A ^ B) & Cin); endmodule
Przypisanie ciągłe Przypisanie ciągłe można wykorzystać: jawnie przez zastosowanie assign w tej samej linii w której deklaruje się wire module suma( input A,B,Cin, output Y, Cout); wire ab_xor = A ^ B; assign Y = A ^ B ^ Cin; assign Cout = (A & B) ( ab_xor & Cin); endmodule assign {Cout,Y} = A + B + Cin;
Parametr module suma ( input [7:0] A,B, input Cin, output [7:0] Y, output Cout); wire {Cout,Y} = A + B + Cin; endmodule module NAZWA [Lista parametrów] [lista portów] // Deklaracja i instrukcje endmodule
Parametr module suma_n #(parameter N=32) ( input [N-1:0] A,B, input Cin, output [N-1:0] Y, out Cout); assign {Cout,Y} = A + B + Cin; endmodule module minusator ( input [7:0] A,B, output [7:0] Y, output CY); wire [7:0] nb=~b; // Negacja suma_n #(8) s1(.a(a),.b(b),.y(y),.cout(cy),.cin(1 b1)); endmodule A B = A + B + 1
Parametr suma_n #(8) s1(.a(a),.b(b),.y(y),.cout(cy),.cin(1 b1)); Parametr można przypisać w oparciu o notację opartą na nazwach: suma_n #(.N(8)) s1(.a(a),.b(b),.y(y),.cout(cy),.cin(1 b1)); Lub przez rodzaj stałych symbolicznych (operator == jest odpowiedzialny za przypisanie ciągłe) parameter JO = 2 h3; assign jupii = (instr [7:6] == JO); Lub przez wykorzystanie redefinicji instrukcją defparam odnosząc się do nazwy hierarchicznej suma_n s1(.a(a),.b(b),.y(y),.cout(cy),.cin(1 b1)); defparam s1.n=8;
Verilog - operatory operand równy 0 to wartość logiczna również 0 Możliwe trzy wartości 0, 1, x 0 jeżeli relacja spełniona, 1 jeżeli relacja niespełniona Działania na poszczególnych bitach, jeżeli operandy mają różną długość, krótszy z nich uzupełniany jest od lewej zerami - bit po bicie Wykonują operacje na poszczególnych bitach jednego operatora, - wynik jednobitowy Lewy operand to wektor, prawy przesunięcie 30 Konkatencja łączenie operandów w wektor
Operatory relacji i porównania Operatory relacji: >, >=, <, <= assign Y = ( A >= B ); Operatory porównania: ==,!=, ===,!== assign Y = ( A == B ); VS assign Y = ( A === B ); A0 A1 B0 B1 Y 0 0 0 0 1 0 1 0 0 0 Z 1 0 1 1 X 1 1 0 0 A0 A1 B0 B1 Y 0 0 0 0 1 0 1 0 0 0 Z 1 0 1 0 X 1 X 1 1
Operatory bitowe Wykonywanie operacji bit po bicie (na bitach o odpowiadającej sobie wadze) Operandy Wartość wyrażenia a b a & b a b a ^ b a ~^ b 0 0 0 0 0 1 0 1 0 1 1 0 1 0 0 1 1 0 1 1 1 1 0 1 0 x X X X X X 0 X X X X X x X X X X 1 x X 1 X X X 1 x 1 x x
Operator redukcji Jest to specjalny przypadek operatorów bitowych. Ich wynik jest jednoargumentowy: AND (&), OR ( ), NAND (~&), NOR (~ ), XOR (^), XNOR (~^). Operand Wartość wyrażenia a &a a ^a 0000 0000 0 0 0 1111 1111 1 1 0 1010 1101 0 1 1 1100 11zz 0 1 x 1111 111x x 1 x
Operatory przesunięcia bitowego Przesuniecie w prawo (>>) Przesunięcie w lewo (<<) Przesunięcie ze znakiem w prawo (>>>) Przesunięcie ze znakiem w lewo (<<<) X: A: B: C: D: 0 0 1 1 0 0 0 0 0 0 1 1 1 0 0 0 0 1 1 1 0 0 0 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 0 wire [7:0] X = 8 B00110000; wire [7:0] A = X>>>1; wire [7:0] B = X<<<1; wire [7:0] C = X>>1; wire [7:0] D = X<<1;
Operator sklejania (konkatenacji) Wykonuje operację złączenia bitów lub wektorów w celu uformowania wektora o większej liczbie bitów. Wykonuje się to z zastosowaniem nawiasów klamrowych { } : {wyr1, wyr2,, wyr_n} Operator replikacji wykorzystuje dwa nawiasy klamrowe {{ }} : {liczba{wyr1, wyr2,, wyr_n}}
Operator sklejania (konkatenacji) wire [3:0] a,b; wire [7:0] c,d; wire [11:0] e,f; assign c = {a,b}; assign e = {b,a,b}; assign f = { 3{ a }}; assign b = { 4{ e==f }}; assign f = {a,d}; assign e = { 2{1'b1, a, 1'b0 }}; assign {a,b} = d; assign {q,b,f} = { e,d }+1; Inicjalizacja typów wire Sklejanie po prawej stronie przypisania Sklejanie po lewej stronie przypisania
Operator sklejania (konkatenacji) wire [3:0] a,b; wire [7:0] c,d; wire [11:0] e,f; assign f = { 3{ a }}; assign b = { 4{ e==f }}; assign f = {a,a,a}; assign b = {(e==f), (e==f), (e==f), (e==f)};
Operator sklejania (konkatenacji) wire [3:0] a,b; wire [7:0] c,d; wire [11:0] e,f; assign e = { 2{1'b1, a, 1'b0 }}; assign {a,b} = d; assign {q,b,f} = { e,d }+1; assign e = 1 a 3 a 2 a 1 a 0 0 1 a 3 a 2 a 1 a 0 0 {1'b1, a, 1'b0} {1'b1, a, 1'b0}
Priorytety operatorów Operator opis Operator (cd.) opis (cd.) [ ] Selekcja bitu << >> <<< >>> Przesunięcie bit. ( ) Nawias okrągły > >= < <= Operacja relacji! ~ Negacja logiczna ==!= ===!=== Porównanie & ~& ~ ^ ~^ ^~ Redukcja & AND bitowy + - Zmiana znaku ^ ^~ ~^ XOR, XNOR bit. { } Sklejanie OR bitowy ** Potęgowanie && AND logiczny l* / % Arytmetyka OR logiczny + - Arytmetyk (2-arg) l?: Warunek
Dziękuję za uwagę :)