★ 시프트 레지스터
시프트 레지스터는 여러 개의 플립플롭이 직렬로 연결된 구조를 가지며, 클럭신호가 인가될 때마다 데이터가 왼쪽 또는 오른쪽으로 이동되는 기능을 수행한다. 시프트 레지스터의 데이터는 직렬 또는 병렬로 입-출력을 할 수 있다. 또한 4가지의 입-출력 동작을 선택적으로 수행하도록 범용 시프트 레지스터로 구현될 수도 있다. 또한 시프팅 방향에 따라 왼쪽 시프트, 오른쪽 시프트, 양방향 시프트 등이 있다.
시프트 레지스터는 플립플롭이 직렬로 연결된 형태를 가지므로, 앞단의 플립플롭 출력이 다음 단 플립플롭의 입력으로 연결되도록 모델링되어야한다. 이를 위해서는 클럭의 엣지 전이를 검출하는 always블록 내부에 nonblocking할당문이 사용되어야 한다. 시프팅 동작의 모델링을 위해 nonblocking할당문, 시프트 연산자, 결합 연산자 등 다양한 방법들이 사용될 수 있다.
★ 직렬입력 - 직렬출력 시프트 레지스터
위 그림은 직렬입력 - 직렬출력 8비트 시프트 레지스터 회로이며, active-low동기식 Reset을 갖는다. 클록의 상승엣지에서 레지스터의 내용이 왼쪽으로 1비트씩 시프팅되며, 직렬입력 sin은 레지스터의 LSB에 입력되고, 직렬출력 sout은 MSB에서 직렬로 출력된다.
시프트 레지스터의 동작을 직접적으로 표현하면 다음과 같이 nonblocking할당문을 사용하여 레지스터의 각 비트가 시프팅되도록 모델링할 수 있다.
module shift_reg_nblk(clk,rst,sin,sout);
input clk,rst,sin;
output sout;
reg [7:0] q;
assign sout = q[7];
always@(posedge clk)begin
if(!rst) q<=8'b0;
else begin
q[0] <= sin;
q[1] <= q[0];
q[2] <= q[1];
q[3] <= q[2];
q[4] <= q[3];
q[5] <= q[4];
q[6] <= q[5];
q[7] <= q[6];
end
end
endmodule
그러나 이 방법은 코드의 길이가 레지스터의 비트 수에 비례하여 커지므로, 좋은 코딩이라 할 수 없다. 다음과 같이 직렬입력을 받는 q[0]을 제외한 나머지를 벡터로 묶어서 하나의 nonblocking할당문으로 처리할 수 있으며, 다음과 같이 간결한 표현으로 모델링할 수 있다.
module shift_reg(clk,rst,sin,sout);
input clk,rst,sin;
output sout;
reg [7:0] q;
assign sout = q[7];
always@(posedge clk)begin
if(!rst) q <=8'b0;
else begin
q[0] <= sin;
q[7:1] <= q[6:0];
end
end
endmodule
▣ TESTBENCH
module tb_shift_reg;
reg clk,rst,sin;
wire sout;
integer i;
shift_reg u0(clk,rst,sin,sout);
always
#10 clk = ~clk;
initial begin
clk = 1'b0;
rst = 1'b1;
sin = 1'b0;
end
always begin
for(i=1;i<32;i=i+1)begin
#20 sin = i;
end
end
endmodule
★ 병렬입력 - 병렬출력 시프트 레지스터
다음은 active-low 동기식 reset을 갖는 병렬입력-병렬출력 시프트 레지스터이다. load=1이면 8비트 데이터 din이 병렬로 레지스터에 입력되고, load=0이면 시프트 레지스터로 동작한다. 레지스터를 구성하는 각 플립플롭의 출력이 병렬로 pout에 출력된다. 다음과 같은 코드로 모델링 될 수 있으며, if(load)조건문이 사용되었으며, load=0인 경우에는 왼족 시프트 동작을 구현하기 위하여 논리시프트 연산자 <<가 사용되었다.
module pld_shift_reg(clk, rst, load, din, pout);
input clk,rst,load;
input [7:0] din;
output [7:0] pout;
reg [7:0] data_reg;
assign pout = data_reg;
always@(posedge clk) begin
if(!rst) data_reg <= 7'b0;
else begin
if(load) data_reg <= din;
else data_reg <= data_reg << 1;
end
end
endmodule
▣ TESTBENCH
module tb_pld_shift_reg;
reg clk, rst, load;
reg [7:0] din;
wire [7:0] pout;
integer i;
pld_shift_reg uo(clk,rst,load,din,pout);
always
#10 clk = ~clk;
initial begin
clk = 1'b0;
rst = 1'b1;
din = 7'b0;
load = 1'b1;
#160 load = 1'b0;
end
always begin
for(i=1;i<8;i=i+1)begin
#20 din = i;
end
end
endmodule
★ 양방향 병렬포트를 갖는 시프트 레지스터
양방향 병렬포트를 가지며, 크기를 가변시킬 수 있는 시프트 레지스터의 설계 예를 살펴본다. 클럭의 상승엣지에서 왼쪽으로 1비트씩 시프팅되며, 직렬입력 si가 LSB플립플롭에 입력되고, 직렬출력 so는 MSB 플립플롭에서 출력된다. 데이터의 병렬 입-출력은 inout포트 data_io를 통해 이루어진다.
데이터의 병렬로드(wr=0)와 시프팅 동작(en=0)이 동시에 일어나지 않으며, data_io포트가 inout이므로 rd신호와 wr신호가 동시에 0이 되지 않는다.
다음 코드는 위 기능을 수행하는 Verilog modeling이다. 시프트 레지스터의 비트 수는 parameter문에 Len으로 선언되었고, 양방향 포트 data_io는 조건 연산자를 사용하여 모델링 되었다. rd=0일 때 시프트 레지스터의 값이 병렬로 출력된다.
high impedance상태는 parameter Len을 이용하여 {Len{1'bz}}로 표현하였다. 직렬출력 so는 레지스터의 MSB가 assign문으로 할당된다. 시프팅 동작은 always블록 내에 시프트 연산자 <<로 모델링되었다. if(!en) 조건문에 의해 왼쪽 시프팅 동작과 직렬입력 si가 레지스터의 LSB에 입력되며, else if(!wr)에 의해 data_io의 병렬입력이 레지스터에 로드된다.
module shifter(clk,rst,en,wr,rd,si,so,data_io);
parameter Len = 8;
input clk,rst,en,wr,rd,si;
output so;
inout [Len-1:0] data_io;
reg [Len-1:0] shift_reg;
assign so = shift_reg[7];
assign data_io = !rd ? shift_reg : {Len{1'bz}};
always@(posedge clk)begin
if(!rst) shift_reg <= {Len{1'b0}};
else begin
if(!en) begin
shift_reg <= shift_reg << 1;
shift_reg[0] <= si;
end
else if(!wr)
shift_reg <= data_io;
end
end
endmodule
▣ TESTBENCH
시뮬레이션 테스트벤치 작성을 위해서는 data_io가 inout포트이므로 data_io를 wire형으로 선언하고, initial블록에서 생성된 병렬 입력 값이 assign문을 통해 data_io에 할당되도록 한다. 레지스터 값을 병렬로 읽어내는 동안(rd=0인동안)에는 data_io를 high impedance상태로 유지해야한다. 또한 병렬로드(wr=0)와 시프팅 동작(en=0)이 동시에 일어나지 않도록 해야하며, rd신호와 wr신호가 동시에 0이 되지 않도록 테스트벤치를 작성해야한다.
module tb_shifter;
reg clk,rst,en,wr,rd,si;
wire so;
wire [7:0] data_io;
integer i;
shifter u0(clk,rst,en,wr,rd,si,so,data_io);
always
#10 clk = ~clk;
initial begin
clk=1'b0; rst=1'b0; en=1'b1; wr=1'b1; rd=1'b1; si=1'b0;
#60
rst=1'b1; en=1'b0;
// #60
// en=1'b1; rd=1'b0;
// #60
// rd=1'b1; wr=1'b0;
end
always begin
for(i=1;i<9;i=i+1)begin
#20 si = i;
end
end
endmodule
module tb_shifter;
reg clk,rst,en,wr,rd,si;
wire so;
wire [7:0] data_io;
integer i;
shifter u0(clk,rst,en,wr,rd,si,so,data_io);
always
#10 clk = ~clk;
assign data_io = 8'b00001111;
initial begin
clk = 1'b0; rst = 1'b0; en = 1'b1; wr = 1'b1; rd = 1'b1; si =1'b1;
#40 rst = 1'b1; wr = 1'b0;
#40 wr = 1'b1; en = 1'b0;
end
always begin
for(i=1;i<7;i=i+1)begin
#20 si = i;
end
end
endmodule
rst=0주어서 shift_reg초기화 시켜준 뒤 #40지연시간이 흐른 후 리셋을 풀어주고 wr=1'b0을 주어 병렬 로드 시킨다. 여기서 shift_reg값은 data_io값인 00001111의 값이 들어간다. 또 #40의 지연시간이 흐른뒤 부터 en=0으로 주어 병렬로드된 00001111값이 왼쪽으로 매 클럭마다 한킨씩 시프팅 되고 오른쪽은 si값이 계속해서 들어간다.
'UVM & RTL > Verilog HDL' 카테고리의 다른 글
[30] Verilog HDL 순차회로( Counter ) (0) | 2022.03.05 |
---|---|
[29] Verilog HDL 순차회로 설계과제 (시프트 레지스터) (0) | 2022.03.05 |
[27] Verilog HDL blocking할당문과 nonblocking할당문 설계과제 (2) | 2022.03.05 |
[26] Verilog HDL 순차회로에서 blocking할당문과 nonblocking할당문 (0) | 2022.03.05 |
[25] Verilog HDL 순차회로 설계과제 (LATCH, FILP FLOP) (0) | 2022.03.05 |
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!