桶式移位器

本文详细介绍了CPU核心部件中的桶式移位器(BS),包括其工作原理、常见的移位操作类型以及如何通过C语言实现。文章以案例分析和代码示例展示了循环右移的操作过程。
摘要由CSDN通过智能技术生成

前言

本篇文章介绍CPU的核心部件之一:桶式移位器,简称BS,英文全称为Barrel Shifter
桶式移位器最大的特点就是能在单周期内完成多种方式,各种位数的移位操作

常见的移位操作

常见的移位操作种类如下:

  • 算术右移
    是指数据向右移位,左侧用符号位补齐
  • 逻辑右移
    是指数据向右移位,左侧用0补齐
  • 算术左移和逻辑左移
    是指数据向左移动,右侧用0补齐
  • 循环右移
    是指数据向右移动,左侧用用测移出的位补齐
    比如1011 0101,循环右移两位就会变成 0110 1101
    注意:循环左移可以通过循环右移来实现,对于n位数据,循环左移m位就相当于循环右移n-m位

桶形移位器的实现方式

下面这张图是我从网上找的,链接地址在这里
在这里插入图片描述

这张图可以非常形象的说明桶形移位器的电路逻辑,先对里面的各种值进行一下说明:

  • S C i SCi SCi:表示移位的位数,对于支持n位移位的移位器来说,有n个 S C i SCi SCi,如果想要移动m位,只需要 S C m SCm SCm设置为1,别的 S C i SCi SCi为0即可。
  • a i ai ai:输入的待移位的数的二进制位,对于64位的移位器,需要64个输入
  • a ′ i a'i ai:输出的移位的数的二进制位,对于64位的移位器,需要64个输出
  • S i n 1 Sin1 Sin1:输入的移位标志,右移为1,左移为0
  • i n 1 in1 in1:一个逻辑与门,输入端为 a i ai ai S i n 1 Sin1 Sin1,表示的意思是右移时输出为 a i ai ai,左移时输出为0
  • D 0 / 1 D0/1 D0/1:右移时左侧填补的位,如果是算术右移就连接的是 a i ai ai的最高位,逻辑右移就是0
  • S i n 2 Sin2 Sin2:左移或者循环右移的时候为1,否则为0
  • S i n 2 ‾ \overline {Sin2} Sin2: S i n 2 Sin2 Sin2的非
  • i n 2 in2 in2:由两个与门一个或门组成的逻辑电路,如下图所示:
    在这里插入图片描述

用公式表示输出$$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的作用可以描述如下:

  • 右移时为0或者符号位,去填补左侧移出的空位
  • 左移时为输入值,用于实现左移,在到达 i n 2 in2 in2之前没有左移的逻辑

案例分析: 循环右移两位

我们按照上图的标记进行分析,以 a 7 a7 a7位为例,因为是循环右移,所以我们先把对应的值确定一下:

  • 循环右移, S i n 1 Sin1 Sin1=1,所以 i n 1 in1 in1 a 7 a7 a7的输出为1
  • 循环右移, S i n 2 Sin2 Sin2=1, S i n 2 ‾ \overline {Sin2} Sin2=0, D 0 / 1 D0/1 D0/1不重要了,因为 S i n 2 ‾ \overline {Sin2} Sin2=0,所以 S i n 2 ‾ ⋅ D 0 / 1 \overline {Sin2}\cdot D0/1 Sin2D0/1=0,也就是 i n 2 in2 in2的值完全取决于 a i ai ai
  • 右移两位,所以 S C 2 SC2 SC2==1,其余都为0

接下来看流程,为了方便,我们再次拷贝一下上面的图:
在这里插入图片描述

  • i n 1 in1 in1 a 7 a7 a7的输出 i n 1 in1 in1的值
  • 跟着电路走,直到到 S C 2 SC2 SC2接触点的时候,因为 S C 2 SC2 SC2=1,所以开关接通
  • a 7 a7 a7的值从 a ′ 5 a'5 a5输出
  • 同理
    a 7 a7 a7的值从 a ′ 5 a'5 a5输出
    a 6 a6 a6的值从 a ′ 4 a'4 a4输出
    a 5 a5 a5的值从 a ′ 3 a'3 a3输出
    a 4 a4 a4的值从 a ′ 2 a'2 a2输出
    a 3 a3 a3的值从 a ′ 1 a'1 a1输出
    a 2 a2 a2的值从 a ′ 0 a'0 a0输出
  • 然后看 a 1 a1 a1,虽然在 i n 1 in1 in1也输出了 a 1 a1 a1的值,但是没有到 S C 2 SC2 SC2就已经跑出电路了,另一条输出到了上面的 a 1 a1 a1,进入 i n 2 in2 in2电路,此时根据上面的数值我们知道 i n 2 in2 in2电路输出 a 1 a1 a1的值,然后该值沿着电路往左下方走,直到到 S C 2 SC2 SC2,因为 S C 2 SC2 SC2=1,所以开关接通, a 1 a1 a1的值从 a ′ 7 a'7 a7输出
  • 同理,我们可以分析 a 0 a0 a0的值从 a ′ 6 a'6 a6输出
  • 这样,循环右移便完成了。

C语言描述

下面给出桶式移位器的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");
}
  • 27
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Logisim是一个数字电路模拟,可以用来设计和模拟数字电路。下面是一个简单的移位电路的实现: 首先,我们需要一个输入端口来接收要移位的数据,还需要两个控制端口,一个用来选择向左移位还是向右移位,另一个用来选择移位的位数。 接下来,我们可以使用多个触发(flip-flop)来实现移位电路。为了方便起见,在这里我们将使用D触发。 假设我们要实现一个向左移位移位,我们可以按照以下步骤设计电路: 1. 将输入数据连接到最左侧的D触发的D输入端口。 2. 将第一个D触发的时钟端口与控制端口相连,以便控制移位何时开始移位。 3. 将第一个D触发的Q输出端口连接到第二个D触发的D输入端口。 4. 将第二个D触发的时钟端口连接到第一个D触发的Q输出端口,以便在第一个D触发的值移入第二个D触发之后,第二个D触发可以将值移入第三个D触发,以此类推。 5. 将最右侧D触发的Q输出端口连接到输出端口,以便输出移位后的结果。 6. 为了控制移位的位数,我们可以使用一个计数电路。将计数电路的输出端口连接到一个多路选择(mux)的控制端口,选择的输入端口是从第一个D触发开始到最后一个D触发的所有Q输出端口。 7. 将多路选择的输出端口连接到输出端口。 这样就完成了一个简单的向左移位移位电路。如果要实现向右移位,只需要将第一个D触发的D输入端口与最右侧的输入数据相连,将最右侧的D触发的Q输出端口连接到第一个D触发的D输入端口,以便将最右侧的值移入第一个D触发,其他部分的设计保持不变即可。 需要注意的是,在实际电路设计中,还需要考虑一些细节问题,如时序问题、输入输出阻抗匹配、信号干扰等,这些都需要进行详细的分析和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值