직렬입력 - 직렬출력 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
'Verilog' 카테고리의 다른 글
Verilog 멀티플렉서, BCD 변환기, 플립플롭 (0) | 2023.04.19 |
---|---|
Verilog 인코더, 디코더, 7세그먼트, 멀티플렉서 (0) | 2023.04.18 |
Verilog 3일 특강 2 (0) | 2023.04.17 |
Verilog 반가산기, 전가산기, 병렬가감산기, 비교기 (0) | 2023.04.17 |
Verilog 3일 특강 1 (0) | 2023.04.13 |