[논리설계] Sequential Logic 및 예제
지난 포스팅에 이어 Sequential Logic에 대해 알아보겠다. Sequential Logic은 회로의 출력이 현재 입력뿐만 아니라 과거의 입력에도 의존하는 것이기 때문에, 회로 내부의 상태(State) 개념이 도입된다. 여기서 상태는 레지스터를 통해 구현되며, 레지스터의 값은 clock 신호에 맞춰 갱신된다.
Sequential Logic Example: Door Combinational Lock
Sequential Logic의 예시로, 올바른 숫자 3개를 차례대로 입력해 잠금장치를 여는 도어락을 생각해 보자.
위 사진의 왼쪽이 회로의 구성을 대략적으로 나타낸 것이다. 새로운 값이 입력되는 순간 new가 1로 설정되고 value가 0부터 9 사이 중 하나의 값으로 들어온다. 이러한 value가 현재 자릿수에 해당하는 비밀번호 값(C1, C2, C3 중 하나)과 일치하는지를 판단하여 잠금장치가 열리는지 여부(open)을 출력하는 회로이다. 이제 이 회로를 설계해 보자.
이 회로가 가질 수 있는 상태는 S1, S2, S3, ERR, OPEN이 있다. S1, S2, S3는 각각 비밀번호 중 1번째, 2번째, 3번째 자리의 입력을 기다리는 상태이고, ERR은 틀린 입력이 들어온 상태, OPEN은 비밀번호 입력이 모두 올바르게 들어와 잠금장치가 열린 상태를 의미한다. 위 사진의 오른쪽은 이러한 상태들이 어떤 조건에서 어떻게 변화하는지를 나타낸 Finite-State Diagram이다.
그 다음으로 Combinational Logic에서 진리표를 만들었던 것과 같이, State와 입력에 따른 다음 State 및 출력을 결정하는 State table을 만들어야 한다. 위 사진은 State Diagram에서 상태 전이를 표로 옮긴 것이다. 이제 이를 바탕으로 회로를 설계해 보자.
Sequential Logic의 내부는 데이터를 다루는 Datapath와 회로의 상태를 다루는 Controller로 나누어 설계한다.
Controller에 state 레지스터가 위치하고 있으며, new / equal / reset이라는 세 가지 신호와 state 자신을 입력으로 받는 combinational logic에 의해 다음 state가 정해진다. 이 combinational logic은 위의 state table에 따라 설계하면 된다.
Datapath에는 비밀번호 데이터에 해당하는 C1, C2, C3 값이 저장되어 있으며 Controller에서 현재 state 정보를 받아 멀티플렉서로 이 세 값 중 하나를 선택한 뒤, 입력된 value와 비교한다. Datapath의 출력인 equal은 다시 Controller에서 다음 state를 구하는 데 활용된다.
Verilog 구현 및 시뮬레이션
위와 같이 설계한 회로를 Verilog로 구현해 보았다.
doorlock.v
(위 설계와는 다르게, 시뮬레이션에서 모듈 내부의 state를 확인하기 위해 intstate라는 output을 추가하였다.)
module doorlock(
input wire clk,
input wire[3:0] value,
input wire new,
input wire reset,
output reg open,
output reg[2:0] intstate
);
// State of the Controller
reg[2:0] state = 1;
// possible states: 1(C1), 2(C2), 3(C3), 4(OPEN), 5(ERR)
// Password stored in Datapath
reg[3:0] C1 = 7;
reg[3:0] C2 = 8;
reg[3:0] C3 = 9;
reg[3:0] muxout;
reg equal;
// Sequential logic: executed at every clock
always @ (posedge clk) begin
if(reset) begin
state = 1;
end
if(new) begin
// Datapath section
case(state)
1: muxout = C1;
2: muxout = C2;
3: muxout = C3;
endcase
equal = (muxout == value);
// Combinational logic in Controller
if(equal) begin
if(state < 4) state = state + 1;
end
else begin
state = 5;
end
end
// Assign the output of Controller
open <= (state == 4);
intstate <= state;
end
endmodule
tb_doorlock.v
module tb_doorlock();
reg clk = 1, new, reset;
reg[3:0] value;
wire open;
wire[2:0] intstate;
doorlock u_doorlock(
.clk(clk), .new(new), .reset(reset),
.value(value), .open(open), .intstate(intstate)
);
always #5 clk = ~clk;
initial begin
clk <= 0; new <= 0; reset <= 0; value <= 0;
#15
// test #1: input '789'
value <= 7; new <= 1; #10
value <= 8; #10
value <= 9; #10
new <= 0; #10
// reset
#20
reset <= 1; #10
reset <= 0; #10
// test #2: input '787'
value <= 7; new <= 1; #10
value <= 8; #10
value <= 7; #10
new <= 0; #10
// reset
#20
reset <= 1; #10
reset <= 0;
end
endmodule
이 testbench는 7,8,9를 순서대로 모듈에 입력하고, 1회 reset한 후 7,8,7 순서대로 다시 입력한다.
ModelSim으로 시뮬레이션한 결과는 다음 화면과 같다.
모듈의 state와 open이 의도한 설계에 맞게 변화하는 것을 볼 수 있다.