Verilog

Verilog 레지스터

오버헤드프레스 2023. 4. 26. 16:32

 

직렬입력 - 직렬출력 SISO

직렬입력 - 병렬출력 SIPO

병렬입력 - 직렬출력 PISO

병렬입력 - 병렬출력 PIPO

 

 

SISO

`timescale 1ns / 1ps

module shift_register_SISO(
    input D,
    input clk,
    input reset_n,
    output Q
    );
    
    wire [2:0] w;
    
    D_flip_flop_negedge DFF0 (.D(D), .E(clk), .Q(w[0]));
    D_flip_flop_negedge DFF1 (.D(w[0]), .E(clk), .Q(w[1]));
    D_flip_flop_negedge DFF2 (.D(w[1]), .E(clk), .Q(w[2]));
    D_flip_flop_negedge DFF3 (.D(w[2]), .E(clk), .Q(Q));
    
    
endmodule

SISO 코드

 

`timescale 1ns / 1ps

module shift_register_SISO_tb();

reg D,clk;
wire Q;
reg [3:0] Data;

shift_register_SISO DUT(.D(D), .clk(clk), .reset_n(1), .Q(Q));

initial begin
    D = 0;
    clk = 0;
    Data = 4'b1101;
end
initial begin
    #100 clk = 1;
    #100 D = Data[0];
    #10 clk = 0;
    #10 clk = 1;
    #10 D = Data[1];
    #10 clk = 0;
    #10 clk = 1;
    #10 D = Data[2];
    #10 clk = 0;
    #10 clk = 1;
    #10 D = Data[3];
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    #100 $finish;
end





endmodule

테스터벤치 코드

 

Data = 4'b1101

Data[0] = 1, Data[1] = 0, Data[2] = 1, Data[3] = 1

Q출력에서 하강에지에 출력된다. 앞에서 부터 Data[0] = 1, Data[1] = 0, Data[2] = 1, Data[3] = 1

 

 

 

 

 

SIPO

module shift_register_SIPO(
    input D,
    input clk,
    input rd_e_n,
    output reg [3:0] Q
    );
    
    wire [3:0] w;
    
    D_flip_flop_negedge DFF0 (.D(D), .E(clk), .Q(w[3]));
    D_flip_flop_negedge DFF1 (.D(w[3]), .E(clk), .Q(w[2]));
    D_flip_flop_negedge DFF2 (.D(w[2]), .E(clk), .Q(w[1]));
    D_flip_flop_negedge DFF3 (.D(w[1]), .E(clk), .Q(w[0]));
    
    always @(posedge clk)begin
        if(!rd_e_n)begin //rd_e_n이 0일 때라는 뜻
            Q = w;
        end
        else begin
            Q = 4'bz;
        end
    end
endmodule

SIPO 코드

 

module shift_register_SIPO_tb();

reg D,clk;
wire [3:0] Q;
reg [3:0] Data;
reg rd_e_n;

shift_register_SIPO DUT(.D(D), .clk(clk), .rd_e_n(rd_e_n), .Q(Q));

initial begin
    D = 0;
    clk = 0;
    Data = 4'b1101;
    rd_e_n = 0;
end
initial begin
    #100 clk = 1;
    #100 D = Data[0];
    #10 clk = 0;
    #10 clk = 1;
    #10 D = Data[1];
    #10 clk = 0;
    #10 clk = 1;
    #10 D = Data[2];
    #10 clk = 0;
    #10 clk = 1;
    #10 D = Data[3];
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    #10 rd_e_n = 1;
    #10 clk = 1;
    #100 $finish;
end





endmodule

SIPO 테스터 벤치

 

 

always문으로 작성할거라면 다음과 같이 진행해야함

 

3상태버퍼 사용

 

 

조건연산자를 사용할 수 있음

 

PISO

module shift_register_PISO(
    input [3:0] D,
    input clk,
    input shift_load,   //1일때는 shift, 0일 때는 load
    output Q
    );
    
    wire [2:0] dff_o;
    wire [2:0] mux_o;
    
    D_flip_flop_negedge DFF3 (.D(D[3]), .E(clk), .Q(dff_o[2]));
    D_flip_flop_negedge DFF2 (.D(mux_o[2]), .E(clk), .Q(dff_o[1]));
    D_flip_flop_negedge DFF1 (.D(mux_o[1]), .E(clk), .Q(dff_o[0]));
    D_flip_flop_negedge DFF0 (.D(mux_o[0]), .E(clk), .Q(Q));
    
    mux_2_1 mux2(.D({dff_o[2], D[2]}), .S(shift_load), .F(mux_o[2]));
    mux_2_1 mux1(.D({dff_o[1], D[1]}), .S(shift_load), .F(mux_o[1]));
    mux_2_1 mux0(.D({dff_o[0], D[0]}), .S(shift_load), .F(mux_o[0]));
    
    
    
    endmodule

PISO 코드

 

module shift_register_PISO_tb ();

