Języki Opisu Sprzętu Prowadzący: dr inż. Andrzej Skoczeń Składnia Veriloga: Komórki prymitywne użytkownika Wykład 7 2017 29 listopad 2017 Zadania systemowe Obsługa plików Interfejs do innych języków Sterowanie przebiegiem czasu Proceduralne przypisania ciągłe http://www.fis.agh.edu.pl/~skoczen/hdl AGH WFiIS Informatyka Stosowana Języki Opisu Sprzętu 1
Własne komórki podstawowe primitive nazwa_udp(output reg <nazwa_wyjścia>, input <nazwy_wejść> ); initial <nazwa_wyjścia>=<wartość>; table <wiersze tablicy> endtable endprimitive dla sekwencyjnych UDP Format jednego wiersza tabeli table : dla układu kombinacyjnego: <input1> <input2>... <inputn> : <output>; dla układu sekwencyjnego: gate level UDP User Defined Primitives incjalizacja możliwa w sekwencyjnych UDP <input1> <input2>... <inputn> : <stan_bieżący> : <stan_następny>; 2
Własne komórki podstawowe Reguły tworzenia UDP: Dozwolone są tylko skalarne wejścia. Dozwolone jest tylko jedno skalarne wyjście. Jego nazwa musi być pierwsza na liście. Dla sekwencyjnych UDP wyjście dodatkowo musi być zadeklarowane jako reg. Pozycje tabeli zawierają 0, 1, x (z jest traktowane jak x). Porty inout są niedozwolone. gate level Z poziomu innych modułów traktowane są tak samo jak komórki predefiniowane. 3
Własne komórki podstawowe prinitive udp_and(output out, input a, b); //tablica stanów table //a b : out; 0 0 : 0; 0 1 : 0; 1 0 : 0; 1 1 : 1; endtable endprinitive gate level Jeśli w tabeli stanów brakuje linii np. (x 0) to na wyjściu podawany jest stan x. Dlatego specyfikacja bramki and jest w naszym przykładzie nie kompletna. Można stosować symbol? dla skrócenia notacji, który oznacza stan dowolny czyli 0 lub 1 lub x. 4
Własne komórki podstawowe prinitive udp_or(output out, input a, b); gate level //tablica stanów table //a b : out; 0 0 : 0; 1? : 1;? 1 : 1; 0 x : x; x 0 : x; endtable endprinitive 5
Sekwencyjne UDP gate level Symbol Znaczenie Opis? 0, 1, x Nie może być użyty w polu wyjściowym b 0, 1 Nie może być użyty w polu wyjściowym - Bez zmian Tylko dla sekwencyjnych UDP r (01) Narastające zbocze sygnału f (10) Opadające zbocze sygnału p (01), (0x), (x1) Narastające zbocze potencjału sygnału n (10), (1x), (x0) Opadające zbocze potencjału sygnału * (??) Dowolna zmiana sygnału 6
Sekwencyjne UDP gate level primitive dlatch ( output reg q, input d, gate, clear); initial q = 0; //initialize output table UDP czuły na poziom modelujący zatrzask D // d gate clear : q : q+?? 1 :? : 0; //clear 1 1 0 :? : 1; //latch 1 0 1 0 :? : 0; //latch 0? 0 0 :? : -; //no change endtable endprimitive primitive d_ff (output reg q, input clk, d); initial q = 0; //initialize output table UDP czuły na zbocze modelujący przerzutnik D // clk d : q : q+ r 0 :? : 0; //synchr reset r 1 :? : 1; //synchr set f? :? : -; //no change? * :? : -; //no cahnge endtable endprimitive 7
// ASYNCHRONOUS CLEAR ( Q OUTPUT UDP ). primitive U_FD_P_RB_NO (output reg Q, input D, CP, RB, NOTIFIER_REG); table Taka sama kolejność wejść // D CP RB NOTIFIER_REG : Qt : Qt+1 1 (01) 1? :? : 1; // clocked data 0 (01)?? :? : 0; 1 (?1) 1? : 1 : 1; // reducing pessimism 0 (?1)?? : 0 : 0; 1 (0?) 1? : 1 : 1; 0 (0?)?? : 0 : 0;? (?0) 1? :? : -; // ignore falling clock? (1?) 1? :? : -; // ignore falling clock?? 0? :? : 0; // asynchronous clear?? x? :? : x; // pessimism *? 1? :? : -; // ignore the edges on data?? (?1)? :? : -; // ignore the edges on clear??? * :? : x; endtable endprimitive Przerzutnik jako UDP gate level Przy dowolnej zmianie NOTIFIER_REG, czyli przy łamaniu krórejkolwiek kontroli czasowej wyjście przechodzi w stan nieokreślony niezależnie od stanów na innych wejściach. Format jednej lini tabeli table: <input1> <input2>... <inputn> : <stan_biezacy> : <stan_nastepny>; 8
Zadania systemowe Wywołuje się je w postaci: $<słowo_kluczowe> Zatrzymywanie symulacji $stop; Zawiesza symulację i wprowadza tryb interaktywny np. w celu analizy sygnałów w projekcie. Zakańczanie symulacji $finish; Kończy symulację. 9
Zadania systemowe Wyświetlanie informacji $display(p1, p2,..., pn); $write(p1, p2,..., pn); p1, p2,..., pn zmienne, wyrażenia, ciągi znaków ujęte w cudzysłów. Różnica między $display a $write polega na tym, że pierwszy na końcu ciągu znaków domyślnie wstawia koniec linii a drugi nie. Dla wyświetlenia kilku ciągów znaków w jednej linii używamy $write. Monitorowanie informacji $monitor(p1, p2,..., pn); p1, p2,..., pn zmienne, nazwy sygnałów, ciągi znaków ujęte w cudzysłów. W sposób ciągły monitoruje wartości zmiennych i sygnałów i wyświetla ich wartości w momentach zmiany choć jednego z parametrów. Zadanie to wystarczy wywołać tylko raz. Drugie wystąpienie zadania $monitor powoduje deaktywację poprzedniego. Dwa pomocnicze zadania systemowe: $monitoron; aktywacja zadania $monitor (domyślne) $monitoroff; deaktywacja zadania $monitor 10
Zadania systemowe Formatowanie ciągów znakowych: %h lub %H heksadecymalnie %d lub %D dziesiątkowo %o lub %O oktalnie %b lub %B binarnie %c lub %C znak ASCII %v lub %V moc sygnału w węźle %m lub %M nazwy hierarchiczne %s lub %S ciągi znaków (string) %t lub %T bieżący czas %f lub %F liczby rzeczywiste w sposób dziesiętny %e lub %E liczby rzeczywiste w sposób wykładniczy %g lub %G liczby rzeczywiste w sposób dziesiętny lub wykładniczy, tak aby było krócej 11
Zadania systemowe module disp; initial begin $display("\\\t%%\n\"\123"); end endmodule $display ncsim> run \ % "S module printval; reg [11:0] r1; initial begin r1 = 12 d10; $display("printing with maximum size - :%d: :%h:",r1,r1 ); $display("printing with minimum size - :%0d: :%0h:",r1,r1 ); end endmodule ncsim> run Printing with maximum size - : 10: :00a: Printing with minimum size - :10: :a: 12
Zadania systemowe $display module disp; reg [31:0] rval; pulldown (pd); initial begin rval = 32 d101; $display("rval = %h hex %d decimal",rval,rval); $display("rval = %o octal %b binary",rval,rval); $display("rval has %c ascii character value",rval); $display("pd strength value is %v",pd); $display("current scope is %m"); $display("%s is ascii value for 101",101); $display("simulation time is %t", $time); end endmodule ncsim> run rval = 00000065 hex 101 decimal rval = 00000000145 octal 00000000000000000000000001100101 binary rval has e ascii character value pd strength value is StX current scope is disp e is ascii value for 101 simulation time is 0 13
Zadania systemowe $monitor `timescale 1ns / 1ns module top; reg clock, reset; initial begin clock = 1'b0; forever #5 clock = ~clock; end initial begin reset = 1'b0; #1 reset = 1'b1; #3 reset = 1'b0; end //monitorowanie wartości czasu i sygnałów zegara i resetu initial $monitor($time, "ns Wartosci sygnałow clock = %b reset = %b", clock, reset); initial #20 $finish; endmodule 0ns Wartosci sygnałow clock = 0 reset = 0 1ns Wartosci sygnałow clock = 0 reset = 1 4ns Wartosci sygnałow clock = 0 reset = 0 5ns Wartosci sygnałow clock = 1 reset = 0 10ns Wartosci sygnałow clock = 0 reset = 0 15ns Wartosci sygnałow clock = 1 reset = 0 14
Funkcja systemowa $random Generacja liczb losowych jest konieczna dla tworzenia losowych wymuszeń w modułach testujących. Służy do tego funkcja systemowa: $random(<seed>) Zwraca ono 32-bitową losową liczbę całkowitą ze znakiem. Standard nie określa algorytmu. Parametr seed (posiew) sprawia, że różne strumienie losowe są generowane dla różnych jego wartości. Może być zadeklarowany jako: integer, reg, lub time. Przypisanie wartości do zmiennej seed musi być wykonane przed wywołaniem. $random % b reg [23:0] rand; rand = $random % 60; Daje liczby losowe z zakresu [(-b+1): (b-1)]. Generacja liczb losowych z zakresu od -59 do 59. reg [23:0] rand; rand = {$random} % 60; Nawiasy klamrowe oznaczają utworzenie modułu wylosowanej wartości co ogranicza zakres do wartości dodatnich tzn. od 0 do 59. reg serdata; serdata = {$random} % 2; Generacja losowego strumienia zer i jedynek. 15
Funkcje systemowe konwersji Składnia real real_val; integer $rtoi(real_val); reg [63:0] int_val; real $itor(int_val); real real_val; [63:0] $realtobits(real_val); real $bitstoreal(bit_val); Opis Konwersja odbywa się przez obcięcie części ułamkowej Konwersja odbywa się przez dołaczenie zerowej części ułamkowej converts from a real number to the 64-bit representation (vector) of that real number converts from the bit pattern to a real number Liczby rzeczywiste akceptowane (generowane) przez te funkcje muszą być (są) zgodne z reprezentacją liczby rzeczywistych wprowadzoną przez standard IEEE 754-1985 - Standard for Binary Floating-Point Arithmetic (ANSI) 123.45 123 123 123.0 16
Funkcja systemowa $bitstoreal Generacja rzeczywistych liczb losowych w terminach znaku sgn, wykładnika exp i mantysy man. Potrzebne jest użycie funkcji systemowej $bitstoreal. module Tb(); reg sgn; reg [10:0] exp; reg [51:0] man; real r_num; initial begin repeat(5) begin sgn = $random; exp = $random; man = $random; r_num = $bitstoreal({sgn,exp,man}); $display("r_num = %e",r_num); end end endmodule r_num = 3.649952e+193 r_num = -1.414950e-73 r_num = -3.910319e-149 r_num = -4.280878e-196 r_num = -4.327791e+273 17
Zadanie systemowe $readmemb, $readmemh Zadania do inicjowania pamięci zawartością pliku. $readmemb wczytuje zmienne binarne $readmemh wczytuje zmienne heksadecymalne module test; reg [7:0] memory [0:7]; integer i; initial begin $readmemb( init.dat, memory); for(i=0; i<8; i=i+1) $display( memory[%0d]=%b,i, memory[i]); end endmodule $readmemb( <nazwa_pliku>, <zmienna_pam>, <start_adres>, <finish_adres>); Plik init.dat : @002 11111111 01010101 00000000 10101010 @006 1111zzzz 00001111 memory[0]= xxxxxxxx memory[1]= xxxxxxxx memory[2]= 11111111 memory[3]= 01010101 memory[4]=00000000 memory[5]= 10101010 memory[6]= 1111zzzz memory[7]= 00001111 18
Zadania systemowe linii komend Składnia $test$plusargs(string) $value$plusargs(user_string, variable) Opis This system function searches the list of plusargs for the provided string This system function searches the list of plusargs for a user specified plusarg string. The string is specified in the first argument to the system function as either a string or a register which is interpreted as a string. If the string is found, the remainder of the string is converted to the type specified in the user_string and the resulting value stored in the variable provided. 19
Zadanie systemowe initial if ($test$plusargs( test01 )) $readmemh( test01.dat,stim_mem); if ($test$plusargs( test02 )) $readmemh( test02.dat,stim_mem); if ($test$plusargs( test03 )) $readmemh( test03.dat, stim_mem); if ($test$plusargs( test04 )) $readmemh( test04.dat, stim_mem); % ncsim snapshot_name +test01 & % ncsim snapshot_name +test02 & % ncsim snapshot_name +test03 & % ncsim snapshot_name +test04 & % isim snapshot_name plusargs test01 & % isim snapshot_name plusargs test02 & % isim snapshot_name plusargs test03 & % isim snapshot_name plusargs test04 & Incisive, Cadence ISim, Xilinx 20
Zadanie systemowe Synteza pamięci stałej ISim, Xilinx 21
Zadanie systemowe Synteza pamięci stałej ISim, Xilinx 22
Zadania obsługi plików Obsługa plików poprzez zadania systemowe: Otwarcie pliku: <uchwyt_pliku>=$fopen( <nazwa_pliku>,tryb); <uchwyt_pliku> - 32-bitowa wartość z MSB = 1; Deskryptory predefiniowane: STDIN STDOUT STDERR 32 h8000_000 32 h8000_001 32 h8000_002 Pisanie do pliku: $fdisplay(<uchwyt_pliku>, p1, p2,..., pn); $fmonitor(<uchwyt_pliku>, p1, p2,..., pn); p1, p2,..., pn zmienne, sygnały lub łańcuchy znakowe w cudzysłowie tak samo jak dla zwykłych zadań $display, $monitor tryb sposób otwarcia pliku: r odczyt, w zapis, a kontynuacja. Odczyt z pliku: $fgetc, $ungetc, $fgets, $fscanf, $fread Zamknięcie pliku: $fclose(<uchwyt_pliku>); 23
Zadania obsługi plików - odczyt Zadanie $fgetc $ungetc $fgets $fscanf $fread Opis Czyta jedne znak Wstawia znak c z powrotem do bufora określonego deskryptorem pliki fd Czyta jedną linię Czyta formatowane dane Czyta dane binarne 24
module str(); integer fptr, c; reg [8*12:1] nazwa_plik, buffer; initial nazwa_plik = "datafile.txt"; initial begin fptr = $fopen(nazwa_plik,"r"); if(!fptr ) $stop; $display("otwarto plik %s do czytania o deskryptorze %b", nazwa_plik, fptr); c = 1; Bufor o długosci 12 bajtów while ( c!= 0 ) begin c = $fgets(buffer, fptr); $write(" number=%0d data:%s", c, buffer); end $fclose(fptr); end endmodule Zadanie obsługi plików - odczyt Otwarto plik datafile.txt do czytania o deskryptorze 10000000000000000000000000000011 number=12 Data:abababababa number=12 Data:xxxxbbbbcccc number=1 Data: number=9 Data: ccccdddd number=12 Data:mmmmmmmmmmmm number=2 Data: number=0 Data: m m abababababa xxxxbbbbcccc ccccdddd mmmmmmmmmmmmm Incisive, Cadence Napotkano koniec pliku, więc bufor buffer nie został zaktualizowany. 25
Zadanie obsługi plików - zapis module strout(); reg [255:0] v; reg [7:0] xb; integer fptr; initial begin xb = {8{1'b1}}; v = {32{xb}}; fptr = $fopen("output_data.txt", "w"); if(!fptr) begin $display("blad!"); $stop; end $display("otwarto plik output_data.txt o deskryptorze %b", fptr); $fwrite(fptr, "Value of v is: %b", v); $fwrite(fptr, "Some string."); $fclose(fptr); end endmodule Wynik symulacji: Value of v is: 11111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111 111111111111111111111 Some string. Incisive, Cadence Otwarto plik output_data.txt o deskryptorze 10000000000000000000000000000011 26
Wielokanałowy deskryptor: służy tylko do zapisu Zadanie obsługi plików powstaje w nieobecności argumentu tryb ma MSB=0 i LSB=0 zawiera tylko jeden bit ustawiony na 1. Zapis do wielu plików równocześnie jest możliwy poprzez alternatywę deskryptorów wielokanałowych. 27
Zapis wielokanałowy module mcdtry; integer mcd1, mcd2, cluster, all; initial begin mcd1 = $fopen("plik1.dat"); if(mcd1 == 0) $display("blad otwarcia pliku!"); mcd2 = $fopen("plik2.dat"); if(mcd2 == 0) $display("blad otwarcia pliku!"); cluster = mcd1 mcd2; //uzupelnij o stdout all = cluster 1'b1; $display("mcd1\t=%b\nmcd2\t=%b\ncluster\t=%b\nall\t=%b", mcd1,mcd2,cluster,all); $fdisplay(all,"czas: %0d ns", $time); #10 $fdisplay(cluster,"xxxxxxxx", $time); forever #10 $fdisplay(mcd2, "tylko do plik2.txt"); end initial #100 $finish; endmodule 28
Zapis wielokanałowy Wyniki z symulacji kodu na poprzednim slajdzie: Incisive, Cadence Czas: 0 ns plik2.txt XXXXXXXX 10 tylko do plik2.txt tylko do plik2.txt tylko do plik2.txt tylko do plik2.txt tylko do plik2.txt tylko do plik2.txt tylko do plik2.txt tylko do plik2.txt Czas: 0 ns plik1.txt XXXXXXXX 10 ncsim> run stdout mcd1 =00000000000000000000000000000010 mcd2 =00000000000000000000000000000100 cluster =00000000000000000000000000000110 all =00000000000000000000000000000111 Czas: 0 ns Simulation complete via $finish(1) at time 100 NS + 0./mcd.v:18 initial #100 $finish; 29
Interfejsy do języków programowania Dwa sposoby dostępu do struktury danych projektu napisanego w Verilogu: Programming Language Interface PLI standard proceduralnego dostępu z poziomu języka C i mechanizmów interfejsu C-Verilog, Verilog Procedural Interface VPI - dostarczający zorientowanych obiektowo sposobów dostępu do obiektów Verilog-a z poziomu języka C, TCL - dostęp do obiektów Verilog-a z poziomu języka skryptowego. 30
Sterowanie przebiegiem czasu Jest to metoda określania chwil czasu symulacji, w których ma nastąpić wykonanie instrukcji proceduralnych. Verilog posiada trzy rodzaje sterowania przebiegiem czasu: opóźnieniowy (delay-based) - określa czas upływający od napotkania instrukcji do jej wykonania (symbol: #) zdarzeniowy (event-based) - zdarzenie polegające na zmianie wartości rejestru lub węzła wyzwala wykonanie instrukcji (symbole: @, or). Rozróżnia się sterowanie: zwykłe, z nazwą i wielokrotne czułe na poziom (level-sensitive) - wykonanie instrukcji czeka na wystąpienie określonego na sygnałach warunku (słowo kluczowe wait) Konstrukcje sterowania czasem są niesyntezowalne timing control Timing controls i timing checks to są dwie zupełnie odmienne rodziny konstrukcji Veriloga 31
Sterowanie przebiegiem czasu Opóźnieniowe Zdarzeniowe Czułe na poziom # @ wait zwykłe wewnątrz przypisań zerowe zwykłe z nazwą wielokrotne 32
Sterowanie opóźnieniowe Określa odstęp czasu między napotkaniem instrukcji, a je wykonaniem. Trzy sposoby specyfikowania: #<liczba> #<identyfikator> #<min:typ:max> użyta przez elaborator gdzie liczba określa liczbę jednostek czasu symulacji gdzie identyfikator określa parametr lub zmienną gdzie opcja linii komend decyduje, która z trzech liczb jest irun -maxdelays nazwa.v (-mindelays lub -typdelays) delay-based Trzy rodzaje: zwykłe (regular) wewnątrz przypisań (intra-assignment) zerowe (zero delay) Konstrukcja ta jest niesyntezowalna 33
Opóźnienie zwykłe Określane dla lewej strony przypisania proceduralnego. //deklaracje parametrów localparam latency = 20, delta = 2; //deklaracje zmiennych rejestrowych reg a, y, z, p, q; initial begin a = 1 b0; //bez opóźnienia #10 y = 1 b1; //opóźnienie z liczbą; przypisanie po 10 //jednostkach czasu #latency z = 1 b0; //opóźnienie z identyfikatorem o 20 jedn. #(latency+delta) p = 1 b1;//opóźnienie z wyrażeniem o 22 jedn. #y a = a + 1 b1; //opóźnienie z identyfikatorem o wartość y #(4:5:6) q = 1 b0; //min:typ:max w zależności od opcji linii komend end initial $monitor($time," a=%d y=%d z=%d p=%d q=%d",a,y,z,p,q); initial #60 $finish; regular Incisive, Cadence Wynik symulacji: irun -mindelay regular.v 0 a=0 y=x z=x p=x q=x 10 a=0 y=1 z=x p=x q=x 30 a=0 y=1 z=0 p=x q=x 52 a=0 y=1 z=0 p=1 q=x 53 a=1 y=1 z=0 p=1 q=x 57 a=1 y=1 z=0 p=1 q=0 34
Opóźnienie zwykłe Przykład popsuty tak aby y było nie zainicjowane y=x w momencie gdy służy ono do wyznaczenia opóźnienia: //deklaracje parametrów localparam latency = 20, delta = 2; //deklaracje zmiennych rejestrowych reg a, y, z, p, q; initial begin a = 1 b0; //bez opóźnienia #latency z = 1 b0; //opóźnienie z identyfikatorem o 20 jedn. #(latency+delta) p = 1 b1;//opóźnienie z wyrażeniem o 22 jedn. #y a = a + 1 b1; //opóźnienie z identyfikatorem o wartość y #(4:5:6) q = 1 b0; //min:typ:max w zależności od opcji linii komend #10 y = 1 b1; //opóźnienie z liczbą; przypisanie po 10 //jednostkach czasu end initial $monitor($time," a=%d y=%d z=%d p=%d q=%d",a,y,z,p,q); initial #60 $finish; regular Incisive, Cadence Wynik symulacji: irun -typdelay regular.v 0 a=0 y=x z=x p=x q=x 20 a=0 y=x z=0 p=x q=x 42 a=1 y=x z=0 p=1 q=x 47 a=1 y=x z=0 p=1 q=0 57 a=1 y=1 z=0 p=1 q=0 35
Opóźnienie zwykłe Przykład z zamienionym blokiem sekwencyjnym na blok równoległy: //deklaracje parametrów localparam latency = 20, delta = 2; //deklaracje zmiennych rejestrowych reg a, y, z, p, q; initial fork a = 1 b0; //bez opóźnienia #latency z = 1 b0; //opóźnienie z identyfikatorem o 20 jedn. #(latency+delta) p = 1 b1;//opóźnienie z wyrażeniem o 22 jedn. #y a = a + 1 b1; //opóźnienie z identyfikatorem o wartość y #(4:5:6) q = 1 b0; //min:typ:max w zależności od opcji linii komend #10 y = 1 b1; //opóźnienie z liczbą; przypisanie po 10 //jednostkach czasu join initial $monitor($time," a=%d y=%d z=%d p=%d q=%d",a,y,z,p,q); initial #25 $finish; regular Incisive, Cadence Wynik symulacji: irun -maxdelay regular.v 0 a=1 y=x z=x p=x q=x 6 a=1 y=x z=x p=x q=0 10 a=1 y=1 z=x p=x q=0 20 a=1 y=1 z=0 p=x q=0 22 a=1 y=1 z=0 p=1 q=0 36
Opóźnienie wewnątrz przypisań Określane dla prawej strony przypisania proceduralnego. intra-assignmet //opóźnienie wewnątrz przypisań initial begin x = 0; z = 0;... y = #5 x + z; end //metoda równoważna za pomocą opóźnienia zwykłego initial begin x = 0; z = 0; temp_xz = x + z;... #5 y = temp_xz; end Konstrukcja ta jest niesyntezowalna od razu weź x i z i dodaj je; następnie czekaj 5 jednostek czasu i dopiero wykonaj przypisanie wartość x+z w chwili bieżącej wstaw do zmiennej tymczasowej nawet jeśli x i z uległy zmianie pomiędzy chwila 0 i 5, to nie ma to wpływu na wartość y 37
Opóźnienie zerowe Jest metodą na określenie, które instrukcje spośród tych, które wykonują się w tej samej chwili czasu symulacji, mają być wykonane jako ostatnie. initial begin x = 0; y = 0; end initial begin #0 x = 1; //zerowe opóźnienie #0 y = 1; end //czyli x i y będą mieć wartości 1 Konstrukcja ta jest niesyntezowalna 38
Sterowanie zdarzeniowe event-based Zdarzenie jest zmianą wartości rejestru lub węzła. Zdarzenia mogą wyzwalać wykonanie instrukcji lub bloku instrukcji. Są trzy rodzaje sterowania zdarzeniowego: zwykłe (regular) z nazwą (named) wielokrotne (or) 39
Zwykłe sterowanie zdarzeniowe Jest określane za pomocą symbolu @, który umożliwia sterowanie wrażliwe na zbocze sygnału. regular //przypisanie q = d wykonuje się przy: @(clock) q = d; //każdej zmianie sygnału clock @(posedge clock) q = d; //narastającym zboczu sygnału clock @(negedge clock) q = d; //opadającym zboczu sygnału clock q = @(posedge clock) d; //narastającym zboczu sygnału clock //jednak obliczenie jego wartości jest wykonane natychmiast Uwagi: posedge narastające zbocze sygnału to zmiana jego wartości z do 0 1, x, z x 1 z 1 Konstrukcja ta jest niesyntezowalna negedge opadające zbocze sygnału to zmiana jego wartości z do 1 0, x, z x 0 z 0 40
Sterowanie zdarzeniowe z nazwą event received; //deklaracja zdarzenia received named W Verilogu można zadeklarować zdarzenie i potem wyzwalać i rozpoznawać jego zajście. Zdarzenie nie przechowuje danych. Deklarowane jest za pomocą słowa kluczowego event. Wyzwalane jest za pomocą symbolu ->, a rozpoznawane symbolem @. bufor danych przechowuje dane po przybyciu ostatniego pakietu danych always @(posedge clock) //wykonaj na zboczach narastających begin if (last_data_packet) ->received; jeśli to ostatni pakiet wyzwól zdarzenie received end always @(received) //oczekuj na zdarzenie received data_buf={data_pkt[0],data_pkt[1],data_pkt[2],data_pkt[3]}; jeśli zdarzenie received zostało wyzwolone to zapisz wszystkie cztery pakiety w buforze danych za pomocą operatora konkatenacji Konstrukcja ta jest niesyntezowalna 41
Sterowanie zdarzeniowe wielokrotne Umożliwia wyzwalanie zmianą jednego z wielu sygnałów lub zdarzeń rozdzielonych słowem kluczowym or lub przecinkiem,. Lista tych sygnałów lub zdarzeń jest też nazywana listą wrażliwości. Verilog-1995 //zatrzask czuły poziomem z asynchronicznym kasowaniem always @(reset or clock or d) //czekaj na zmianę tych sygnałów begin if (reset) //jeśli reset=1, q ustaw na 0 q = 1 b0; else if(clock) // jeśli clock=1, zatrzaśnij wejście q = d; end or always @(reset, clock, d) begin if (reset) q = 1 b0; else if(clock) q = d; end Verilog-2001 42
Sterowanie poziomem wait Polega na oczekiwaniu aż spełniony zostanie pewien warunek zanim instrukcja lub ich grupa zostanie wykonana. Do tego celu używa się słowa kluczowego wait. //jeśli count_enable=0 to count nie zmienia się //jeśli count_enable=1 to count jest inkrementowane co 20 jed. always wait (count_enable) #20 count = count + 1; Konstrukcja ta jest niesyntezowalna 43
Układ sekwencyjny Układ kombinacyjny Przypisania ciągłe module xx (...); wire [4:0] komb_out; wire [4:0] c; reg [4:0] a, b; assign komb_out = a (b & c); endmodule Przypisania proceduralne module xx (...); reg [4:0] komb_out; wire [4:0] c; reg [4:0] a, b; always @* komb_out = a (b & c); endmodule module xx (...); reg [4:0] seq_out; wire [4:0] c; reg [4:0] a, b; always @(posedge clk) seq_out <= a (b & c); endmodule 44
Proceduralne przypisanie ciągłe module xx (...); reg [4:0] komb_out; wire [4:0] c; reg [4:0] a, b; always @* assign komb_out = a (b & c); endmodule Taka składnia jest także poprawna ale znaczenie jest odmienne. 45
Proceduralne przypisanie ciągłe Jest to przypisanie ciągłe do: Zmiennej rejestrowej, Pozostaje ważne tylko przez czas określony jego odwołaniem, Jest nadrzędne w stosunku do zwykłego przypisania proceduralnego. W sposób ciągły przypisuje wartość do zmiennej rejestrowej z priorytetem wyższym niż zwykłe przypisanie proceduralne. Po jego odwołaniu przez deassign zmienna rejestrowa nadal utrzymuje uzyskaną wartość, aż do chwili wystąpienia zwykłego przypisania proceduralnego. assign zmienna_reg = wyrazenie;... deassign zmienna_reg; Lewa strona przypisania może być zmienną lub połączeniem zmiennych. Nie może być słowem pamięci lub tablicy i nie może być bitem lub grupą bitów wektora. 46
module assigntry(input clk, rst, set, d, output reg q); always @* if(~rst) assign q = 1'b0; else if(~set) assign q = 1'b1; else deassign q; always @(posedge clk) q <= d; endmodule Przy przejściu rst w stan niski wyjście q otrzyma stan niski. Przy przejściu set w stan niski wyjście q otrzyma stan wysoki. Jeżeli żadne z wejść set, rst nie jest w stanie niskim wyjście zostanie uwolnione i kontrolę nad nim przejmie zwykłe przypisanie proceduralne w drugim always. Komunikaty o błędach w czasie syntezy za pomocą RTL Compiler (Cadence): if(~rst) assign q = 1'b0; Error : Unsupported procedural assignment. [VLOGPT-39] [read_hdl] : Procedural assign in file 'assign.v' on line 7, column 16. : 'assign' and 'deassign' statements within a sequential statement are not supported for synthesis. Synteza jest poprawna w XST w nawigatorze ISE: Process "Synthesize - XST" completed successfully Encounter RTL Compiler, Cadence XST, Xilinx 47
module assigntry( input clk, rst, set, d, output reg q); always @(posedge clk) q <= d; always @* if(~rst) assign q = 1'b0; else if(~set) assign q = 1'b1; else deassign q; endmodule Symulacja RTL (behavioral) ISim, Xilinx 48
XST, Xilinx module assigntry (input clk, rst, d, set, output q); wire rst_inv; wire set_inv; wire VCC; X_FF #(.INIT ( 1'b0 )) q_1 (.CLK(clk),.RST(rst_inv),.I(d),.SET(set_inv),.O(q),.CE(VCC)); X_INV X_INV X_ONE endmodule ISim, Xilinx set_inv1_inv_0 (.I(set),.O(set_inv)); rst_inv1_inv_0 (.I(rst),.O(rst_inv)); NlwBlock_assigntry_VCC (.O(VCC)); Symulacja Post-Translate module tb; reg clk, rst, set, d; wire q; assigntry uut (.clk(clk),.rst(rst),.set(set),.d(d),.q(q)); wire GSR = glbl.gsr; initial begin clk = 0; forever #40 clk = ~clk; end initial begin @(negedge GSR); rst = 1'b1; set = 1'b1; d = 1'b1; #100 rst = 1'b0; #120 rst = 1'b1; #110 set = 1'b0; #110 set = 1'b1; #150 set = 1'b0; #10 rst = 1'b0; #100 rst = 1'b1; #10 set = 1'b1; #100 d = 1'b0; end initial #1000 $finish; endmodule 49
Proceduralne przypisanie ciągłe Są to konstrukcje przeznaczone do tworzenie modeli symulacyjnych i pisania modułów testowych (test-bench). Dwa rodzaje: Do zmiennej rejestrowej assign... deassign ; uważana za zły styl kodowania, Do zmiennej węzłowej lub rejestrowej force... release ; zastosowanie ograniczone do generacji wymuszeń i dubugowania. 50
Proceduralne przypisanie ciągłe force zmienna_reg_net = wyrazenie;... release zmienna_reg_net; Na zmiennych rejestrowych działa tak jak assign ale ma jeszcze wyższy priorytet. Na zmiennych węzłowych nadpisuje przypisania ciągłe i wyjścia instancji na czas określony przez wystąpienie instrukcji release. 51
`timescale 1 ns / 100 ps module force_release_tb; reg w, x, y; wire f; and and_1 (f, w, x, y); initial begin $monitor("%d ns, f=%b", $time,f); end endmodule w = 1 b1; x = 1 b0; y = 1 b1; #10 force f = w x y; #10 release f; #10 $finish; Bramka and na 10 jednostek czasu zostaje zastąpiona przez funktor LUB modelowany przypisaniem force Wynik symulacji : 0 ns, f=0 10 ns, f=1 20 ns, f=0 Incisive, Cadence 52
Zestawienie różnych przypisań Typ danych Wyjście instancji Ciągłe Proceduralne priorytet Proceduralne ciągłe assign force Węzłowe X X Rejestrowe X X 53