本篇文章介绍CPU的核心部件之一:桶式移位器,简称BS,英文全称为Barrel Shifter
桶式移位器最大的特点就是能在单周期内完成多种方式,各种位数的移位操作
常见的移位操作种类如下:
下面这张图是我从网上找的,链接地址在这里
这张图可以非常形象的说明桶形移位器的电路逻辑,先对里面的各种值进行一下说明:
用公式表示输出$$KaTeX parse error: Can't use function '$' in math mode at position 5: in2i$?为: in2i = Sin2 \cdot ai+\overline {Sin2}\cdot D0/1$$
i n 2 in2 in2的作用可以描述如下:
我们按照上图的标记进行分析,以 a 7 a7 a7位为例,因为是循环右移,所以我们先把对应的值确定一下:
接下来看流程,为了方便,我们再次拷贝一下上面的图:
下面给出桶式移位器的C语言描述,git地址
extern long bs(long in_1,long type,long num);
extern void bs_test(void);
#include "alu.h"
long bs(long in_1,long type,long num)
{
long sin1=0;// 右移才会为1
long sin2=0;// 左移/循环右移才会为1
long sin3=0;// 右移才会为1
long d0=0; // 右移才有意义,逻辑右移为0,算术右移为最高位
num%=(sizeof(long)*8);
switch (type) {
case 0:// 逻辑左移
sin1=0;
sin2=1;
sin3=0;
d0=0;
num =(sizeof(long)*8-num);
break;
case 1:// 逻辑右移
sin1=1;
sin2=0;
sin3=1;
d0=0;
break;
case 2:// 算术右移
sin1=1;
sin2=0;
sin3=1;
d0=in_1>>(sizeof(long)*8-1);
break;
case 3:// 循环右移
sin1=1;
sin2=1;
sin3=1;
d0=0;
break;
default:
break;
}
// 每个位都会输出,为了左移或者循环右移
long a = in_1;
// 默认输出为0,只有发生移动才会有值
long in1 = 0;
// 计算in1的输出,如果不是右移,原样输出
// 使用-1来表示位都是1的情况
if(sin1!=0)
{
unsigned long temp = in_1;
in1 = (temp>>num);
}
// 下面的三步走的in2的电路
long in2_1 = alu_and(a, sin2==0?0:-1, sizeof(long)*8);
long in2_2 = alu_and(sin3, d0, sizeof(long)*8);
long in2 = alu_or(in2_1, in2_2==0?0:-1, sizeof(long)*8);
in2 <<=(sizeof(long)*8-num);
return in2|in1;
}
下面是一个测试例子:
void bs_test(void)
{
printf("bs test start:\n");
for(int i = 0;i<sizeof(long)*8;i++)
{
long r1 = bs(1, 0, i);
printf("\t1 move left %d:%ld\n",i,r1);
}
for(int i = 0;i<sizeof(long)*8+1;i++)
{
long r1 = bs(-1, 1, i);
printf("\t1 move right logic %d:%ld\n",i,r1);
}
for(int i = 0;i<sizeof(long)*8+1;i++)
{
long r1 = bs(-1, 2, i);
printf("\t1 move right arithmetic %d:%ld\n",i,r1);
}
long a = 0xAAAAAAAAAAAAAAAA;
for(int i = 0;i<sizeof(long)*8+1;i++)
{
long r1 = bs(a, 3, i);
printf("\t1 move right loop %d:%ld\n",i,r1);
}
printf("bs test end\n");
}