移位器
一位可控移位器
其实是一个复杂的多路开关电路,根据不同控制信号,将输入左移或右移或不变。多位的移位可以简单串联这样的单元实现,但移位位数多时,该方法过于复杂,不实用并且速度很慢。
桶形移位器
由晶体管阵列构成,行数等于数据字长,列数等于最大移位宽度。
特点:
- Sh0-Sh3 只能有一位是高电平,分别控制A右移0位-3位
- 自动支持符号位扩展
- 信号最多只需要通过一个传输门,也就是说传播延时理论上是常数,与位数和规模无关(实际上因为缓冲器输入电容会随着移位宽度线性增加,所以延时不会是常数)
- 版图尺寸不由晶体管决定,而是通过布线数目或者所金属线的间距决定。
- 适用于移位数较小的移位器。
3.3 对数移位器
桶形移位器实现为传输管的单个阵列,而对数移位器采用分级的方法。移位值分解为几个2的指数值。
- 对数移位器的速度取决于移位宽度,一个M位的移位器需要 l o g 2 M log_2M log2M级
- 适用于较大的移位值,在速度和面积上都更有效,且容易参数化。
版图:
代码简易实现
Verilog实现
针对16位数据进行左移位,使用对数桶形结构
module log_barrel_shifter_left(input [15:0]ip, input [3:0]shift, output [15:0]op);
wire [15:0] st1, st2, st3;
assign st1[0] = shift[0]? 1'b0: ip[0];
assign st1[1] = shift[0]? ip[0]: ip[1];
assign st1[2] = shift[0]? ip[1]: ip[2];
assign st1[3] = shift[0]? ip[2]: ip[3];
assign st1[4] = shift[0]? ip[3]: ip[4];
assign st1[5] = shift[0]? ip[4]: ip[5];
assign st1[6] = shift[0]? ip[5]: ip[6];
assign st1[7] = shift[0]? ip[6]: ip[7];
assign st1[8] = shift[0]? ip[7]: ip[8];
assign st1[9] = shift[0]? ip[8]: ip[9];
assign st1[10] = shift[0]? ip[9]: ip[10];
assign st1[11] = shift[0]? ip[10]: ip[11];
assign st1[12] = shift[0]? ip[11]: ip[12];
assign st1[13] = shift[0]? ip[12]: ip[13];
assign st1[14] = shift[0]? ip[13]: ip[14];
assign st1[15] = shift[0]? ip[14]: ip[15];
assign st2[0] = shift[1]? 1'b0: st1[0];
assign st2[1] = shift[1]? 1'b0: st1[1];
assign st2[2] = shift[1]? st1[0]: st1[2];
assign st2[3] = shift[1]? st1[1]: st1[3];
assign st2[4] = shift[1]? st1[2]: st1[4];
assign st2[5] = shift[1]? st1[3]: st1[5];
assign st2[6] = shift[1]? st1[4]: st1[6];
assign st2[7] = shift[1]? st1[5]: st1[7];
assign st2[8] = shift[1]? st1[6]: st1[8];
assign st2[9] = shift[1]? st1[7]: st1[9];
assign st2[10] = shift[1]? st1[8]: st1[10];
assign st2[11] = shift[1]? st1[9]: st1[11];
assign st2[12] = shift[1]? st1[10]: st1[12];
assign st2[13] = shift[1]? st1[11]: st1[13];
assign st2[14] = shift[1]? st1[12]: st1[14];
assign st2[15] = shift[1]? st1[13]: st1[15];
assign st3[0] = shift[2]? 1'b0: st2[0];
assign st3[1] = shift[2]? 1'b0: st2[1];
assign st3[2] = shift[2]? 1'b0: st2[2];
assign st3[3] = shift[2]? 1'b0: st2[3];
assign st3[4] = shift[2]? st2[0]: st2[4];
assign st3[5] = shift[2]? st2[1]: st2[5];
assign st3[6] = shift[2]? st2[2]: st2[6];
assign st3[7] = shift[2]? st2[3]: st2[7];
assign st3[8] = shift[2]? st2[4]: st2[8];
assign st3[9] = shift[2]? st2[5]: st2[9];
assign st3[10] = shift[2]? st2[6]: st2[10];
assign st3[11] = shift[2]? st2[7]: st2[11];
assign st3[12] = shift[2]? st2[8]: st2[12];
assign st3[13] = shift[2]? st2[9]: st2[13];
assign st3[14] = shift[2]? st2[10]: st2[14];
assign st3[15] = shift[2]? st2[11]: st2[15];
assign op[0] = shift[3]? 1'b0: st3[0];
assign op[1] = shift[3]? 1'b0: st3[1];
assign op[2] = shift[3]? 1'b0: st3[2];
assign op[3] = shift[3]? 1'b0: st3[3];
assign op[4] = shift[3]? 1'b0: st3[4];
assign op[5] = shift[3]? 1'b0: st3[5];
assign op[6] = shift[3]? 1'b0: st3[6];
assign op[7] = shift[3]? 1'b0: st3[7];
assign op[8] = shift[3]? st3[0]: st3[8];
assign op[9] = shift[3]? st3[1]: st3[9];
assign op[10] = shift[3]? st3[2]: st3[10];
assign op[11] = shift[3]? st3[3]: st3[11];
assign op[12] = shift[3]? st3[4]: st3[12];
assign op[13] = shift[3]? st3[5]: st3[13];
assign op[14] = shift[3]? st3[6]: st3[14];
assign op[15] = shift[3]? st3[7]: st3[15];
endmodule
tb代码:
`timescale 1ns / 1ps
module tb_log_barrel_shifter_left;
// log_barrel_shifter_left Parameters
parameter PERIOD = 10;
// log_barrel_shifter_left Inputs
reg [15:0] ip = 0 ;
reg [3:0] shift = 0 ;
// log_barrel_shifter_left Outputs
wire [15:0] op ;
initial
begin
#(PERIOD*2) ip = 16'd5;
#(PERIOD*2) shift = 2;
#(PERIOD*2) shift = 3;
#(PERIOD*2) shift = 4;
#(PERIOD*2) shift = 5;
#(PERIOD*2) shift = 6;
#(PERIOD*2) shift = 7;
#(PERIOD*2) shift = 9;
end
log_barrel_shifter_left u_log_barrel_shifter_left (
.ip ( ip [15:0] ),
.shift ( shift [3:0] ),
.op ( op [15:0] )
);
initial
begin
#1000
$finish;
end
endmodule
仿真结果