background image

 

Laboratorium Podstaw Techniki Cyfrowej 

Ćwiczenie 5: Wprowadzenie do języków opisu sprzętu 

 

 

1. Języki opisu sprzętu 

Języki opisu sprzętu(HDL – Hardware Description Language) to języki słuŜące do opisu ukła-
dów cyfrowych. Ich historia sięga lat pięćdziesiątych, jednakŜe pierwsze praktyczne implemen-
tacje powstały w latach siedemdziesiątych. 
 
 
 

2. Języki HDL – wstęp do języka VERILOG 

2.1. Stałe liczbowe 

Stałe liczbowe w języku VERILOG zapisywane są w następującej postaci: 
 

 

[ [<rozmiar>]

 

[<podstawa>] ] <wartość> 

Zarówno rozmiar jak i podstawa są opcjonalne, niemniej jednak rozmiar nie moŜe występować 
bez podstawy. Rozmiar jest liczbą dziesiętną, która określa na ilu bitach ma zostać zapisana licz-
ba, natomiast podstawa jest stałą określającą podstawę liczby. MoŜe ona przyjmować następują-
ce wartości: 

•  ’d – liczba dziesiętna (domyślnie), 
•  ’h – liczba szesnastkowa, 
•  ’o – liczba ósemkowa, 
•  ’b – liczba binarna. 

2.2. Komentarze 

W VERILOGu występują podobnie jak w języku C dwa sposoby komentowania kodu. 
Pierwszym z nich są dwa ukośniki (

//

) słuŜące do komentowania pojedynczych linii kodu. Dru-

gim dokładnie tak samo jak w języku C są: 

•  ciąg znaków 

/* 

- określa początek komentarza, 

•  ciąg znaków 

*/ 

- określa koniec komentarza. 

Wszystko co jest pomiędzy tymi dwoma ciągami znaków nie jest brane pod uwagę podczas syn-
tezy układu cyfrowego. Przykład wykorzystania pokazany został na kolejnym listingu. 
 

// To jest komentarz w pojedynczej linii 
/* Pierwsza linijka komentarza wielolinijkowego 
   Druga linijka komentarza wielolinijkowego 
   Trzecia linijka komentarza wielolinijkowego 
*/ 

 

2.3. Obiekty 

VERILOG w odróŜnieniu od klasycznych języków programowania proceduralnego takich jak 
Pascal czy C posiada zamiast zmiennych obiekty. NajwaŜniejszymi z nich są: 

background image

•  reg – (rejestr) obiekt pamiętający swoją wartość do momentu wpisania kolejnej wartości, 
•  net – (sieć) obiekt stanowiący połączenie pomiędzy dwoma blokami, nie posiada pamię-

ci, musi być ciągle wysterowywany, 

•  integer – liczba całkowita której rozmiar jest zwykle determinowany przez rozmiar słowa 

na maszynie na której kod jest symulowany, 

•  real – liczba rzeczywista, zwykle podwójnej precyzji (64 bit), 
•  time – obiekt przeznaczony do przechowywania czasu symulacji. 

 
Istnieje wiele rodzajów obiektów typu net. Niektóre z nich to: 

•  wire – zwykła sieć do której moŜna dołączyć tylko jeden sterownik, 
•  wor – wyjścia sterowników są połączone do sieci poprzez wielowejściową bramkę OR, 
•  wand – wyjścia sterowników są połączone do sieci poprzez wielowejściową bramkę 

AND (modeluje otwarty kolektor), 

•  wand – wyjścia sterowników połączonych  
•  tri – sieć trzystanowa, moŜna do niej dołączyć więcej niŜ jeden sterownik, 
•  tri0 – sieć trzystanowa, podciągana do zera logicznego gdy źródła sterujące są w stanie 

wysokiej impedancji, 

•  tri1 – sieć trzystanowa, podciągana do jedynki logicznej gdy źródła sterujące są w stanie 

wysokiej impedancji, 

•  trireg – sieć trzystanowa, zachowuje poprzednią wartość gdy źródła sterujące są w stanie 

wysokiej impedancji. 

 

