Verilog HDL
2007/06/29 15:29
http://blog.naver.com/PostPrint.nhn?blogId=babojay&logNo=40039249819#
Chapter 7.
Behavioral Modeling
*Objectives
- always, initial in behavioral
modeling
- blocking, nonblocking procedural assignments
-
Delay-based timing control. regular delay, intra-assignment delay, zero
delay
- Event-based timing control. regular event control, named event
control, event OR control
- Level-sensitive timing control
-
Conditional statement. if and else.
- Multiway branching. case, casex,
casez
- Looping. while, for, repeat, forever.
- Sequential
block, parallel block.
- Naming of blocks, diabling of named
blocks
7.1 Structured
Procedures
- always, initial
: 가장 기본적인 structuered procedure 구문
- always와 initial 안에 다른 모든 behavioral 구문들이
위치한다.
- Concurrency : always,
initial구문 동작흐름은 동시에 병렬로 이루어진다.
- 이런 동작 흐름들은 시뮬레이션 시간
0에서 시작한다.
- nested될 수 없다.
7.1.1 initial statement
- initial 구문안에 있는 모든 구문은
initial block을 구성한다.
- initial block은 시간 0에서 시작하며 시뮬레이션 동안 단 한번
실행된다.
- 여러개의 initial block이 있는 경우 각각 시간 0에서 실행시작하며 다른 block에 영향을 주지도
받지도 않고 독립적으로 실행된다.
- 다수의 behavioral 구문은 bigin과 end로 묶어주어야 한다. 단 한 개의 구문을 묶어줄 필요는 없다. 하지만
가독성과 구문 추가의 여지를 위해서 begin과
end를 생략하지 않는 것이
좋다.
Ex)
// initial Statement
module stimulus;
reg x, y, a, b, m;
initial
m =
1'b0; //
time 0에서 실행
initial
begin
#5 a =
1'b1; // time 5에서
실행
#25 b =
1'b0; // time 5의 시점에서 25뒤(30)에 b = 1'b0;
실행
end
initial
begin
#10 x =
1'b0; // time 10에
실행
#25 y =
1'b1; // time 10의 시점에서 25뒤(35)에 y =
1'b1; 실행
end
initial
#50
$finish; // time 50에
실행
endmodule
* 위의 예제에서 3개의 initial block이 동시에 실행
** #<delay>뒤에 오는 구문은 현재시점(실행도중)에서
delay만큼 후에 실행된다.
- 실행결과는 다음과 같다.
time
실행되는 구문
0
m = 1'b0;
5
a = 1'b1;
10
x = 1'b0;
30
b = 1'b0;
35
y = 1'b1;
50
$finish;
7.1.2 always Statement
- always구문 안에 있는 모든 구문은
always block을 구성한다.
- time 0에서 시작해서 계속 반복되는 형태로 실행된다.
- clock
generator같은 전원이 있는 동안 계속 반복되는 동작을 기술할때 유용하다.
Ex)
// always
Statement
module clock_gen;
reg clock;
initial
clock =
1'b0;
// 초기화
always
#10 clock =
~clock; // 10마다 반전 (주기 20)
initial
#1000 $finish;
endmodule
7.2 Procedural Assignments
- reg, integer, real, time
변수들의 값을 변경할 때 사용한다.
- 변경된 값들은 다른 값으로 reassign하기 전까지 절대 변하지
않는다.
- 오른쪽 수식의 변화가 왼쪽의 값을 변화시키는 continuous assignment와 구별된다.
Syntax]
<assignment>
::=<lvalue> =
<expression>
- <lvalue>에
올수 있는 것들은 다음과 같다.
* reg, integer, real, time register
variable, memory element
* 위의 변수의 bit-select (ex.,
addr[0])
* 위의 변수의 part-select (ex.,
addr[31:19])
* 위의 변수의 concatenation
7.2.1 Blocking Assignments
- 구문이 명시된 순서대로 실행된다
- = 연산자를 사용한다.
Ex)
// Blocking
Statements
reg x, y,
z;
reg [15:0] reg_a, reg_b;
integer
count;
initial
begin
x = 0; y = 1; z =
1;
// time 0 에
실행
count =
0;
// time 0 에 실행
reg_a = 16'b0; reg_b = reg_a; // time 0 에 실행
#15 reg_a[2] =
1'b1;
// time 15에 실행
#10 reg_b[15:13] = {x, y, z}; // time 25에
실행
count = count +
1;
// time 25에 실행
end
* x = 0;구문이 실행되고 y
= 1;구문이 실행된다.
** count = count +
1;구문은 가장 마지막에 실행된다.
*** 오른쪽 수식의 bit수가 왼쪽보다 크면 LSB쪽을 선택하고 왼쪽에
맞추어 자른다.
**** 왼쪽 수식의 bit수가 크면 남는 부분은 0으로 채워진다.
7.2.2 Nonblocking Assignments
- sequential block의 구문의 실행을 방해하지 않고 시간계획에 따라 assign이 이루어진다.
-
<= 연산자를 사용한다.
Ex)
// Nonblocking
Assignments
reg x, y, z;
reg [15:0]
reg_a, reg_b;
integer count;
initial
begin
x = 0; y = 1; z =
1;
count =
0;
reg_a = 16'b0; reg_b =
reg_a;
reg_a[2] <= #15
1'b1;
// 15 tu에 실행
reg_b[15:13]
<= #10 {x, y, z}; // 10 tu에
실행
count <= count +
1;
// 0 tu에 실행
end
* x = 0;에서부터reg_b
= reg_a;구문까지는 0 tu에 순차적으로 실행된다.
** nonblocking(<= 연산자를 사용한 구문)은 동시에 실행된다.
*** 같은 tu에
blocking과 nonblocking이 존재한다면(count = 0; 과 count <= count +1;) blocking이 먼저 실행되고 난 후 nonblocking이
실행된다.
■ Application of nonblocking assignments
- nonblocking assignment는 동시에 일어나는 데어터 전송에 사용된다.
Ex)
// Concurrent
data transfer
always @(posedge
clock) // at positive edge of
clock
begin
reg1 <= #1 in1;
reg2 <=
@(negedge clock) in2 ^ in3;
reg3
<= #1 reg1;
end
* read : clock의 positive edge에서 오른쪽 수식의
변수in1, in2, in3, reg1를 읽어들여 계산하고 임시 저장한다.
**
write : 각각 정해진 delay와 event에 따라 때가 되면 왼쪽으로 assign된다.
- 이해를 돕기 위해 두 변수의 값을 서로 바꾸는 data swap을 blocking과 nonblocking으로 표현해 보자
Ex)
// Blocking
Statement
always @(posedge
clock)
a =
b;
always @(posedge
clock)
b = a;
// Nonblocking
Statement
always @(posedge
clock)
a <=
b;
always @(posedge
clock)
b <= a;
* 위의 blocking의 경우 a = b;와
b = a;중에서 어느것이 먼저 실행될지는 아무도 모른다. 이런 경우 두 변수의 값이 제대로
swap되는 것을 보장할 수 없다. 아마도 결과는 두 변수에 모두 같은 값(a, b중 하나)이 저장되게 될 것이다.
** nonblocking의 경우 b와 a의 값을 읽어 임시 저장소에 저장하였다가 a와 b에 각각 assign하게 된다. 이를
blocking으로 표현하면 다음의 예와 같이 될 것이다.
Ex)
// Nonblocking
expressed with blocking statement
always @(posedge
clock)
begin
temp_a =
a;
temp_b =
b;
a =
temp_b;
b =
temp_a;
end
- nonblocking을 사용할 경우 시뮬레이터의 성능저하를 유발하거나 메모리 사용량이 늘어날 가능성이 있다.
7.3 Timing Controls
- 다양한 behavioral timing control들이 있다.
- 이러한 timing control 구문이
없으면 시뮬레이션 time은 진행되지 않는다.
7.3.1 Delay-Based Timing
Control
- 구문이 나타나서 실행되기까지의 시간을 지정한다.
Syntax]
<delay>
::=
#<NUMBER>
||=
#<identifier>
||=
#(<mintypmax_expression>
<,<mintypmax_expression>>*)
■ Regular delay control
- Procedural assignment의 왼쪽에 지정한 non-zero delay.
- 명시된 delay만큼
기다렸다가 오른쪽 statement를 실행한다.
Ex)
//
Regular Delay Control
parameter latency =
20;
parameter delta = 2;
reg x, y, z, p, q;
initial
begin
x =
0;
// no delay
#10 y =
1;
// number delay
#latency z =
0;
// identifier delay
#(latency + delta) p = 1; // expression delay
#y x = x +1; // identifier delay
#(4:5:6) q =
0;
// min, typ, max delay
end
■ Intra-assignment delay control
- assignment 연산자의 오른쪽에 명시한 delay
- 연산자 오른쪽의 수식을 계산하고 난 후 명시된
delay만큼 기다렸다가 assign을 수행. Regular delay와 구별
Ex)
//
Intra-assignment delay
reg x, y, z;
initial
begin
x = 0; z =
0;
y = #5 x +
z; // 0 tu에 x와 z의 값을 취해 수식을
계산한후
// 5 tu동안 기다렸다가 y에 assign
end
// Regular delay로
표현하면..
initial
begin
x = 0; z =
0;
temp_xz = x +
z;
#5 y =
temp_xz;
end
■ Zero delay control
- 별도의 always block이나 initial block에 있는 procedural 구문은 같은 시뮬레이션 시간에
실행된다.
- 이렇게 같은 시간에 실행되는 구문들의 실행순서는 제멋대로이다.
- zero delay는 같은
시간에 실행되는 구문들중에서 가장 나중에 실행하게 한다.
- Race condition을 해소하는데 사용된다.
Ex)
// Zero delay
control
initial
begin
x =
0;
y = 0;
end
initial
begin
#0 x =
1; // zero delay
control
#0 y =
1;
end
* x = 0; y = 0; x = 1; y = 1;
구문 모두 0 tu에 실행되게 된다.
** 그 중에서도 #0(zero delay)가 적용된 x = 1; y =
1; 구문이 가장 나중에 실행된다.
*** 그러나 x = 1; y =
1; 구문들의 실행 순서는 어느것이 먼저일지 모른다.
7.3.2 Event-Based Timing Control
- Event : register나 net의 값이 변하는 것을 말한다.
■ Regular
event control
- @ : event control을 명시하는
심볼
- 신호의 변화, 신호의 positive(↑) 전환, negative(↓)전환을 감지하여 뒤에오는 구문을
실행시킨다.
- Positive transition : 0 → (1, x, z), x → 1, z → 1 인
경우
- Negative transition : 1 → (0, x, z), x → 0, z → 0 인 경우
Ex)
//Regular
Event Control
@(clock) q =
d;
// clock신호가 바뀔때마다 q = d;실행
@(posedge clock) q =
d; // clock신호가 pos transition일때 q = d;를
실행
@(negedge clock) q =
d; // clock신호가 neg transition일때 q = d;를
실행
q = @(posedge clock) d; // clock신호의 positive edge일때
// 즉시 d를 계산하고 q에 저장
■ Named event control
- 사용자가 event를 선언하고 그 event에 trigger와 recognize를 지정할 수 있다.
-
event : event 이름을 선언하는
keyword
- -> : event를
trigger하는 심볼
- @ :
trigger된 event를 인식하는 심볼
Ex)
// Named Event
Control
// 마지막 packet이 들어온 후에 버퍼에 저장하는 예제이다.
event received_data; // event 선언 name : received_data
always @(posedge
clock)
begin
if(last_data_packet)
->received_data;
end
always
@(received_data)
data_buf =
{data_pkt[0], data_pkt[1], data_pkt[2], data_pkt[3]};
■ Event OR control
- 다수의 event에 의해 실행되는 구문이나 구문 block이 있는 경우 event를 OR하여 사용
Ex)
// Event OR
control
always @(reset or clock or
d) // reset, clock, d중 어느하나라도 바뀌면
// begin~end실행
begin
if
(reset)
q =
1'b0;
else if
(clock)
q
= d;
end
7.3.3 Level-Sensitive Timing Control
- @ 는 edge를 감지하는
control이다.
- wait : 어떠한
조건이 true(level = 1)가 되기 전에는 뒤따라오는 구문을 실행하지 않는다.
Ex)
//
Level-sensitive timing control
always
wait (count_enable) #20
count = count + 1;
* count_enable을 계속 감시하다가 그 값이 1이 되면 20 tu후에 count 값을
증가시킨다.
** count_enable이 계속 1을 유지하게 되면 count값은 20 tu마다 계속 증가하게
된다.
7.4 Conditional Statements
- 어떤 조건이 만족하는지의 여부에 따라 실행할 구문을 결정한다.
- if, else : C programming과 비슷하다.
Syntax]
// Type 1
if
(<expression>) true_statement;
// Type 2
if
(<expression>) true_statement;
else false_statement;
// Type 3
if
(<expression1>) true_statement1;
else if (<expression2>)
true_statement2;
else if
(<expression3>) true_statement3;
else default_statement;
- <expression>을 계산하여
true(non-zero)이면 true_statement를,
false(0,x,z)이면 false_statement
실행한다.
- true_statement, false_statement가 여러개의 구문으로 되어 있는 경우 begin,
end로 그룹화한다.
Ex)
// Conditional
Statement Examples
if (!lock) buffer =
data;
if (enable) out = in;
if (number_queued
< MAX_Q_DEPTH)
begin
data_queue = data;
number_queued = number_queued +
1;
end
else
$display("Queue Full. Try
again");
if (alu_control ==
0)
y = x +
z;
else if (alu_control ==
1)
y = x -
z;
else if (alu_control ==
2)
y = x *
z;
else
$display("Invalid ALU control signal");
7.5 Multiway Branching
- 앞에서 언급한 if-else if
구문(Type 3 conditional statement)의 다른 형태
- 조건이 많아지면 if-else if 구문으로는 표현하기 번거롭다.
-
case : 조건의 결과에 따라 실행구문이 달라진다.
7.5.1 case Statement
// case Statement structure
case
(expression)
alternative1:
statement1;
alternative2:
statement2;
alternative3:
statement3;
:
default:
default_statement;
endcase
- expression은 alternative1에서부터 쓰여있는 순서대로 차례로 비교된다.
-
비교 결과 일치한 경우 그에 따른 구문을 실행하고 case구문을
빠져 나온다.
- 일치하는 경우가 없는 경우 default_statement를 실행하고 case구문을 빠져 나온다.
- case문은
nesting이 가능하다.
Ex)
// case구문으로
작성한 7.4의 type 3예제
reg [1:0] alu_control;
case
(alu_control)
2'd0: y = x +
z;
2'd1: y = x -
z;
2'd2: y = x *
z;
default: $display("Invalid ALU
control signal");
endcase
- Many-to one multiplexer와 같이 동작한다.
Ex)
// 4-to-1
Multiplexer with case statement
module mux4to1 (out, i0,
i1, i2, i3, s1, s0);
output
out;
input i0, i1, i2, i3;
input s1,
s0;
reg out;
always @(s1 or s0 or
i0 or i1 or i2 or i3)
case ({s1,
s0})
2'd0 : out =
i0;
2'd1 : out =
i1;
2'd2 : out =
i2;
2'd3 : out =
i3;
default : $display("Invalid
control signals");
endcase
endmodule
- case 구문은 expression과 alternative의 값을 bit대 bit로 비교한다.
- 0, 1, x, z 모두 bit별로 일대일 비교한다.
-
bit width가 다르면 큰 쪽으로 맞추어 비교한다. (남는부분은 0으로 채움)
Ex)
// Case with x
& z
module demux1to4 (out0, out1, out2, out3, in, s1,
s0);
output out0, out1,
out2, out3;
reg out0, out1, out2,
out3;
input in;
input s1,
s0;
always @(s1 ro s0 or
in)
case ({s1,
s0})
2'b00 : begin out0 = in; out1
= 1'bz; out2 = 1'bz, out3 = 1'bz;
end
2'b01 : begin out0 = 1'bz;
out1 = in; out2 = 1'bz, out3 = 1'bz;
end
2'b10 : begin out0 = 1'bz;
out1 = 1'bz; out2 = in, out3 = 1'bz;
end
2'b11 : begin out0 = 1'bz;
out1 = 1'bz; out2 = 1'bz, out3 = in; end
2'bx0, 2'bx1, 2'bxz,
2'bxx, 2'b0x, 2'b1x, 2'bzx
:
begin
out0 = 1'bx; out1 = 1'bx; out2 = 1'bx; out3 =
1'bx;
end
2'bz0, 2'bz1, 2'bzz, 2'b0z,
2'b1z :
begin
out0 = 1'bz; out1 = 1'bz; out2 = 1'bz; out3 =
1'bz;
end
default : $
display("Unspecified control signals");
endcase
endmodule
* 같은 실행구문을 갖는 alternatives들은 위의 예처럼 comma(,)로 구분하여 함께 적어줄 수 있다.
7.5.2 casex, casez Keyowrds
- casez : case expression과
alternative에 있는 모든 z를 don't care로
취급한다.
- casex : case
expression과 alternative에 있는 모든 x와
z를 don't care로 취급한다.
Ex)
// casex
Usage
reg [3:0] encoding;
integer
next_state;
casex
(encoding)
4'b1xxx : next_state =
3;
4'bx1xx : next_state =
2;
4'bxx1x : next_state =
1;
4'bxxx1 : next_state =
0;
default : next_state =
0;
endcase
7.6 Loops
7.6.1 While Loop
- while-expression이 거짓(false)이 될 때까지 loop를 실행한다.
Ex)
// While
Loop
// 예제 1
integer
count;
initial
begin
count =
0;
while (count <
128) // count = 128이 되면
begin~end를
// 실행하지 않고 빠져나온다.
begin
$display("Count = %d",
count);
count = count + 1;
end
end
// 예제
2
'define TURE 1'b1;
'define FALSE
1'b0;
reg [15:0]
flag;
integer i;
reg
continue;
initial
begin
flag = 16'b
0010_0000_0000_0000;
i =
0;
continue = 'TRUE;
while ((i<16)
&& continue) // 다수의 expression
사용가능
begin
if
(flag[i])
begin
$display("Encountered a TRUE bit at element number %",
i);
continue =
'FALSE;
end
i = i
+ 1;
end
end
7.6.2 For Loop
- 초기값과 종료조건을 가지며, 변수값을 변화시키는 구문을 함께 갖고 있다.
- while
구문에 비해 축약되고 함축적이지만 일반적이지 않아 사용범위가 넓지 않다.
Ex)
// For
Loop
integer count;
initial
for (count = 0; count <
128; count = count
+1)
$display("Count = %d", count);
7.6.3 Repeat Loop
- 반복할 횟수를 숫자로 명시하는 Loop이다.
- Loop에 들어갈 순간에 읽은 반복횟수는 loop가 진행되는
동안 값이 바뀌어도 반복횟수가 바뀌진 않는다.
Ex)
// Repeat
Loop
// Illustration #1
integer
count;
initial
begin
count =
0;
repeat(128)
begin
$display("Count = %d",
count);
count = count + 1;
end
end
// Illustration
#2
module data_buffer (data_start, data,
clock);
parameter cycles =
8;
input data_start;
input [15:0]
data;
input clock;
reg [15:0] buffer
[0:7};
integer i;
always
@(posedge clock)
begin
if(data_start)
begin
i =
0;
repeat(cycles) // begin ~ end를 8번
반복
begin
@(posedge clock) buffer[i] = data; // clock의 posedge를 기다렸다가
// data를
저장
i = i + 1;
end
end
end
endmodule
7.6.4 Forever Loop
- $finish를 만나기 전까지는 빠져나오지
않는 loop
- while(1)과
같다.
- disable구문으로 빠져나올 수
있다.
Ex)
// Forever
Loop
// #1 Clock Generator
reg
clock;
initial
begin
clock =
1'b0;
forever #10 clock =
~clock;
end
//
#2
reg clock;
reg x,
y;
initial
forever @(posedge clock) x
= y;
7.7 Sequential and Parallel Blocks
- Block이란 앞에서 보아왔던 begin,
end로 묶인 구문들의 집합이다.
-
Block에는 여러가지 형태와 특징들을 갖고 있다.
7.7.1 Block Types
■ Sequential Blocks
- begin, end로
묶인 구문들의 집합
- 작성된 순서대로 순차적으로 실행된다. 즉 앞선 구문의 실행이 완전히 끝나야 다음 구문이
실행된다.
- delay나 event control이 명시되어 있다면 앞선 구문의 실행이 완료된 시점을 기준으로 한다.
Ex)
// Sequential
Block
// #1
reg x,
y;
reg [1:0] z, w;
initial
begin
x =
1'b0;
y =
1'b1;
z = {x,
y};
w = {y,
x};
end
//
#2
reg x, y;
reg [1:0] x,
w;
initial
begin
x =
1'b0;
// 0 tu : 실행 완료
#5 y =
1'b1;
// 5 tu : 실행 완료
#10 z = {x,
y}; // 15 tu : 실행
완료
#30 w = {y,
x}; // 45 tu : 실행
완료
end
■ Parallel Blocks
- fork, join으로
묶인 구문들의 집합
- 모든 구문들은 작성순서에 관계없이 동시에 실행
- 구문들의 실행순서는 delay와
event control에 의해 조절된다.
- delay나 event control은 block에 들어간 시점을 기준으로
한다.
Ex)
// Parallel
Blocks
reg x, y;
reg [1:0] z,
w;
initial
fork
x =
1'b0;
// 0 tu : 실행 완료
#5 y =
1'b1; // 5 tu
: 실행 완료
#10 z = {x,
y}; // 10 tu : 실행
완료
#20 w = {y,
x}; // 20 tu : 실행 완료
join
- Parallel block에서 주의할 점은 모든 구문들이 동시에 실행되면서 race condition에 빠질 수 있다는
것이다.
- 위의 예에서 delay가 명시 되지 않는 다면 어떤 결과가 나올지 아무도 장담 못한다.
- 그림 7.1에서 처럼 4개의 구문이 한꺼번에 실행된다면 z와 w의 값은 보장할 수 없게 된다.
그림 7.1 parallel block race condition
7.7.2 Special Features of Blocks
■ Nested Blocks
- Block은 nesting이 가능하며, sequential과 parallel block을 섞어 사용할 수도 있다.
Ex)
// Nested
Blocks
initial
begin
x =
1'b0;
fork
#5 y
= 1'b1;
#10 z = {x, y};
join
#20 w = {y,
x};
end
■ Named Blocks
- Block에 이름을 정해줄 수 있다.
- 이름이 정해진 block내에서만 사용하는 local
variable을 선언할 수 있다.
- Hierarchical name으로 access가능하다.
- disable로 실행을 정지시킬 수 있다.
Ex)
// Named
blocks
module top;
initial
begin:
block1 // Sequential
block, name : block1
integer
i;
// static & local to block1
...
...
end
initial
fork:
block2 //
Parallel block, name : block2
reg
i;
// static & local to block2
...
...
join
■ Disabling Named Blocks
- disable : block의 실행을 중지시키는 기능
Ex)
// Disabling
Named Blocks
reg [15:0] flag;
integer i;
initial
begin
flag = 16'b
0010_0000_0000_0000;
i =
0;
begin:
block1
while(i <
16)
begin
if
(flag[i])
begin
$display("Encountered a TRUE bit at element number %d",
i);
disable
block1;
end
i = i + 1;
end
end
end
7.8 Examples
7.8.1 4-to1 Multiplexer
Ex)
// 4-to1
multiplexer
module mux4to1 (out, i0, i1, i2, i3, s1,
s0);
output
out;
input i0, i1, i2, i3;
input s1,
s0;
reg out;
// 입력중 어느 하나라도 값이 변하면
출력을 다시 계산하도록 한다.
// 모든 입력이 출력 재계산의 원인이 되므로 always @(...)의
리스트가 된다.
always @(s1 or s0 or i0 or i1 or i2 or
i3)
begin
case ({s1,
s0)}
2'b00: out =
i0;
2'b01:
out = i1;
2'b10: out =
i2;
2'b11:
out = i3;
default: out = 1'bx;
endcase
end
endmodule
7.8.2 4-bit Counter
Ex)
// 4-bit
Counter
module counter(Q, clock, clear);
output [3:0]
Q;
input clock, clear;
reg [3:0]
Q;
always @(posedge
clear or negedge clock)
begin
if
(clear)
Q
= 4'd0;
else
Q =
(Q + 1) % 16;
end
endmodule
7.8.3 Traffic Signal Controller
■ Specification
- Highway의 교통신호가 최우선이며, 기본적으로 파란불이다.
- 때때로 Country road에 차가
도착하면 대기중인 차가 지나갈만큼의 시간동안 파란불이 된다.
- Country road에 차가 다 지나가면 즉시 노란불로 바뀌고
곧 빨간불로 바뀌면서 highway의 신호가 파란불로 바뀐다.
- 센서는 country road에 대기중인 차가 있는지를
감지하고 X 신호로 controller에게 신호를 보낸다. country road에 대기중인 차가 있으면 X = 1이 된다.
그림 7.3 Dataflow Diagram of Statemachine
■ Verilog Description
// Traffic signal
Controller
'define TRUE
1'b1
'define FALSE 1'b0
'define
RED 2'd0
'define
YELLOW 2'd1
'define GREEN 2'd2
// Define
State
HWY
CNTRY
'define S0
3'd0 //
Green
Red
'define S1
3'd1 //
Yellow
Red
'define S2
3'd2 //
Red
Red
'define S3
3'd3 //
Red
Green
'define S4
3'd4 //
Red
Yellow
// Delay
define
'define Y2RDELAY 3 //
Yellow to Red delay
'define R2GDELAY
2 // Red to Green delay
module sig_control (hwy, cntry, X, clock, clear);
output [1:0] hwy,
cntry;
reg [1:0] hwy, cntry;
input
X;
input clock, clear;
// Internal
variables
reg [2:0] state;
reg [2:0]
next_state;
initial
begin
state =
'S0;
next_state =
'S0;
hwy =
'GREEN;
cntry =
'RED;
end
always @(posedge
clock)
state =
next_state;
always
@(state)
begin
case(state)
'S0:
begin
hwy =
'GREEN;
cntry =
'RED;
end
'S1:
begin
hwy =
'YELLOW;
cntry =
'RED;
end
'S2:
begin
hwy =
'RED;
cntry =
'RED;
end
'S3:
begin
hwy =
'RED;
cntry =
'GREEN;
end
'S4:
begin
hwy =
'RED;
cntry =
'YELLOW;
end
endcase
end
always @(state or
clear or X)
begin
if
(clear)
next_state = 'S0;
else
case
(state)
'S0: if
(X)
next_state =
'S1;
else
next_state =
'S0;
'S1:
begin
repeat('Y2RDELAY) @(posedge
clock);
next_state =
'S2:
end
'S2:
begin
repeat('R2GDELAY) @(posedge
clock);
next_state =
'S3;
end
'S3: if
(X)
next_state =
'S3;
else
next_state =
'S4;
'S4:
begin
repeat('Y2RDELAY) @(posedge
clock);
next_state =
'S0;
end
default: next_state =
'S0;
endcase
end
endmodule
■ Stimulus
// Stimulus
Module
module stimulus
wire [1:0] MAIN_SIG,
CNTRY_SIG;
reg CAR_ON_CNTRY_RD;
reg
CLOCK, CLEAR;
sig_control SC(MAIN_SIG, CNTRY_SIG, CAR_ON_CNTRY_RD, CLOCK, CLEAR);
initial
$monitor($time, "Main Sig
= %b Country Sig = %b Car_on_cntry =
%b",
MAIN_SIG, CNTRY_SIG, CAR_ON_CNTRY_RD);
initial
begin
CLOCK =
'FALSE;
forever #5 CLOCK =
~CLOCK;
end
initial
begin
CLEAR =
'TRUE;
repeat (5) @(negedge
CLOCK);
CLEAR =
'FALSE;
end
initial
begin
CAR_ON_CNTRY_RD =
'FALSE;
#200 CAR_ON_CNTRY_RD =
'TRUE;
#100 CAR_ON_CNTRY_RD =
'FALSE;
#200 CAR_ON_CNTRY_RD =
'TRUE;
#100 CAR_ON_CNTRY_RD =
'FALSE;
#200 CAR_ON_CNTRY_RD =
'TRUE;
#100 CAR_ON_CNTRY_RD =
'FALSE;
#100
$stop;
end
endmodule