概述
目录
- 1 简单的移位寄存器
- 1.1 构建一个4位移位寄存器
- 1.2 构建一个100位的左/右旋转器
- 1.3 建立一个64位算术移位寄存器
- 2 线性反馈移位寄存器(重要)
- 2.1 构建5位最大长度的Galois LFSR
- 2.2 LFSR的示例
- 2.3 构建32位Galois LFSR
- 2.4 移位寄存器电路的实现
- 2.5 设计一个用于8x1存储器的电路
1 简单的移位寄存器
1.1 构建一个4位移位寄存器
构建一个4位移位寄存器(右移位),具有异步置位、同步置数和使能。
areset:将移位寄存器置零。
load:用data[3:0]载入移位寄存器而不是移位。
ena:向右移位(q[3]变为零,q[0]被移出去,消失)。
q:移位寄存器的输出。
如果load和ena同时输入为1,则load具有更高的优先级。
solution:
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
q <= q;
end
endmodule
official solution:
module top_module(
input clk,
input areset,
input load,
input ena,
input [3:0] data,
output reg [3:0] q);
// Asynchronous reset: Notice the sensitivity list.
// The shift register has four modes:
// reset
// load
// enable shift
// idle -- preserve q (i.e., DFFs)
always @(posedge clk, posedge areset) begin
if (areset) // reset
q <= 0;
else if (load) // load
q <= data;
else if (ena) // shift is enabled
q <= q[3:1]; // Use vector part select to express a shift.
end
endmodule
1.2 构建一个100位的左/右旋转器
构建一个具有同步置数和左/右使能功能的100位左/右旋转器。旋转器从寄存器的一端移入另一端移出的位,这与移位器丢弃移出的位并移入零不同。 如果使能端有效,旋转器将旋转这些位,并且不会修改/丢弃这些位。
load:向移位寄存器置入data[99:0],而不是旋转。
ena[1:0]:选择是否旋转以及旋转方向:
- 2’b01向右旋转一位
- 2’b10向左旋转一位
- 2’b00和2’b11不旋转
q :旋转器的输出。
solution:
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 begin
case (ena)
2'b01: q <= {q[0],q[99:1]};
2'b10: q <= {q[98:0],q[99]};
default: q <= q;
endcase
end
end
endmodule
1.3 建立一个64位算术移位寄存器
建立一个具有同步负载的64位算术移位寄存器。移位器可以向左和向右移位1或8位的位置(按数量选择)。
算术右移将移位寄存器中数字的符号位(在这种情况下为q [63])移位,而不是通过逻辑右移完成的零移位。
关于算术右移的另一种思考方式是,它假定要移位的数字是带符号的并保留符号,以便算术右移将带符号的数除以2的幂。
逻辑左移和算术左移之间没有区别。
load:向移位寄存器加载数据[63:0],而不是进行移位。
ena:选择是否移动。
amount:选择要移动的方向和移动量:
- 2’b00:向左移1位。
- 2’b01:向左移8位。
- 2’b10:右移1位。
- 2’b11:向右移8位。
提示:5位数字11000算术右移1是11100,而逻辑右移将产生01100。
类似地,算术右移1的5位数字01000算术右移为00100,并且逻辑右移将产生相同的结果,因为原始数字为非负数。
关于算术移位和逻辑移位,可以看这篇文章,注意:
- 左移的规则:丢弃最高位,0补最低位;
- 算术右移的规则:按二进制形式把所有的数字向右移动对应的位数,低位移出(舍弃),高位的空位补符号位;
- 逻辑右移的规则:忽略了符号位扩展,0补最高位,填充时不管左边的数字是正是负都用0来填充。
solution:
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 begin
if (ena) begin
case(amount)
2'b00: q <= {q[62:0],1'b0};
2'b01: q <= {q[55:0],8'b0};
2'b10: q <= {q[63],q[63:1]};
2'b11: q <= {{8{q[63]}},q[63:8]};
default: q <= q;
endcase
end
else
q <= q;
end
end
endmodule
2 线性反馈移位寄存器(重要)
2.1 构建5位最大长度的Galois LFSR
线性反馈移位寄存器,即linear feedback shift register(LFSR),是通常带有几个XOR门的移位寄存器,以产生移位寄存器的下一个状态。 Galois LFSR是一种特殊的设置,其中带有“抽头tap”的位与输出位进行异或运算以产生其下一个值,而没有移动“tap”位位置。如果仔细选择tap位置,LFSR可以设为“最大长度”。n位的最大长度LFSR在重复之前循环经过2n-1个状态(永远不会达到全零状态)。
下图显示了一个5位最大长度的Galois LFSR,在位置5和3处有抽头,即tap(抽头“tap”位置通常从1开始编号)。
请注意,为保持一致性,我在位置5处绘制了XOR门,但XOR门输入之一为0。
提示:从1开始的前几个状态是00001、10100、01010、00101,… LFSR在返回00001之前应循环经过31个状态。
这道题目关键在于理解这句话:Galois LFSR是一种特殊的设置,其中带有“抽头tap”的位与输出位进行异或运算以产生其下一个值,而没有移动“tap”位位置。
solution:
module top_module(
input clk,
input reset, // Active-high synchronous reset to 5'h1
output [4:0] q
);
integer i;
always @(posedge clk) begin
if (reset)
q <= 5'b00001;
else begin
q <= {q[0],q[4],q[3]^q[0],q[2],q[1]};
end
end
endmodule
official solution(⭐️):
module top_module(
input clk,
input reset,
output reg [4:0] q);
reg [4:0] q_next; // q_next is not a register
// Convenience: Create a combinational block of logic that computes
// what the next value should be. For shorter code, I first shift
// all of the values and then override the two bit positions that have taps.
// A logic synthesizer creates a circuit that behaves as if the code were
// executed sequentially, so later assignments override earlier ones.
// Combinational always block: Use blocking assignments.
always @(*) begin
q_next = q[4:1]; // Shift all the bits. This is incorrect for q_next[4] and q_next[2]
q_next[4] = q[0]; // Give q_next[4] and q_next[2] their correct assignments
q_next[2] = q[3] ^ q[0];
end
// This is just a set of DFFs. I chose to compute the connections between the
// DFFs above in its own combinational always block, but you can combine them if you wish.
// You'll get the same circuit either way.
// Edge-triggered always block: Use non-blocking assignments.
always @(posedge clk) begin
if (reset)
q <= 5'h1;
else
q <= q_next;
end
endmodule
2.2 LFSR的示例
为下面这一时序电路(该电路在这里出现过)编写Verilog代码(可以使用子模块,但顶层必须命名为top_module)。 假设将在DE1-SoC板上实现该电路, 将R输入连接到SW开关,将Clock连接到KEY [0],将L输入到KEY [1],将Q输出连接到红灯LEDR。
提示:该电路是线性反馈移位寄存器(LFSR)的示例。最大周期LFSR可用于生成伪随机数,因为它在重复之前会循环2n-1个组合。全零组合不会出现在此序列中。
solution:
module top_module (
input [2:0] SW, // R
input [1:0] KEY, // L and clk
output [2:0] LEDR); // Q
wire [2:0] temp;
assign temp = KEY[1] ? SW : {LEDR[2]^LEDR[1],LEDR[0],LEDR[2]};
always @(posedge KEY[0]) begin
LEDR <= temp;
end
endmodule
2.3 构建32位Galois LFSR
在位32、22、2和1处用抽头构建32位Galois LFSR。
提示:这足够长,以至于您要使用向量,而不是32个DFF实例化。
module top_module(
input clk,
input reset, // Active-high synchronous reset to 32'h1
output [31:0] q
);
reg [31:0] q_next;
always @(*) begin
q_next <= q[31:1];
q_next[31] <= q[0];
q_next[21] <= q[22]^q[0];
q_next[1] <= q[2]^q[0];
q_next[0] <= q[1]^q[0];
end
always @(posedge clk) begin
if (reset)
q <= 32'h1;
else
q <= q_next;
end
endmodule
2.4 移位寄存器电路的实现
实现下面的电路:
这里我采用的是例化D触发器的方式,官方给的参考利用的是移位寄存器的方法,更加简洁。
solution:
module top_module(
input clk,
input resetn, // synchronous reset
input in,
output out);
reg q1,q2,q3,q4;
DFF d1 (clk,resetn,in,q1);
DFF d2 (clk,resetn,q1,q2);
DFF d3 (clk,resetn,q2,q3);
DFF d4 (clk,resetn,q3,q4);
always @(posedge clk) begin
if (resetn)
out <= 0;
else
out <= q4;
end
endmodule
module DFF(
input clk,
input resetn,
input in,
output q);
always @(posedge clk) begin
if (resetn)
q <= 0;
else
q <= in;
end
endmodule
official solution(⭐️):
module top_module (
input clk,
input resetn,
input in,
output out
);
reg [3:0] sr;
// Create a shift register named sr. It shifts in "in".
always @(posedge clk) begin
if (~resetn) // Synchronous active-low reset
sr <= 0;
else
sr <= {sr[2:0], in};
end
assign out = sr[3]; // Output the final bit (sr[3])
endmodule
考虑如下所示的n位移位寄存器电路:
假设n = 4,则为移位寄存器编写一个顶级Verilog模块(名为top_module)。在该顶级模块中实例化MUXDFF子电路的四个副本。假设我们要在DE2板上实现该电路。
- 将R输入连接到SW开关,
- clk连接到KEY [0],
- E连接到KEY [1],
- L连接到KEY [2],
- w连接到KEY [3],
- 将输出连接到红灯LEDR [3:0]
solution:
module top_module(
input [3:0] SW,
input [3:0] KEY,
output [3:0] LEDR
); //
MUXDFF m0 (KEY[0],KEY[1],KEY[2],KEY[3],SW[3],LEDR[3]);
MUXDFF m1 (KEY[0],KEY[1],KEY[2],LEDR[3],SW[2],LEDR[2]);
MUXDFF m2 (KEY[0],KEY[1],KEY[2],LEDR[2],SW[1],LEDR[1]);
MUXDFF m3 (KEY[0],KEY[1],KEY[2],LEDR[1],SW[0],LEDR[0]);
endmodule
module MUXDFF(
input clk,
input E,
input L,
input w,
input R,
output q
);
wire temp0,temp1;
assign temp0 = E ? w : q;
assign temp1 = L ? R : temp0;
always @(posedge clk) begin
q <= temp1;
end
endmodule
2.5 设计一个用于8x1存储器的电路
⭐️
在这个问题中,您将设计一个用于8x1存储器的电路,该存储器的写入是通过移入位完成的,而读取是“随机访问”,就像在典型的RAM中一样。然后,使用该电路实现3输入逻辑功能。
首先,创建一个带有8位D型触发器的8位移位寄存器。标记触发器的输出为Q[0]… Q [7]。
移位寄存器输入应称为S,它输入Q [0]的输入(MSB首先移入)。
enable输入控制是否移动。
然后,将电路扩展为具有3个附加输入A,B,C和输出Z。电路的行为应如下:
当ABC为000时,Z = Q [0],当ABC为001时,Z = Q [1 ], 等等。
电路应仅包含8位移位寄存器和多路复用器。(此外:该电路称为3输入查找表(LUT))。
这道题突破口在于:该存储器的写入是通过移入位完成的,并且是先从低位输入的。
module top_module (
input clk,
input enable,
input S,
input A, B, C,
output Z);
wire [2:0] abc;
reg [7:0] temp;
assign abc = {A,B,C};
assign Z = temp[abc];
always @(posedge clk) begin
if (enable)
temp <= {temp[6:0],S};
else
temp <= temp;
end
endmodule
official solution(⭐️):
module top_module (
input clk,
input enable,
input S,
input A, B, C,
output reg Z
);
reg [7:0] q;
// The final circuit is a shift register attached to a 8-to-1 mux.
// Create a 8-to-1 mux that chooses one of the bits of q based on the three-bit number {A,B,C}:
// There are many other ways you could write a 8-to-1 mux
// (e.g., combinational always block -> case statement with 8 cases).
assign Z = q[ {A, B, C} ];
// Edge-triggered always block: This is a standard shift register (named q) with enable.
// When enabled, shift to the left by 1 (discarding q[7] and and shifting in S).
always @(posedge clk) begin
if (enable)
q <= {q[6:0], S};
end
endmodule
最后
以上就是孝顺棉花糖为你收集整理的HDLBits-Circuits学习小结(六)移位寄存器(shift registers)1 简单的移位寄存器2 线性反馈移位寄存器(重要)的全部内容,希望文章能够帮你解决HDLBits-Circuits学习小结(六)移位寄存器(shift registers)1 简单的移位寄存器2 线性反馈移位寄存器(重要)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复