reg clk;
reg [3:0] D;
wire Q;
reg shift_load;

shift_register_PISO DUT (.D(D), .clk(clk), .shift_load(shift_load), .Q(Q));

initial begin
    clk = 0;
    D = 4'b1101;
    shift_load = 0;
end
initial begin
    #100 clk = 1; 
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    shift_load = 1;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    #100 $finish;
end

endmodule

PISO 테스터벤치 코드

 

결과 시뮬레이션

 

shift_load가 0일 때는 1101의 값을 받다가 shift_load가 1이 되었을 때, 하강 에지에서 값을 받기 시작한다.

 

 

PIPO

 module shift_register_PIPO(
    input [3:0] D,
    input clk,
    input wr_e_p, rd_e_n,   //1일때는 shift, 0일 때는 load
    output [3:0] Q
    );
    
    wire [3:0] dff_o;
    wire [3:0] and_o;
    
    and (and_o[3], D[3], wr_e_p);
    and (and_o[2], D[2], wr_e_p);
    and (and_o[1], D[1], wr_e_p);
    and (and_o[0], D[0], wr_e_p);
    
    D_flip_flop_negedge DFF3 (.D(and_o[3]), .E(clk), .Q(dff_o[3]));
    D_flip_flop_negedge DFF2 (.D(and_o[2]), .E(clk), .Q(dff_o[2]));
    D_flip_flop_negedge DFF1 (.D(and_o[1]), .E(clk), .Q(dff_o[1]));
    D_flip_flop_negedge DFF0 (.D(and_o[0]), .E(clk), .Q(dff_o[0]));
    
    bufif0 (Q[0], dff_o[3],rd_e_n);
    bufif0 (Q[1], dff_o[2],rd_e_n);
    bufif0 (Q[2], dff_o[1],rd_e_n);
    bufif0 (Q[3], dff_o[0],rd_e_n);
    
    endmodule

 

PIPO 코드

 

module shift_register_PIPO_tb ();

reg clk;
reg [3:0] D;
wire [3:0] Q;
reg rd_e_n, wr_e_p;

shift_register_PIPO DUT (.D(D), .clk(clk), .rd_e_n(rd_e_n), .wr_e_p(wr_e_p), .Q(Q));

initial begin
    clk = 0;
    D = 4'b1101;
    rd_e_n = 1;
    wr_e_p = 0;
end
initial begin
    #100 wr_e_p = 0;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
     wr_e_p = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    rd_e_n = 0;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    wr_e_p = 0;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    rd_e_n = 1;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    #10 clk = 1;
    #10 clk = 0;
    rd_e_n = 0;
    #100 $finish;
end

endmodule

PIPO 테스터벤치

 

PIPO 신호 결과

 

시프트 레지스터

시간지연회로

 

 

module edge_detect(
    input clk,
    input cp_in,
    input reset_n,
    output p_edge,
    output n_edge
);
    
    reg cp_in_old, cp_in_cur;
    
    always @(negedge clk or negedge reset_n)begin
        if(!reset_n)begin
            cp_in_old = 1;
            cp_in_cur = 1;
        end
        else begin
            cp_in_old <= cp_in_cur;  //시프트 레지스터니까 논블로킹
            cp_in_cur <= cp_in;
        end
    
    end
    
    assign p_edge = ~cp_in_old & cp_in_cur;
    assign n_edge = cp_in_old & ~cp_in_cur;


endmodule

시간지연회로 코드

 

 

신호 출력 결과

 

 

 

clk의 주기가 똑같다면 Q0의 주기도 똑같을 것이다.

clk 주파수가 100MHz면 Q0의 주파수는 50MHz

T플립플롭을 거칠 때마다 2배씩 늘어남

 

분주기

 

sel 이 0일 때 1주기, 1일 때 2주기, 2일 때 4주기, 3일 때 5주기 

pwm 같은거 만들 때 사용하면 좋음

 

 

 

주기가 빠를수록 7세그먼트가 흐려지고 높을수록 깜빡거린다.

 

 

주기를 40us로 했을 경우 잔상없이 잘 출력됨

 

주기를 160ns까지 했을 때 잔상이 남아있다.

 

 

주기를 늘렸을 때 깜빡거리는 것을 확인하기위해 늘려봤다.

 

 

원래는 위 사진처럼 이동하는데 주기가 빨라 눈으로 확인하지 못하는 것이다.

 

 

파라미터 사용하기

