1、题目描述:
本题目将学习常用的移位寄存器的设计,并实现在移位指令中需要用到的桶形移位器。
背景介绍:
移位寄存器在时钟的触发沿,根据其控制信号,将存储在其中的数据向某个方向移动一位。移位寄存器也是数字系统的常用器件。
下图中是一个由4个D触发器构成的简单向右移位寄存器,数据从移位寄存器的左端输入,每个触发器的内容在时钟的正跳变沿(上升沿)将数据传到下一个触发器。下表是一个此移位寄存器的序列传递实例。
下表描述了常见的移位寄存器工作方式。 其中左端串行输入1位数值,并行输出8位数值是指每个时钟到来时右移一位,并且移入的最左位由外部开关决定是1还是0,输出同其他情况一样为同时输出8位。 这个功能在进行串行转换为并行时比较有用,可以将时间上顺序输入的8个bit存入移位寄存器,在8个周期后形成一个8bit数一起输出。
控制位 | 工作方式 |
0 0 0 | 清0 |
0 0 1 | 置数 |
0 1 0 | 逻辑右移 |
0 1 1 | 逻辑左移 |
1 0 0 | 算术右移 |
1 0 1 | 左端串行输入1位值,并行输出8位值 |
1 1 0 | 循环右移 |
1 1 1 | 循环左移 |
移位寄存器的种类有很多,需要根据需求来设计。在CPU中比较常见的有32位移位寄存器。在移位操作中,按照前文所描述的移位方法,每个时钟周期只能进行一位的移位操作,当需要移位的位数较多时,就会导致很大的时间浪费。那么可不可以设计一种通用的寄存器,使得可以在较短的时间内实现不大于32次的任意次数的移位操作呢。
题目要求:
为了简化设计难度,要求设计一款能够在5个时钟周期完成不大于32次的任意次数的移位操作的32位循环移位寄存器,要求有异步置零、同步置数、左移、右移和保持原状态不变五个模式
接口描述:
输入端口:
data_in[31:0]:数据输入,待移位的32位数据
shift_bit[4:0]:移位位数,为一个不大于32的数字
clk:时钟输入
rst_n:复位信号,低电平有效
mode[1:0]:模式切换,00为保持,01为左移,10为右移,11为并行输入
en:使能信号,高电平有效
输出端口:
data_out[31:0]:数据输出
模块名称:shifter_32
提示:
可以考虑一下,为什么是32位,又为什么是5个时钟周期。2的5次方刚好等于32,是不是巧合呢?
如果需要写多个模块,将所有模块复制到提交框中提交,只需保证顶层模块为shifter_32即可。
2、Verilog代码:
module shifter_32(
input [31:0] data_in,//:数据输入,待移位的32位数据
input [4:0] shift_bit,//:移位位数,为一个不大于32的数字
input clk,//:时钟输入
input rst_n,//:复位信号,低电平有效
input [1:0] mode,//:模式切换,00为保持,01为左移,10为右移,11为并行输入
input en,//:使能信号,高电平有效
output reg [31:0] data_out//:数据输出
);
reg [31:0] barrel=0; //循坏移位寄存器
reg [31:0] temp=0;
reg [31:0] tmp_data_out[0:4]; //二维数组,深度5,宽度32
integer i;
initial begin //初始化,避免出现高阻值z。不可综合
for(i=0;i<=4;i++)
tmp_data_out[i]=0;
end
always@(posedge clk,negedge rst_n)begin
if(!rst_n)
barrel<=0;
else if(en)
case(mode) //根据mode,进行循环移位操作
2'b00:barrel<=barrel;
2'b01:{barrel,temp}<=({data_in,data_in}<<shift_bit);
2'b10:{temp,barrel}<=({data_in,data_in}>>shift_bit);
2'b11:barrel<=data_in;
endcase
end
always@(posedge clk,negedge rst_n)begin
if(!rst_n)
data_out<=0;
else if(en)
data_out<=tmp_data_out[4]; //输出五个周期前的移位操作
end
always@(posedge clk)begin
tmp_data_out[4]=tmp_data_out[3]; //串入串出寄存器,5个触发器实现
tmp_data_out[3]=tmp_data_out[2];
tmp_data_out[2]=tmp_data_out[1];
tmp_data_out[1]=tmp_data_out[0];
tmp_data_out[0]=barrel;
end
endmodule
实现的是一个当前输出为5个周期前的操作。运用到了循环移位寄存器和串入串出寄存器。
3、testbench:
module tb_shifter_32();
reg [31:0] data_in;//:数据输入,待移位的32位数据
reg [4:0] shift_bit;//:移位位数,为一个不大于32的数字
reg clk;//:时钟输入
reg rst_n;//:复位信号,低电平有效
reg [1:0] mode;//:模式切换,00为保持,01为左移,10为右移,11为并行输入
reg en;//:使能信号,高电平有效
wire [31:0] data_out;//:数据输出
shifter_32 U(data_in,shift_bit,clk,rst_n,mode,en,data_out);
initial begin
data_in=0;shift_bit=0;clk=0;rst_n=0;mode=0;en=0;
#10
data_in=0;shift_bit=0;clk=1;rst_n=0;mode=0;en=0;
#10
data_in=0;shift_bit=0;clk=0;rst_n=0;mode=0;en=0;
#10
data_in=0;shift_bit=0;clk=1;rst_n=0;mode=0;en=0;
#10
data_in=36;shift_bit=2;clk=0;rst_n=1;mode=3;en=1;
#10
data_in=36;shift_bit=2;clk=1;rst_n=1;mode=3;en=1;
#10
data_in=9;shift_bit=2;clk=0;rst_n=1;mode=3;en=1;
#10
data_in=9;shift_bit=2;clk=1;rst_n=1;mode=3;en=1;
#10
data_in=36;shift_bit=2;clk=0;rst_n=1;mode=3;en=1;
#10
data_in=36;shift_bit=2;clk=1;rst_n=1;mode=3;en=1;
#10
data_in=9;shift_bit=2;clk=0;rst_n=1;mode=3;en=1;
#10
data_in=9;shift_bit=2;clk=1;rst_n=1;mode=3;en=1;
#10
data_in=36;shift_bit=2;clk=0;rst_n=1;mode=3;en=1;
#10
data_in=36;shift_bit=2;clk=1;rst_n=1;mode=3;en=1;
#10
data_in=9;shift_bit=2;clk=0;rst_n=1;mode=3;en=1;
#10
data_in=9;shift_bit=2;clk=1;rst_n=1;mode=3;en=1;
#10
data_in=36;shift_bit=2;clk=0;rst_n=1;mode=3;en=1;
#10
data_in=36;shift_bit=2;clk=1;rst_n=1;mode=3;en=1;
#10
data_in=9;shift_bit=2;clk=0;rst_n=1;mode=3;en=1;
#10
data_in=9;shift_bit=2;clk=1;rst_n=1;mode=3;en=1;
#10
data_in=36;shift_bit=2;clk=0;rst_n=1;mode=3;en=1;
#10
data_in=36;shift_bit=2;clk=1;rst_n=1;mode=3;en=1;
#10
data_in=9;shift_bit=2;clk=0;rst_n=1;mode=3;en=1;
#10
data_in=9;shift_bit=2;clk=1;rst_n=1;mode=3;en=1;
end
initial begin
$dumpfile("test.vcd");
$dumpvars(0);
end
endmodule
波形图:
4、总结
通过此题,学会循环移位寄存器,加深对串入串出寄存器的认识。