2.4. Deklaracja obiektów i wektorów obiektów 

Obiekty w języku VERILOG moŜna deklarować w sposób skalarny i wektorowy. Oba przypadki 
nie róŜnią się znacznie od deklarowania zmiennych w języku C. 

2.4.1. Deklaracja obiektów skalarnych 

reg 

<obiekt1, obiekt2, obiekt3,..., obiektN>

wire 

<obiekt1, obiekt2, obiekt3,..., obiektN>

2.4.2. Deklaracja obiektów wektorowych 

reg [ 

val1

 : 

val2

 ] 

<obiekt1, obiekt2, obiekt3,..., obiektN>

wire [ 

val1

 : 

val2

 ] 

<obiekt1, obiekt2, obiekt3,..., obiektN>

 
wire [ 

7

 : 

<obiekt1, obiekt2, obiekt3,..., obiektN>

wire [ 

0

 : 

<obiekt1, obiekt2, obiekt3,..., obiektN>

 
wire

 

7

 : 

data; 

wire

 

15

 : 

addr;

 

 

NajwaŜniejszą rzeczą na jaką naleŜy zwrócić uwagę jest fakt, Ŝe val1 moŜe być większe 
lub mniejsze od val2. Jest to najzwyczajniej modelowanie sposobu zapisu. NaleŜy pamiętać 
aby w całym kodzie stosować tą samą notację zapisu.  Niemniej jednak notacją, która się 
przyjęła jest zapis dla którego val1 > val2. 

background image

2.5. Operatory stosowane w języku VERILOG 

W niniejszej tablicy zestawiono operatory wykorzystywane w języku VERILOG w kolejności ro-
snącego priorytetu operacji. PoniewaŜ w tym miejscu jest jeszcze zbyt wcześnie by podawać 
przykłady działania tych operatorów, zostaną one podane w dalszej części tej instrukcji. 
 
 

Symbol operatora 

Opis 

?: 

operator warunkowy 

|| 

suma logiczna 

&& 

iloczyn logiczny 

bitowe or 

~| 

bitowe nor 

bitowe xor 

^~ 

bitowe xnor 

~^ 

bitowe xnor 

bitowe and 

~& 

bitowe nand 

== 

relacja równości 

!= 

relacja nierówności 

relacja - większy 

relacja - mniejszy 

>= 

relacja - większy bądź równy 

<= 

relacja - mniejszy bądź równy 

>> 

przesunięcie bitowe w prawo 

<< 

przesunięcie bitowe w lewo 

dodawanie 

odejmowanie 

mnoŜenie 

dzielenie 

modulo 

 

2.6. Instrukcje sterujące języka VERILOG 

PoniewaŜ VERILOG jest językiem opisu sprzętu naleŜy się bardzo ostroŜnie posługiwać instruk-
cjami sterującymi. Przy implementacji modułów w sprzęcie praktycznie wykorzystywane są tyl-
ko dwa typy instrukcji sterujących. Do pierwszego z nich naleŜą instrukcje wykonywania wa-
runkowego if-else. Sposób wykorzystania instrukcji ilustruje następujący przykład: 

 

if

 

(

 enable 

==

 1

’b

)

 

begin

 

=

 x

;

 

ny 

=

 

!

x

;

 

end else begin 

=

 0

;

 

ny 

=

 1

;

 

end 

 

Drugim typem instrukcji sterującej jest instrukcja case. Działa ona podobnie jak instrukcja swi-
tch w języku C. Ilustruje to kolejny przykład: 

 

background image

case

 

(

 input 

)

 

0

 : 

output

 = 

7

1

 : 

output

 = 

2

2

 : 

output

 = 

8

3

 : 

output

 = 

9

default

 

output 

=

 0

;

 

endcase

 

 
Jeśli obiekt input przyjmuje wartości 0, 1, 2, 3, to obiekt output przyjmuje odpowiednio wartości 
7, 2, 8, 9. We wszystkich innych przypadkach obiekt output przyjmuje wartość 0. 
Kolejne trzy instrukcje sterujące nie posiadają właściwie Ŝadnego zastosowania przy implemen-
tacjach sprzętowych, natomiast wykorzystuje się je przy implementacji środowisk testowych. 
Wszystkie są instrukcjami pętli. Pierwszą z nich jest instrukcja while. Jest ona analogiczna do in-
strukcji while w języku C. Dopóki oiekt ma wartość logiczną jeden (wartość większa od zera) 
zawartość pętli jest wykonywana. Ilustruje to następujący przykład: 
 

counter

 = 

10

#

10

while(

 counter 

)

 

begin

 

counter

 = 

counter

 - 

1

=

 

~

y; 

$display( “

counter = %d, y = %b

,

 

counter, y

 ); 

#

10

end

 

 
Wynik działania wygląda następująco: 

# counter =  9, y = 1 
# counter =  8, y = 0 
# counter =  7, y = 1 
# counter =  6, y = 0 
# counter =  5, y = 1 
# counter =  4, y = 0 
# counter =  3, y = 1 
# counter =  2, y = 0 
# counter =  1, y = 1 
# counter =  0, y = 0

 

Instrukcja 

#

10

;

 oznacza opóźnienie o 10 jednostek czasowych. Jest to typowe zastosowanie przy 

symulacji układów cyfrowych. 

Kolejna instrukcja sterująca to pętla for. Jest ona praktycznie identyczna jak w języku C, 

poza faktem, Ŝe VERILOG nie posiada operatorów 

++

 i 

--

. Wykorzystanie tej instrukcji zostało 

pokazane w kolejnym przykładzie: 
 

for(

 i 

=

 0

;

 i 

<

 10

;

 i 

=

 i 

+

 1 

)

 

begin

 

$display( “

i = %b

,

 

i

 ); 

#

10

end

 

 
Wynik wygląda następująco: 

# i = 0000 
# i = 0001 
# i = 0010 
# i = 0011 
# i = 0100 
# i = 0101 
# i = 0110 

background image

# i = 0111 
# i = 1000 
# i = 1001

 

 
Ostatnią z instrukcji sterujących jest pętla repeat. Ciało tej pętli jest wykonywane tyle razy ile 
podano w argumencie. Ilustruje to następujący snippet kodu: 
 

i

 = 

0

#

10

repeat (

 5 

)

 

begin

 

$display( “

i = %d

,

 

i

 ); 

+

 1

#

10

end

 

 
Wynik symulacji tego kodu wygląda następująco: 

# i = 0 
# i = 1 
# i = 2 
# i = 3 
# i = 4 

 

WAśNE !!!! 
Jeśli przy opisie za pomocą instrukcji if-else lub case nie zostaną zdefiniowane wszystkie kom-
binacje (przy if brakuje else, a przy case brakuje default) narzędzie syntezujące stworzy zatrzask. 

2.7. Bloki proceduralne i przypisania 

 
W języku VERILOG wszystkie instrukcje są grupowane w blokach: 

•  assign, 
•  initial, 
•  always, 

przy czym bloki initial i always są nazywane blokami proceduralnymi. 
 

Blok assign słuŜy do modelowania logiki kombinatorycznej uŜywającej obiektów typu wi-

re jako wyjście czyli takich, które potrzebują ciągłego wysterowania. Blok ten wykonywany jest 
asynchronicznie, równolegle z wszystkimi innymi blokami, dlatego teŜ nazywany jest czasami 
przypisanie ciągłe. Jego wykorzystanie ilustruje kolejny przykład: 
 

wire 

out

assign

 out

 = 

(enable) 

?

 data : 1

'b

z

 

Jest to implementacja bufora trzystanowego. Jeśli obiekt enable ma wartość logiczną 1, to war-
tość obiektu data przekazywana jest do obiektu out. W przeciwnym przypadku obiekt out usta-
wiany jest w stan wysokiej impedancji. 

Kolejnym z bloków jest blok initial który jest wykorzystywany tylko podczas symulacji, 

w tzw. środowiskach testowych (nazywanych w języku angielskim testbench). Zawartość tego 
bloku wykonywana jest tylko raz, na początku symulacji. Przykładowa implementacja takiego 
bloku przedstawiona została w kolejnym listingu: 
 

reg

 x1, x2, sw

;

 

background image

wire

 y

;

 

   

initial begin 

x1 

=

 0

;

 

x2 

=

 1

;

 

sw 

=

 0

;

 

#

10

;

 

$display(

 

"

x1: %b, x2: %b, sw: %b, y: %b

"

, x1, x2, sw, y 

);

 

#

10

;

 

sw 

=

 1

;

 

$display(

 

"

x1: %b, x2: %b, sw: %b, y: %b

"

, x1, x2, sw, y 

);

 

#

10

;

 

sw 

=

 0

;

 

$display(

 

"

x1: %b, x2: %b, sw: %b, y: %b

"

, x1, x2, sw, y 

);

 

end 

 

Ostatnim opisywanym tutaj blokiem jest always. Jak sama nazwa mówi, ciało tego bloku wyko-
nywane jest zawsze. No ale cóŜ to za blok wykonywany zawsze ?? OtóŜ blok ten w odróŜnieniu 
od bloku initial posiada tzw. listę wraŜliwości. A jeśli tej nie posiada, to musi bynajmniej posia-
dać instrukcję opóźnienia. Lista wraŜliwości, to lista zmiennych wyzwalająca działanie bloku. 
Najlepiej zilustrować to na przykładzie: 
 

always

 

@(

 sel 

or

 in1 

or

 in2 

or

 in3 

or

 in4 

) begin

 

out 

=

 0

;

 

case (

 sel 

)

 

:

 out 

=

 in1

;

 

:

 out 

=

 in2

;

 

:

 out 

=

 in3

;

 

:

 out 

=

 in4

;

 

endcase 

end 
 

Pokazany kod jest implementacją czterokanałowego multipleksera. Jak widać w linijce w której 
znajduje się always umieszczona została lista pięciu zmiennych separowanych operatorem zda-
rzeniowym or. Przy zmianie kaŜdej z tych zmiennych całe ciało always zostanie wykonane. 
Przypisanie 

out 

=

 0

;

 przed  instrukcją case powoduje, Ŝe program syntezujący nie tworzy prze-

rzutnika dla sygnału out. 

Przykład ten pokazuje tylko jeden typ listy, a mianowicie listę wraŜliwą na zmiany po-

ziomu obiektów (sygnałów). Istnieje drugi typ listy który jest wraŜliwy na zbocza, czyli wyzwo-
lenie wykonania ciała always nastąpi np. przy zboczu narastającym danego sygnału. Jej działanie 
ilustruje kolejny listing kodu: 

always

 

@(

 

posedge

 clk  

or 

negedge

 clk 

)

 begin 

case (

 sel 

)

 

:

 out 

=

 in1

;

 

:

 out 

=

 in2

;

 

:

 out 

=

 in3

;

 

:

 out 

=

 in4

;

 

endcase 

end 

 

Przedstawiony przykładowy kod to implementacja synchronicznego multipleksera czterokana-
łowego, który działa zarówno przy narastającym jak i opadającym zboczu zegara. Zmiany sygna-
łów sel, in1, in2, in3, in4 mają wpływ na wyjście out tylko i wyłącznie w chwilach, w których 
zegar clk zmienia swój poziom (z zero na jeden i jeden na zero). 

background image

2.8. Przypisania proceduralne blokujące, nieblokujące i ciągłe 

W VERIGLOGu istnieją trzy rodzaje przypisań proceduralnych (czyli takich, które są 

wykorzystywane w blokach proceduralnych), blokujące, nieblokujące i ciągłe nazywane czasami 
równieŜ kwaziciągłymi. Wszystkie te przypisania tyczą się obiektów typu reg, time, integer 
i real. Przypisanie blokujące 

=

 cechuje się tym, Ŝe wykonywanie instrukcji w danym bloku pro-

ceduralnym jest opóźnione do momentu wykonania przypisania. Przypisanie nieblokujące 

<= 

na-

tomiast jak sama nazwa mówi nie blokuje wykonywania operacji w bloku. MoŜna to bardzo ła-
two zilustrować na następujących przykładach: 
 
 
 
 
 
 
Gdyby załoŜyć wartości początkowe sygnałów jako: a=0 i b=1, to w przypadku pierwszego 
przykładu otrzymamy wynik: a=1, b=1, natomiast w przypadku drugiego przykładu nastąpi za-
miana wartości zmiennych, tzn. a=1, b=0.  
 

Kolejnym typem przypisania proceduralnego jest tzw. przypisanie ciągłe. RóŜni się ono 

od bloku assign przedstawianego wcześniej tym, Ŝe tyczy się obiektów typu reg, time, integer i 
real, a dla przypomnienia zwykłe przypisanie ciągłe tyczyło się obiektów typu net. Jest ono wy-
korzystywane przy modelowaniu części asynchronicznej elementów synchronicznych, tak jak 
np. w przerzutniku typu D z wejściami zerującym i ustawiającym. Przykład implementacji poka-
zany został w kolejnymi listingu: 

 

always @ ( posedge

 clock 

) begin

 

<=

 d

;

 

q_bar 

<= !

d

;

 

end 

 

// przesłanianie 

always @ (

 set 

or

 reset 

) begin

 

if(

 set

 ) begin

 

assign

 q 

=

 1

;

 

assign

 q_bar 

=

 0

;

 

end else if(

 reset 

) begin

 

assign

 q 

=

 0

;

 

assign

 q_bar 

=

 1

;

 

end else begin 

deassign

 q

;

 

deassign

 q_bar

;

 

end 

end 

 
Analizę przebiegów czasowych symulacji pozostawia się czytelnikowi. 
 

 

// Przykład 1 

always @ ( posedge

 clk 

) begin 

=

 b

;

 

=

 a

;

 

end

 

// Przykład 2 

always @ ( posedge

 clk 

) begin 

<=

 b

;

 

<=

 a

;

 

end

 

background image

 

 

 

Zadania do wykonania 

 

1.  Przeanalizuj poniŜszy kod przykładowego modułu w języku Verilog, w protokole 

omów jaki będzie efekt działania modułu. 

 

module funkcja(x1, x2, y); 
  input x1, x2; 
  output y; 
  reg y; 

 

  assign y = ~(x1 & x2); 

 

endmodule 

 

2.  Zaprojektuj  wektory  testowe  dla  powyŜszego  modułu  a  następnie  sprawdź  jego 

działanie w środowisku ModelSim. 

 

3.  Zaimplementuj  na  płycie  uruchomieniowej,  funkcje  logiczne  NAND,  NOR  oraz 

XOR,  wejścia  funkcji  podłącz  do  przełączników  SW0-SW1,  natomiast  wyjścia 
powinny być podłączone do którejś z diod LED. Działanie modułu opisz w rapor-
cie. 

 

4.  Zaimplementować w języku Verilog poniŜszy układ kombinacyjny, przetestować 

go symulacyjnie a następnie uruchomić na płycie uruchomieniowej. 

 

 

Raport 
Wykonany  podczas  zajęć  protokół,  oceniany  będzie  na  zajęciach.  Wszystkie  programy 
wraz z komentarzami naleŜy przesłać do systemu LabPro przed zakończeniem zajęć. 

 

Ocenianie 
Maksymalnie z ćwiczenia moŜna uzyskać 5 punktów za dowolnie wybrane zadania. 
kartkówka ........1,0 
punkt 1 .............0,5 
punkt 2..............0,5 
punkt 3..............1,5 
punkt 4..............2,0 

 

 

Literatura: 

1.  Spartan-3A/3AN FPGA Starter Kit Board User Guide 

http://www.xilinx.com/support/documentation/boards_and_kits/ug334.pdf 

 

2. 

http://en.wikipedia.org/wiki/Hardware_description_language

 

3. 

http://www.asic-world.com/verilog/veritut.html

 

4. 

http://electrosofts.com/verilog/introduction.html

 

 

Opracowanie: Jan Staniek, Krzysztof CzyŜ, 2008