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에 따라 각 기능들이 정상적으로 동작했음을 확인하였다. 

+ Recent posts