Verilog에서 sequential logic 설계 시, 서로 다른 always@(posedge clk) 블록에서 같은 변수를 변경하려 하면 "Multiple-Driver" 경고가 나오며 Implementation이 진행되지 않는다.
하지만 always@(*) 블록의 경우는 어떨까? 아래 코드를 보자.
module test(
input clk,
input reset,
input a, b,
output led
);
localparam IDLE = 2'b00;
localparam LED_ON = 2'b01;
localparam LED_OFF = 2'b10;
reg [1:0] state, next_state;
reg r_led, r_led_next;
always @(posedge clk, posedge reset) begin
if(reset) begin
r_led <= 0;
state <= 0;
end else begin
r_led <= r_led_next;
state <= next_state;
end
end
always @(*) begin
r_led_next = r_led;
next_state = state;
case (state)
IDLE: if(a) begin
next_state = LED_ON;
r_led_next = 1;
end
LED_ON : if(b) begin
next_state = LED_OFF;
r_led_next = 0;
end
LED_OFF : if(!a && !b) begin
next_state = IDLE;
end
default: begin
next_state = IDLE;
r_led_next = 0;
end
endcase
end
assign led = r_led;
endmodule
불필요한 변수들이 몇몇 있지만, 그 때 당시 동일한 환경을 재현하기 위해 코드를 작성해 보았다. "LED_ON" state 일때만 LED를 ON 시키는 코드이며 아래 영상과 같이 정상적으로 동작하는 것을 볼 수 있다.
다음 코드를 보면 두 개의 always@(*) 블록에서 "r_led_next"에 접근하기에 "Multiple-Driver" 경고가 나올 것 같지만, 위 코드는 합성, 그리고 Bitstream 까지 생성이 된다.
module test(
input clk,
input reset,
input a, b,
output led
);
localparam IDLE = 2'b00;
localparam LED_ON = 2'b01;
localparam LED_OFF = 2'b10;
reg [1:0] state, next_state;
reg r_led, r_led_next;
always @(posedge clk, posedge reset) begin
if(reset) begin
r_led <= 0;
state <= 0;
end else begin
r_led <= r_led_next;
state <= next_state;
end
end
always @(*) begin
r_led_next = r_led;
next_state = state;
case (state)
IDLE: if(a) begin
next_state = LED_ON;
end
LED_ON : if(b) begin
next_state = LED_OFF;
end
LED_OFF : if(!a && !b) begin
next_state = IDLE;
end
default: next_state = IDLE;
endcase
end
always @(*) begin
case (state)
IDLE: r_led_next = 0;
LED_ON : r_led_next = 1;
LED_OFF : r_led_next = 0;
default: r_led_next = 0;
endcase
end
assign led = r_led;
endmodule
입력에 따라 output인 "led"에 어떤 값이 저장되는지, state는 어떤 상태인지 확인할 수 없었지만 아래 동영상과 같이 정상적인 동작은 하지 않는 모습을 볼 수 있다.
아래 코드와 같이 작성했던 이유는 non-blocking 의 경우 병렬이 아닌 순차적으로 처리되기 때문에 블록을 나누어 설계를 해도 아래에 있는 always@(*) 블록의 값이 저장될 것이라 생각했는데... 아니었다. 동기식 블록을 위와 같이 설계하면 race condition이 발생할 수 있다고는 하는데.. 비동기식으로 설계를 했는데도 저런 문제가 나타나니..
이에 대하여 AMD 포럼에 문의를 하니 blocking을 사용했기 때문이라 하는데, "r_led_next" 부분을 non-blocking 방식으로 해도 동작이 되지는.. 않았다.
그러던 중, Clifford E. Cummings의 " Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!"과 Stackoverflow에 올라온 글을 보았는데,
결론적으로 "Multiple-Driving" 문제로 인한 것 같으니,
한 변수에 여러 always 문 assign 을 하는 일은 없도록 하자.
Clifford E. Cummings가 제시하는 코딩 가이드라인을 끝으로 게시글을 마치겠다.
'이론 공부 > 기타 학습' 카테고리의 다른 글
신호 안정화를 위해 Flip-Flop을 여럿 사용하는 이유 (0) | 2025.01.06 |
---|---|
CMOS 설계 시, PMOS의 WIDTH는 무엇을 기준으로 설계되는가? (0) | 2025.01.06 |
Synthesis 단계에선 무슨일이 일어날까? (2) | 2025.01.06 |
Flip-Flop의 종류 (FDRE, FDSE, FDPE, FDCE) (0) | 2025.01.05 |
Flip-Flop 에서 reset의 중요성 (0) | 2025.01.05 |