본문 바로가기

Verilog HDL 설계

Countdown control & display

신호등과 같은 CountDown 표시가 필요한 회로는 세 가지 조건을 만족해야 한다.

 

 

Condition 1.

신호등은 정해진 시간부터 0초까지 1초씩 신호가 바뀐다. 1의 자릿수가 0이 되면 그 다음에는 10의 자릿수가 1씩 감소하며, 1의 자릿수는 9가 된다. 각 자릿수의 카운터가 서로 엮여있으므로 nested counter를 쓸 것이다. nested counter에 대해서는 이전 포스트에서 언급한 적이 있어서 자세히는 설명하지 않겠다.

 

 

Condition 2.

신호등은 각자 다른 시간을 가지고 있기 때문에 그리고 언제든지 조정이 될 수 있어야하기 때문에, 값을 조정할 수도 있어야 할 것이다.

 

Condition 3.

또한 한번 신호가 끝나면 일정 시간 후에 다시 반복해야하기 때문에 신호가 끝나면 일정 시간 동안 기다리기도 해야 할 것이다.

 

카운트다운 모듈을 비롯한 제어 회로를 구현했다. 우선 카운트다운 모듈이다.

 

module countdown_one(
    output [3:0] data_out,
    input  clk_in, rst, enb, EOT,
    input  [3:0] init_val
);

reg [3:0] data_reg;

assign data_out = data_reg;

always @ (posedge clk_in or posedge rst) begin
    if (rst) begin
        data_reg <= 4'b0;
    end
    else if (enb) begin
        data_reg <= init_val;
    end
    else if (~EOT) begin
        if (data_reg == 4'd0) begin
            data_reg <= 4'd9;
        end
        else begin
            data_reg <= data_reg - 4'b1;
        end
    end
end

endmodule

module countdown_ten(
    output [3:0] data_out,
    input  [3:0] data_ones,
    input  clk_in, rst, enb, EOT,
    input  [3:0] init_val
);
// 40 to 00
reg [3:0] data_reg;

assign data_out = data_reg;

always @ (posedge clk_in or posedge rst) begin
    if (rst) begin
        data_reg <= 4'b0;
    end
    else if (enb) begin
        data_reg <= init_val;
    end
    else if (~EOT) begin
        if (data_ones == 4'd0) begin
            if (data_reg == 4'd0) begin
                data_reg <= init_val;
            end
            else begin
                data_reg <= data_reg - 4'b1;
            end
        end
    end
end

endmodule

 

one과 ten을 나눈 이유는 다른 용도에서도 사용할 수 있게끔 하기 위해서다. 예를 들어 분/초 카운터가 있으면 초 단위의 data_out을 이용해서 분 단위 카운터를 제어할 수 있을 것이다.

 

다음 코드에서 다루겠지만 이 두 모듈들은 연결되어 있는 카운터라고 생각해도 되는데, 이유는 ten의 input 중 data_ones가 one의 data_out과 연결되기 때문이다. 위 두 모듈을 이용해 Conditino 1을 만족시켰다.

 

enb가 1인 경우에는 레지스터 값을 init_val로 무조건 바꾸게 되는데, Condition 2를 만족하기 위함이다.

 

EOT는 다음 코드에서도 확인할 수 있지만 End Of Traffic을 줄인 말이다. 그냥 변수 이름 길게 쓰기 싫어서 줄였다. EOT가 0일 경우에만 작동한다는 것은 EOT가 1, 즉 신호가 끝났을 때는 동작하지 않는다는 것이다. 이를 통해 Condition 3의 일부를 만족시켰다(멈추는 기능은 있지만 기다리는 기능은 다른 모듈에 있다). 

 

이제 두 모듈을 연결하는 모듈을 살펴보자.

 

module time_traffic(
    output [7:0] data_traffic_out,
    output End_of_Traffic,
    input  clk, rst, enb,
    input  [7:0] init_val
);

wire clk_ten;
wire [7:0] data_count;
wire enb_countdown = enb;

assign data_traffic_out = data_count;

assign End_of_Traffic = (data_count == 8'b0) ? 1'b1 : 1'b0;

countdown_one ones(
    .data_out(data_count[0 +: 4]),
    .clk_in(clk), 
    .rst(rst), 
    .enb(enb_countdown),
    .init_val(init_val[0 +: 4]),
    .EOT(End_of_Traffic)
);

countdown_ten tens(
    .data_out(data_count[4 +: 4]),
    .clk_in(clk), 
    .rst(rst), 
    .enb(enb_countdown),
    .init_val(init_val[4 +: 4]),
    .data_ones(data_count[0 +: 4]),
    .EOT(End_of_Traffic)
);

endmodule

 

End_of_Traffic 변수는 8비트 변수인 data_count, 카운터에 표시되는 숫자들이 전부 0일 경우에만 1이 된다. 이를 통해 신호가 끝난 시점을 확인할 수 있다.

 

module top(
    output [7:0] data_out,
    input clk, rst,
    input [7:0] init_val
);

reg enb;
reg [3:0] countenb;
wire End_of_Traffic;

time_traffic TRAFFIC(
    .clk(clk), 
    .rst(rst),
    .enb(enb),
    .init_val(init_val),
    .data_traffic_out(data_out),
    .End_of_Traffic(End_of_Traffic)
);

always @ (posedge clk) begin
    if (rst) begin
        enb <= 1'b0;
        countenb <= 4'b0;
    end
    else begin
        if (End_of_Traffic) begin
            if (countenb == 4'd11) begin
                countenb <= 4'b0;
                enb <= 1'b0;
            end
            else if (countenb == 4'd10) begin
                enb <= 1'b1;
                countenb <= countenb + 4'b1;
            end
            else begin
                enb <= 1'b0;
                countenb <= countenb + 4'b1;
            end
        end
    end
end

endmodule

 

마지막 모듈인 top 모듈이다. top 레벨에서 Condition 3의 기다리는 기능을 구현했다. 위의 코드에서는 12 클락 동안 기다리게 된다.

 

이제 제대로 동작하는지 살펴보자. 테스트벤치는 아래와 같다.

 

`timescale 1ns/1ps

module tb_traffic();

reg clk, rst;
reg [7:0] init_val;
wire [7:0] data_out, data_out_top;
wire End_of_Traffic;

top TEST(
    .clk(clk),
    .rst(rst),
    .init_val(init_val),
    .data_out(data_out_top)
);

initial begin
    clk <= 1;
    rst <= 0;
    #10
    rst <= 1;
    #10
    rst <= 0;
end

initial begin
    init_val <= 8'h42;
    #500
    init_val <= 8'h30;
    #500
    init_val <= 8'h22;
end

always #5 clk <= ~clk;

endmodule

 

시작은 42초이며 30초 및 22초로 값이 재설정된다.

 

파형은 다음과 같이 나타나게 된다.

 

'Verilog HDL 설계' 카테고리의 다른 글

Simple Finite State Machine implementation  (0) 2021.04.29
테스트벤치 작성 예시  (0) 2021.04.25
BCD to 7 segment  (0) 2021.04.19
간단한 Deinterleaver  (0) 2021.04.18
D latch, Master-Slave D flip-flop 구현 (gate level)  (0) 2021.04.17