Language/Verilog

Vivado : Edge Detector, Shift Register(SISO, SIPO, PISO, PIPO)

짱도르딘 2024. 7. 16. 10:42
728x90

 

 

Edge Detector Positive

 Edge Detector Positive 동작은 아래의 그림으로 설명된다.

 

 

Clock이 인가되며, cp의 값이 1이 되는 동안 Clock가 posedge일 때 Current는 1이 된다.

Current가 1인 동안 Clock이 posedge 되는 순간 old는 1로 변경된다.

 

Positive Edge detector의 코드는 아래와 같다.

module edge_detector_p(
    input clk, reset_p,
    input cp,
    output p_edge, n_edge);
    
    reg ff_cur, ff_old; //flip flop current
    always @(posedge clk or posedge reset_p)begin
        if(reset_p)begin
            ff_cur <= 0;
            ff_old <= 0;
        end
        else begin
            ff_cur <= cp; //non blocking "<="
            ff_old <= ff_cur;
        end
    end
    
    assign p_edge = ({ff_cur, ff_old} == 2'b10) ? 1 : 0;
    assign n_edge = ({ff_cur, ff_old} == 2'b01) ? 1 : 0;
endmodule

 

코드를 시뮬레이션하면 아래와 같은 파형이 출력된다.

 

Edge detector positive 출력 파형

 

 

 

Edge Detector Negative

 

Negative Edge Detector는 앞서 나온 Positive Edge Detector와는 달리, Clock이 0이 되는 Falling Edge인 순간에 파형 변화가 이루어진다.

 

module edge_detector_n(
    input clk, reset_p,
    input cp,
    output p_edge, n_edge);
    
    reg ff_cur, ff_old; //flip flop current
    always @(negedge clk or posedge reset_p)begin
        if(reset_p)begin
            ff_cur <= 0;
            ff_old <= 0;
        end
        else begin
            ff_cur <= cp; //non blocking "<="
            ff_old <= ff_cur;
        end
    end
    
    assign p_edge = ({ff_cur, ff_old} == 2'b10) ? 1 : 0;
    assign n_edge = ({ff_cur, ff_old} == 2'b01) ? 1 : 0;
endmodule

 

Edge detectir negative 출력 파형

 


이번에 다룰 레지스터는 총 4가지로, SISO, SIPO, PISO, PIPO로 구분된다.

 

 

 

Shift register SISO

직렬입력 직렬출력 레지스터를 구현하려고 한다.

 

SISO n비트 시프트 레지스터 코드는 아래와 같다.

module shift_register_SISO_NBIT_n #(parameter N = 8)(
    input clk, reset_p,
    input d,
    output q);
    
    reg [N-1:0] siso_reg;
    always @(negedge clk or posedge reset_p)begin
        if(reset_p)siso_reg <= 0;
        else begin
            siso_reg <= {d, siso_reg[N-1:1]};
        end
    end
    assign q = siso_reg[0];    
endmodule

 

시뮬레이션 소스로(Test Bench 로) 시프트 레지스터를 작성하려면 다음과 같은 과정을 필요로 한다.

 

 

negative edge에서 바뀌는 코드는 아래와 같다.

 

Test bench 파일은 입출력이 없다. (= 첫 번째 줄 코드에 아무것도 기재하지 않는다.)

 

입력은 reg로, 출력은 wire로 선언하며, initial begin에는 초기값을 부여한다.

 

두 번째 initial 문에는 시뮬레이션할 내용들을 적어주면 된다.

 

그리고 시작하는 곳에 DUT(Design Under Test)를 선언하여 코드를 진행하면 된다.

 

구현한 코드는 아래와 같다.

module tb_shift_register_SISO_Nbit_n();

    reg clk, reset_p; //input == reg
    reg d; // input == reg
    wire q; // output == wire

    parameter data = 4'b1010;

    shift_register_SISO_NBIT_n #(.N(4)) DUT( //Design Under Test
    .clk(clk), .reset_p(reset_p),
    .d(d),
    .q(q));
    
    initial begin
        clk = 0;
        reset_p = 1;
        d = data[0];
    end
    
    always #5 clk = ~clk; // #5 = 5ns(Time scale) Time delay, #5 clk = ~clk => 10ns clock
    integer i;
    initial begin
        #10; // 10ns Clock Start
        reset_p = 0;
        for(i = 0; i < 4; i=i+1)begin
            d = data[i]; #10;
        end
        #40;
        $finish; // Finist Simulation        
    end
    
endmodule

 

출력 파형을 살펴보면, D값이 1이 될 때마다 data값에 1을 주면서, 왼쪽에서 오른쪽으로 data값은 시프트 되는 것을 확인할 수 있다.

 

 

 

이번에는 4bit가 아닌 N을 8bit로 선언하고, '11010011'로 선언하면 아래와 같은 파형이 출력된다.

module tb_shift_register_SISO_Nbit_n();

    reg clk, reset_p; //input == reg
    reg d; // input == reg
    wire q; // output == wire

    parameter data = 8'b11010011;

    shift_register_SISO_NBIT_n #(.N(8)) DUT( //Design Under Test
    .clk(clk), .reset_p(reset_p),
    .d(d),
    .q(q));
    
    initial begin
        clk = 0;
        reset_p = 1;
        d = data[0];
    end
    
    always #5 clk = ~clk; // #5 = 5ns(Time scale) Time delay, #5 clk = ~clk => 10ns clock
    integer i;
    initial begin
        #10; // 10ns Clock Start
        reset_p = 0;
        for(i = 0; i < 8; i=i+1)begin
            d = data[i]; #10;
        end
        #40;
        $finish; // Finist Simulation        
    end
    
endmodule

 

 

 

Shift register SIPO

 

PISO Register 구조

 

이번에는 직렬입력 병렬출력 레지스터를 구현하고자 한다.

 

SISO 때와 마찬가지로, SIPO_Nbit_n을 먼저 구현한 후, DUT로 선언하여 Test bench를 구현한다.

 

코드는 아래와 같다.

module tb_shift_register_SIPO_Nbit_n();

    reg clk, reset_p;
    reg d;
    reg rd_en; //read enable, 3 state buffer
    wire [7:0] q;

    parameter data = 8'b10100011;

    shift_register_SIPO_Nbit_n #(.N(8)) DUT(clk, reset_p, d, rd_en, q);  

    initial begin
        clk = 0;
        reset_p = 1;
        d = data[0];
        rd_en = 0;
    end
    
    always #5 clk = ~clk;
    
    integer i;
    
    initial begin
        #10;
        reset_p = 0; rd_en = 1; #10;
        for(i = 0; i < 8; i = i + 1)begin
            d = data[i]; #10;
        end
        rd_en = 0; #1;
        $finish;
    end
endmodule

 

SIPO 출력 결과

 

 

Shift register PISO

이번 동작을 구현할 것은 PISO이다. 병렬입력 직렬출력 레지스터로, 동작구조는 아래와 같다.

병렬입력 직렬출력 레지스터

 

 

PISO를 구현할 코드는 아래와 같다.

module tb_shift_register_PISO_Nbit_n();

    reg clk, reset_p;
    reg [7:0] d;
    reg shift_load;
    wire q;
    
    parameter data = 8'b11001010;
    
    shift_register_PISO_Nbit_n #(.N(8)) DUT(
        .clk(clk), 
        .reset_p(reset_p),
        .d(d),
        .shift_load(shift_load), // 1 = shift, 0 = load
        .q(q)
    );

    initial begin
        clk = 0;
        reset_p = 1;
        d = data;
        shift_load = 0;
    end

    always #5 clk = ~clk;
    
    initial begin
        #10;
        reset_p = 0;    
        shift_load = 0;
        d = data;
        #10;
        shift_load = 1;
        #70;
        $finish;
     end