module register_N_bit_negedge #(parameter N = 8)(//함수 선언, 회로로 만들어주지않음 initial문, parameter문 등
    input [7:0] D,
    input clk,
    input wr_e_p, rd_e_p,   //1일때는 shift, 0일 때는 load
    output [7:0] Q,
    output [7:0] tri_state_Q
    );
    
    wire [N-1:0] and_o;
    wire [N-1:0] F;
    
    
    genvar i;  //회로 만들때는 무시되고 generate안에서만 사용됨, 아래 generate문 안에 있는 것들은 회로로 만들어줌
    
    generate
        for  (i=0; i<N; i=i+1)begin
            mux_2_1 mx(.D({D[i], Q[i]}), .S(wr_e_p), .F(F[i]));
            and (and_o[i], F[i], reset_n);
            D_flip_flop_negedge DFF (.D(and_o[i]), .E(clk), .Q(Q[i]));
            bufif1 (tri_state_Q[i], Q[i],rd_e_p);  //rd_e_n이 0일 때 Q로 나간다. rd_e_p일 때 0이면 Q는 임피던스
        end
        
    endgenerate  //아래것들을 위처럼 간단하게 가능 

    endmodule

 

다음처럼 파라미터를 사용해서

 

module register_PIPO(
    input [3:0] D,
    input clk,
    input wr_e_p, rd_e_n,   //1일때는 shift, 0일 때는 load
    input reset_n,
    output [3:0] Q
    );
    
    wire [3:0] dff_o;
    wire [3:0] and_o;
    wire [3:0] F;
    
    mux_2_1 mx00(.D({D[0], dff_o[0]}), .S(wr_e_p), .F(F[0]));
    mux_2_1 mx01(.D({D[1], dff_o[1]}), .S(wr_e_p), .F(F[1]));
    mux_2_1 mx02(.D({D[2], dff_o[2]}), .S(wr_e_p), .F(F[2]));
    mux_2_1 mx03(.D({D[3], dff_o[3]}), .S(wr_e_p), .F(F[3]));
    
    and (and_o[3], F[3], reset_n);
    and (and_o[2], F[2], reset_n);
    and (and_o[1], F[1], reset_n);
    and (and_o[0], F[0], reset_n);
    
    D_flip_flop_negedge DFF3 (.D(and_o[3]), .E(clk), .Q(dff_o[3]));
    D_flip_flop_negedge DFF2 (.D(and_o[2]), .E(clk), .Q(dff_o[2]));
    D_flip_flop_negedge DFF1 (.D(and_o[1]), .E(clk), .Q(dff_o[1]));
    D_flip_flop_negedge DFF0 (.D(and_o[0]), .E(clk), .Q(dff_o[0]));
    
    bufif0 (Q[0], dff_o[3],rd_e_n);
    bufif0 (Q[1], dff_o[2],rd_e_n);
    bufif0 (Q[2], dff_o[1],rd_e_n);
    bufif0 (Q[3], dff_o[0],rd_e_n);
    
    endmodule

이 코드를 간단하게 구현할 수 있다

 

 

테스터 벤치로 확인하기

 

module register_N_bit_negedge_tb();
//register_N_bit_negedge module's input signal
reg [7:0] D = 0;
reg [7:0] data = 8'b10010110;
reg wr_e_p = 0;
reg rd_e_p = 0;
reg reset_n = 0;
reg clk = 0;
//register_N_bit_negedge module's output signal
wire [7:0] Q;
wire [7:0] tri_state_Q;
register_N_bit_negedge #(.N(8)) DUT (
    .D(D),
    .wr_e_p(wr_e_p),
    .rd_e_p(rd_e_p),
    .reset_n(reset_n),
    .clk(clk),
    .Q(Q),
    .tri_state_Q(tri_state_Q));
always begin
    #100 clk = ~clk;
end
initial begin
    #500
    D = data;
    #1000
    reset_n = 0;
    wr_e_p = 0;
    rd_e_p = 1;
    #1000
    reset_n = 0;
    wr_e_p = 1;
    rd_e_p = 0;
    #1000
    reset_n = 0;
    wr_e_p = 1;
    rd_e_p = 1;
    #1000
    reset_n = 1;
    wr_e_p = 0;
    rd_e_p = 0;
    #1000
    reset_n = 1;
    wr_e_p = 0;
    rd_e_p = 1;
    #1000
    reset_n = 1;
    wr_e_p = 1;
    rd_e_p = 0;
    #1000
    reset_n = 1;
    wr_e_p = 1;
    rd_e_p = 1;
    #1000
    data = 8'b10111110;
    D = data;
    reset_n = 0;
    wr_e_p = 0;
    rd_e_p = 0;
    #1000
    reset_n = 0;
    wr_e_p = 0;
    rd_e_p = 1;
    #1000
    reset_n = 0;
    wr_e_p = 1;
    rd_e_p = 0;
    #1000
    reset_n = 0;
    wr_e_p = 1;
    rd_e_p = 1;
    #1000
    reset_n = 1;
    wr_e_p = 0;
    rd_e_p = 0;
    #1000
    reset_n = 1;
    wr_e_p = 0;
    rd_e_p = 1;
    #1000
    reset_n = 1;
    wr_e_p = 1;
    rd_e_p = 0;
    #1000
    reset_n = 1;
    wr_e_p = 1;
    rd_e_p = 1;
    #1000
$finish;
end
endmodule