1. Shifter unit
Function unit에서 Shifter를 만들어본다.


opcode에서 10010 ~1111? 의 기능을 구현해야 한다. 즉, 1bit shift, arithmetic right shift, 1bit rotate, n-bit rotate(barrel shift)
를 구현해야 한다. 각각의 회로를 구현한 후 한 모듈에 합치는 방법도 있겠지만 더 효율적인 방법을 고안해보았다.
barrel shifter 회로에 logic을 추가하면 나머지 기능도 모두 구현 가능할 것 같았다.

위의 그림과 같이 먼저 right rotate하는 BR shifter를 생각했다. 31 bit짜리 tmp를 선언한 후 오퍼랜드(oprB) 값 16bit를 할당하고 그 뒤에 15bit를 할당한다. 그리고 16 bit 짜리 먹스 16개를 만들어서 그림과 같이 한 비트씩 shift되도록 할당한다.
그럼 결국 select 값에 따라, select값 만큼 rotate시킬 수 있게 된다. 예를 들어 1bit rotate 시키고 싶다면 sel = 0001을 주고 그렇게 되면 모든 MUX의 d1이 output으로 출력되고 결국 한 비트 rotate된 값이 출력되는 것이다.
이제 이를 기반으로 나머지도 구현할 수 있다.
module mux_unit (din, sel, dout);
parameter BW = 16;
input [3:0] sel;
input [BW-1:0] din;
output wire dout;
assign dout = din[sel];
endmodule
module shifter (mux_sel, oprB, sel_mode, Y);
parameter BW = 16;
input [BW-1:0] oprB;
input [3:0] mux_sel; //FS[0],SA[2:0]
input [2:0] sel_mode; // FS[3:1]
output [BW-1:0] Y;
reg [2*(BW-1):0] tmp;
reg [3:0] mux_tmp;
//assign tmp = {oprB[BW-2:0], oprB[BW-1 : 0]};
genvar i;
always @ (*)
begin
casex (sel_mode)
3'b000 :begin tmp = {oprB[BW-2:0], oprB[BW-1 : 0]}; mux_tmp = 4'b0000; end //hold
3'b001 :begin tmp = {oprB[BW-3:0],2'b0}; mux_tmp = 4'b0001; end //1bit shift left
3'b010 :begin tmp = {15'b0, oprB[BW-1:0]}; mux_tmp = 4'b0001; end //1bit shift right
3'b011 :begin tmp = {oprB[BW-1:15], oprB[15:0]}; mux_tmp = 4'b0001; end //arith shift right
3'b100 :begin tmp = {oprB[BW-2:0], oprB[BW-1 : 0]}; mux_tmp = 4'b1111;end //1bit rotate left
3'b101 : begin tmp = {oprB[BW-2:0], oprB[BW-1 : 0]}; mux_tmp = 4'b0001; end //1bit rotate right
3'b110 :begin tmp = {oprB[BW-2:0], oprB[BW-1 : 0]}; mux_tmp = mux_sel; end // rotate right
default :begin tmp = {oprB[BW-2:0], oprB[BW-1 : 0]}; mux_tmp = (16-mux_sel) ; end //rotate left //4'b111x
endcase
end
generate
for(i = 0; i<BW; i= i+1)begin : barrel
// mux #4 m (.select(mux_sel), .data(tmp[i+BW-1 : i]), .mux_out(Y[i]));
mux_unit m (.sel(mux_tmp), .din(tmp[i+BW-1 : i]), .dout(Y[i]));
end
endgenerate
endmodule
16 bit 짜리 MUX를 인스턴시에이션하여 generate ~ for문을 사용하여 16 bit MUX * 16개를 만들어주었다.
그리고 case문으로 sel_mode값 (FS[3:1])에 따라 기능을 선택할 수 있다. 1bit shift left/ right는 MSB, LSB 쪽에 0을 할당해서 1bit shift된 값으로 출력되게 만들었고, arith는 MSB 고정하고 1bit shfit right를 하도록 했다. 여기서 1bit만 움직이기 위해 mux select값에 1이 들어가도록 mux_tmp를 따로 선언하여 값을 주었다. 그리고 n-bit rotate값은 n-bit rotate를 위해 기존대로 mux_sel값을 할당했다. (FS[0],SA[2:0])
한 가지 느낀 점은 값을 할당할 때 bit수에 유의한다는 점이다. 할당된 비트를 전부 채우지 않았을 때 latch가 생기는 등 회로가 원하는대로 구현되지 않았다.
아래는 shifter 회로이다.

만약 1bit shift와 1bit rotate등의 회로를 각각 구현한 후 합쳤다면 리소스를 훨씬 많이 사용했을 텐데, 위와 같이 설계하였기 때문에 배럴쉬프트 MUX16개 앞에 MUX 2개와 연산로직 하나만 추가된 형태의 최적화된 회로를 구현할 수 있었다.
module tb_SFT;
reg [15:0] oprB;
reg [3:0] mux_sel;
reg [2:0] sel_mode;
wire [15:0] Y;
shifter BR1 (mux_sel, oprB, sel_mode, Y);
initial begin
sel_mode = 3'b000; mux_sel =4'b0011; oprB = 16'b1000_0000_0000_1111;
#10 sel_mode = 3'b001; mux_sel =4'b0011; oprB = 16'b1000_0000_0000_1111;
#10 sel_mode = 3'b010; mux_sel =4'b0011; oprB = 16'b1000_0000_0000_1111;
#10 sel_mode = 3'b011; mux_sel =4'b0011; oprB = 16'b1000_0000_0000_1111;
#10 sel_mode = 3'b100; mux_sel =4'b0011; oprB = 16'b1000_0000_0000_1111;
#10 sel_mode = 3'b101; mux_sel =4'b0011; oprB = 16'b1100_0000_0000_1111;
#10 sel_mode = 3'b110; mux_sel =4'b0011; oprB = 16'b1000_0000_0000_1111;
#10 sel_mode = 3'b111; mux_sel =4'b0011; oprB = 16'b1000_0000_0000_1111;
#10;
$stop;
end
endmodule


위와 같이 sel_mode에 따라 각 기능들이 정상적으로 동작했음을 확인하였다.
'[Harman교육] 베릴로그' 카테고리의 다른 글
| [23.03.27] CPU 제어 회로 및 설계 발표 (0) | 2023.03.27 |
|---|---|
| [23.03.23] CPU 설계 - datapath (1) | 2023.03.23 |
| [23.03.21] CPU 설계 - ALU unit (0) | 2023.03.21 |
| [23.03.20] CPU 설계 기초 (0) | 2023.03.20 |
| [23.03.17] 무어/ 밀리 모델 (0) | 2023.03.17 |