2.3 Shift Registers 移位寄存器
2.3.1 4-bit shift register [Shift4]
问题描述
构建一个4位移位寄存器(向右移位),具有同步重置,同步读取和使能。
- areset : 移位寄存器复位为0。
- load : 用data[3:0]的数据加载移位寄存器,而不是移位。
- ena : 向右移位(q[3]变成0,q[0]移出并消失)。
- q : 移位寄存器的内容
如果load和ena的输入均为高电平,load有更高优先级。
分析
首先注意areset是一个异步复位端= =。
代码
module top_module(
input clk,
input areset, // async active-high reset to zero
input load,
input ena,
input [3:0] data,
output reg [3:0] q);
always@(posedge clk or posedge areset) begin
if(areset)
q <= 0;
else if(load)
q <= data;
else if(ena)
q <= {1'b0,q[3:1]};
else begin
q <= q;
end
end
endmodule
2.3.2 left/right rotator [Rotate100]
问题描述
构建一个100位的左/右旋转器,具有同步load和左/右enable输入信号。当旋转器开始左移或者右移时,发生数据移动的时候不需要移除或者补零,而是让寄存器中的100位数据在启动后,在内部开始旋转移动数据并且不修改或丢弃他们。
- load: 用data[99:0]加载移位寄存器,而不是开始旋转。
- ena[1:0]:使能端,确定是否旋转以及旋转的方向
- 2’b01 向右侧旋转1位
- 2’b10 向左侧旋转1位
- 2’b00和2’b11 不发生旋转
- q:旋转器的内容
分析
实际上与上一题中普通的移位寄存器基本类似,只是在使能的判断与功能上发生一点变化。一是对使能端的条件分支多了左移和右移,可以利用case语句来区分;二是数据循环移位,移出的数据要放在空出的位置即右移时,移出的数据要放到数据的最左端;左移时,移出的数据放回到数据的最右端。
代码
module top_module(
input clk,
input load,
input [1:0] ena,
input [99:0] data,
output reg [99:0] q);
always@(posedge clk) begin
if(load)
q <= data;
else
case(ena)
2'b01 : q <= {q[0],q[99:1]};
2'b10 : q <= {q[98:0],q[99]};
default: q <= q;
endcase
end
endmodule
2.3.3 Left/right arithmetic shift by 1 or 8 [Shift18]
问题描述
构建一个64位算数移位寄存器,具有同步load信号。移位器可以向左和向右移动,可以同时移动1位或是8位,由amount信号决定。
算数右移中的数字符号位(本题中为q[63])的移位方式与逻辑右移的补0不同。它是将被移位的数据看作是有符号数且移位过程中保留符号,因此算数右移是将一个有符号数除以2的幂(可以参考有符号数字)
但是算数左移和逻辑左移之间没有区别
- load:将data[63:0]的数据载入,而不是移位
- ena:决定是否开始移位
- amuont:决定方向和移位的位数
- 2’b00:左移1位
- 2’b01:左移8位
- 2’b10:右移1位
- 2’b11:右移8位
- q: 移位寄存器中的内容
分析
区分算数右移和逻辑右移的区别即可。
算数右移的时候,空位不像逻辑右移一样补零,而是补填原数据的最高位(符号位),即正数补0、负数补1。
代码
module top_module(
input clk,
input load,
input ena,
input [1:0] amount,
input [63:0] data,
output reg [63:0] q);
always@(posedge clk) begin
if(load)
q <= data;
else if(ena==0)
q <= q;
else
case(amount)
2'b00 : q <= {q[62:0],1'b0};
2'b01 : q <= {q[55:0],{8{1'b0}}};
2'b10 : q <= {q[63],q[63:1]};
2'b11 : q <= {{8{q[63]}},q[63:8]};
default: q <= q;
endcase
end
endmodule
2.3.4 5-bit LFSR [Lfsr5]
问题描述
线性反馈移位寄存器(LFSR)通常具有几个异或门以产生下一个状态的移位寄存器。伽罗瓦LFSR是其中一种特定情况,它的tap(抽头)位置的比特与输出比特进行异或以产生下一个值,而没有抽头位置的比特则参与正常的移位。如果抽头的位置经过选择则可以将LFSR制定最大长度。重复之前LFSR的最大长度为2n-1。
下图显示了一个5位最大长度的伽罗瓦LFSR,其抽头位置位于第5位和第3位(抽头位置通常从1编号)。为了保持一致性,在位置5处绘制了异或门,但其中一个输入为0。
设计这个LFSR,复位信号使LFSR复位为1。
分析
使用D触发器,每个时钟周期之后,输出端数据更新为输入端数据,按照图描述即可
代码
module top_module(
input clk,
input reset, // Active-high synchronous reset to 5'h1
output reg [4:0] q
);
always@(posedge clk) begin
if (reset)
q <= 5'b00001;
else
q <= {0^q[0],q[4],q[3]^q[0],q[2],q[1]};
end
endmodule
2.3.5 3-bit LFSR [Mt2015 lfsr]
问题描述
为下图时序电路编写Verilog代码,假设您要在DE1-SOC板上完成该电路。将R输入链接到SW开关,将时钟连接到KEY[0],L连接到KEY[1],将Q输出连接到红灯LEDR。
提示
该电路是线性反馈移位寄存器的示例。最大周期LFSR可以用于生成伪随机数,因为他在重复之前循环了2n-1种组合,全零的序列也不会出现在此序列中。
分析
题目中有提到子模块,上图中具有三组相同电路连接,一个模块由2选1和D触发组成,具有时钟、使能、数据输入和数据输出五个端口
代码
module muxDff(
input r0,r1,
input clk,
input l,
output reg q
);
wire mux_out;
assign mux_out = l ? r1 : r0;
always@(posedge clk) begin
q <= mux_out;
end
endmodule
module top_module (
input [2:0] SW, // R
input [1:0] KEY, // L and clk
output [2:0] LEDR); // Q
muxDff mod0(.r0(LEDR[2]),.r1(SW[0]),.clk(KEY[0]),.l(KEY[1]),.q(LEDR[0]));
muxDff mod1(.r0(LEDR[0]),.r1(SW[1]),.clk(KEY[0]),.l(KEY[1]),.q(LEDR[1]));
muxDff mod2(.r0(LEDR[1] ^ LEDR[2]),.r1(SW[2]),.clk(KEY[0]),.l(KEY[1]),.q(LEDR[2]));
endmodule
2.3.6 32-bit LFSR [Lfsr32]
问题描述
以Lfsr5为例
建立一个32bit,抽头为32 22 2 1的伽罗瓦LFSR
分析
抽头在32 22 2 1 对应的抽头输出分别为0q[0]、q[22]q[0]、q[2]q[0]和q[1]q[0],其余部分正常移位输出即可。
代码
module top_module(
input clk,
input reset, // Active-high synchronous reset to 32'h1
output reg [31:0] q
);
always@(posedge clk) begin
if(reset)
q <= 32'h1;
else
q <= {0^q[0],q[31:23],q[22]^q[0],q[21:3],q[2]^q[0],q[1]^q[0]};
end
endmodule
2.3.7 Shift register [Exams/m2014 q4k]
问题描述
实现下列电路:
分析
四个D触发器共用同一个时钟,前一位的输出是后一位的输入,低电平复位。
代码
module top_module (
input clk,
input resetn, // synchronous reset
input in,
output out
);
reg [3:0] temp;
always@(posedge clk) begin
if(resetn==0)
temp <= 0;
else
temp <= {in,temp[3:1]};
end
assign out = temp[0];
endmodule
2.3.8 Shift register [Exams/2014 q4b]
问题描述
考虑如下所示的n位移位寄存器电路:
为移位寄存器编写一个顶层verilog模块,假设n=4,在顶层模块中实例化MUXDFF子电路四个副本。
- 将R输入与SW开关连接
- clk连接到KEY[0]
- E连接到KEY[1]
- L连接到KEY[2]
- w连接到KEY[3]
- 将输出连接到LEDR[3:0]
(2.1.12 Exams/2014 q4a 写过它的子模块)
分析
与前面题目类似,将整体电路分为四个相同模块,这些模块包含有两个数据选择器和一个D触发器,具有时钟、两个使能、数据输入和数据输出六个端口
代码
module MUXDFF (
input clk,
input w, R, E, L,
output Q
);
wire mux_out1,mux_out2;
assign mux_out1 = E ? w : Q;
assign mux_out2 = L ? R : mux_out1;
always@(posedge clk) begin
Q <= mux_out2;
end
endmodule
module top_module (
input [3:0] SW,
input [3:0] KEY,
output [3:0] LEDR
);
MUXDFF mod0(.clk(KEY[0]),.w(LEDR[1]),.R(SW[0]),.E(KEY[1]),.L(KEY[2]),.Q(LEDR[0]));
MUXDFF mod1(.clk(KEY[0]),.w(LEDR[2]),.R(SW[1]),.E(KEY[1]),.L(KEY[2]),.Q(LEDR[1]));
MUXDFF mod2(.clk(KEY[0]),.w(LEDR[3]),.R(SW[2]),.E(KEY[1]),.L(KEY[2]),.Q(LEDR[2]));
MUXDFF mod3(.clk(KEY[0]),.w(KEY[3]),.R(SW[3]),.E(KEY[1]),.L(KEY[2]),.Q(LEDR[3]));
endmodule
2.3.9 3-input LUT [Exams/ece241 2013 q12]
问题描述
这个问题中,你将设计一个8x1存储器的电路,其中写入存储器是通过移入来完成的,而读取时“随机访问”,类似于典型的RAM。然后你将使用这个电路实现3输入逻辑功能。
首先,用8个D触发器建立一个8位移位寄存器。将触发器的输出标记为Q[7:0]。移位寄存器的输入为S填充到最高位Q[0]。enable输入端控制是否移位。然后将电路扩展三个额外输入A、B、C,和一个输出Z。电路的行为如下:当ABC=000时Z=Q[0],当ABC=001时Z=Q[1],以此类推。您的电路应该只包含8位移位寄存器和多路复用器。(此电路称为3输入查找表(3-input LUT))
分析
按照题目意思,首先要构造一个8位移位寄存器,最低位Q[0]输出回到最前端D触发器的输入,包含有enable使能端控制。然后再利用多路复用器(case)按照ABC的对应情况给出Z的输出。
代码
module sr8(
input clk,
input enable,
input S,
output reg [7:0] Q
);
always@(posedge clk) begin
if(enable)
Q <= {Q[6:0],S};
else
Q <= Q;
end
endmodule
module top_module (
input clk,
input enable,
input S,
input A, B, C,
output reg Z );
wire [7:0] Q;
sr8 sReg_0(.clk(clk),.enable(enable),.S(S),.Q(Q));
always@(*) begin
case({A,B,C})
3'b000 : Z <= Q[0];
3'b001 : Z <= Q[1];
3'b010 : Z <= Q[2];
3'b011 : Z <= Q[3];
3'b100 : Z <= Q[4];
3'b101 : Z <= Q[5];
3'b110 : Z <= Q[6];
3'b111 : Z <= Q[7];
endcase
end
endmodule
这个系列主要是记录一下自己的学习过程和简单的思考过程,参考了许多他人的思路。题目均为HDLBits上的题目,借助翻译器与自己的理解组织了题目描述,如果有问题欢迎批评指正。