endmodule

 

PISO 출력 결과

 

Shift register PIPO

 

PIPO 구조

위 그림을 보면 AND 게이트가 붙어 있는 것을 확인할 수 있다. WR 값이 0인 경우에는 입력을 받지 못하는 상황이므로, 코드를 구현할 때에는 MUX를 활용하여 구현할 예정이다.

 

우선 DUT를 활용하기 위하여 Nbit register 코드를 먼저 구현한다.

module register_Nbit_n #(parameter N = 8)(
    input [N-1:0] in_data,
    input clk, reset_p, wr_en, rd_en, // write/read enable
    output [N-1:0] out_data);
    
    reg [N-1:0] register;
    
    always @(negedge clk or posedge reset_p)begin
        if(reset_p) register = 0;    
        else if(wr_en) register = in_data;
    end
    
    assign out_data = rd_en ? register : 'bz; // if rd_en == 0 => Impedence
                
endmodule

 

 

Nbit register 코드가 구현되었다면, Test Bench를 사용하기 위해 Test Bench 코드를 작성한다.

module tb_register_Nbit_n();

    parameter TEST_DATA_0 = 46;
    parameter TEST_DATA_1 = 8'b00110101;
    parameter TEST_DATA_2 = 8'hf7;
    parameter TEST_DATA_3 = 7;
    
    reg clk, reset_p, wr_en, rd_en;
    reg [7:0] in_data;
    wire [7:0] out_data;
    
    register_Nbit_n #(.N(8)) DUT(in_data, clk, reset_p, wr_en, rd_en, out_data);
        
    initial begin
        in_data = 0;
        clk = 0;
        reset_p = 1;
        wr_en = 0;
        rd_en = 0;
    end        
    
    always #5 clk = ~clk;
    
    initial begin
        #10;
        reset_p = 0; #10;
        in_data = TEST_DATA_0; #10; 
        wr_en = 1; #10;
        wr_en = 0; rd_en = 1; #10;
        rd_en = 0; in_data = TEST_DATA_1; #10;
        wr_en = 1; #10;
        wr_en = 0; rd_en = 1; #10;
        rd_en = 0; in_data = TEST_DATA_2; #10;
        wr_en = 1; #10;
        wr_en = 0; rd_en = 1; #10;
        rd_en = 0; in_data = TEST_DATA_3; #10;
        wr_en = 1; #10;
        wr_en = 0; rd_en = 1; #10;
        $finish;
    end
endmodule

 

출력 파형을 살펴보면, wr_en(write enable)이 1이 될 때마다 register의 값은 변경이 되며, 출력은 임피던스로 된다.

rd_en(read enable)이 1이 되는 순간 임피던스였던 출력이 제 값으로 출력을 하는 것을 확인할 수 있다.

PIPO 출력 결과

 

728x90

'Language > Verilog' 카테고리의 다른 글

Vivado : Basys3 FND / 디지털 시계, 분주  (0) 2024.07.17
Vivado : Basys3 7segment  (0) 2024.07.16
Vivado : 동기식 카운터  (0) 2024.07.12
Vivado : Decoder, Encoder  (2) 2024.06.25
Vivado : 4bit 가산기  (0) 2024.06.16