关注👆 望森FPGA 👆 查看更多FPGA资讯
这是望森的第 14 期分享
作者 | 望森
来源 | 望森FPGA(ID:wangsenfpga)
转载请联系授权(微信ID:wangsen094)
目录
3 Left/right arithmetic shift by 1 or 8
本文中的代码都能够正常运行,请放心食用😋~
练习的官方网站是:https://hdlbits.01xz.net/
注:作者将每个练习的知识点都放在了题目和答案之后
1 4-bit shift register
题目:
构建一个 4 位移位寄存器(右移),具有异步复位、同步加载和启用功能。
-
areset:将移位寄存器复位为零。
-
load:用 data[3:0] 加载移位寄存器,而不是移位。
-
ena:右移(q[3] 变为零,q[0] 移出并消失)。
-
q:移位寄存器的内容。
如果 load 和 ena 输入均被置位(1),则 load 输入具有更高的优先级。
答案:
我的答案:
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) begin
q <= 4'd0;
end
else begin
case({load,ena})
2'b00 : q <= q;
2'b01 : q <= {1'b0,q[3:1]};
2'b10 : q <= data;
2'b11 : q <= data;
default q <= q;
endcase
end
end
endmodule
参考答案:
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
2 Left/right rotator
题目:
构建一个 100 位左/右旋转器,并具有同步加载和左/右启用功能。旋转器把移出的比特位从寄存器的另一端移入,而移位器则丢弃移出的位并移入零。如果启用,旋转器会旋转比特位,而不会修改/丢弃它们。
-
load:使用 data[99:0] 加载移位寄存器,而不是旋转。
-
ena[1:0]:选择是否旋转以及旋转方向。
-
2'b01 向右旋转一位
-
2'b10 向左旋转一位
-
2'b00 和 2'b11 不旋转。
-
-
q:旋转器的内容。
答案:
我的答案:
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) // load
q <= data;
else if (ena) begin
case(ena)
2'b00 : q <= q;
2'b01 : q <= {q[0],q[99:1]};
2'b10 : q <= {q[98:0],q[99]};
2'b11 : q <= q;
default q <= q;
endcase
end
else begin
q <= q;
end
end
endmodule
参考答案:
module top_module(
input clk,
input load,
input [1:0] ena,
input [99:0] data,
output reg [99:0] q);
// This rotator has 4 modes:
// load
// rotate left
// rotate right
// do nothing
// I used vector part-select and concatenation to express a rotation.
// Edge-sensitive always block: Use non-blocking assignments.
always @(posedge clk) begin
if (load) // Load
q <= data;
else if (ena == 2'h1) // Rotate right
q <= {q[0], q[99:1]};
else if (ena == 2'h2) // Rotate left
q <= {q[98:0], q[99]};
end
endmodule
知识点:
在时序always块中,输出保持不变的情况可以省略不写。
3 Left/right arithmetic shift by 1 or 8
题目:
构建一个 64 位算术移位寄存器,并进行同步加载。移位器可以左移和右移,并且可移动 1 位或 8 位,具体位置由 amount 选择。
算术右移将移位寄存器中的数字(本例中为 q[63])的符号位移入,而不是像逻辑右移那样移入零。算术右移的另一种思路是,它假设被移位的数字是有符号的,并保留符号,因此能通过算术右移将有符号数除以 2 的幂。
逻辑左移和算术左移之间没有区别,都是低位补0。
-
load:使用 data[63:0] 加载移位寄存器,而不是移位。
-
ena:选择是否移位。
-
amount:选择移位的方向和移位量。
-
2'b00:左移 1 位。
-
2'b01:左移 8 位。
-
2'b10:右移 1 位。
-
2'b11:右移8位。
-
-
q:移位器的内容。
答案:
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) // Load
q <= data;
else if (ena) begin
case (amount)
2'b00 : q <= {q[62:0],1'd0};
2'b01 : q <= {q[55:0],8'd0};
2'b10 : q <= {q[63],q[63:1]};
2'b11 : q <= {{8{q[63]}},q[63:8]};
endcase
end
end
endmodule
4 5-bit LFSR
题目:
线性反馈移位寄存器( LFSR —— linear feedback shift register )是一种通常带有几个 XOR 门的移位寄存器,用于产生移位寄存器的下一个状态。Galois LFSR 是一种特殊的布置,其中带有“抽头”的比特位置与输出位进行 XOR 以产生其下一个值,而没有抽头的位位置则移位。如果仔细选择抽头位置,则可以将 LFSR 设置为“最大长度”。n 位的最大长度 LFSR 在重复之前循环 2n-1 个状态(永远不会达到全零状态)。
下图显示了一个 5 位最大长度 Galois LFSR,其抽头位于位位置 5 和 3。(抽头位置通常从 1 开始编号)。请注意,为了保持一致性,我将 XOR 门绘制在位置 5,但其中一个 XOR 门输入为 0。
构建此 LFSR。reset 应将 LFSR 复位为 1。
答案:
我的答案:
module top_module(
input clk,
input reset, // Active-high synchronous reset to 5'h1
output [4:0] q
);
always @(posedge clk) begin
if (reset) // Load
q <= 4'd1;
else begin
q[4] <= 1'b0 ^ q[0];
q[3] <= q[4];
q[2] <= q[3] ^ q[0];
q[1] <= q[2];
q[0] <= q[1];
end
end
endmodule
参考答案:
module top_module(
input clk,
input reset,
output reg [4:0] q);
reg [4:0] q_next; // q_next 不是寄存器
// 便利:创建一个组合逻辑块,用于计算
// 下一个值应该是什么。对于较短的代码,我首先移位
// 所有值,然后覆盖具有抽头的两个位位置。
// 逻辑合成器创建一个电路,其行为就像代码是
// 按顺序执行的一样,因此后面的分配将覆盖前面的分配。
// 组合始终块:使用阻塞分配。
always @(*) begin
q_next = q[4:1]; // 移位所有位。对于 q_next[4] 和 q_next[2],这是不正确的
q_next[4] = q[0]; // 为 q_next[4] 和 q_next[2] 提供正确的分配
q_next[2] = q[3] ^ q[0];
end
// 这只是一组 DFF。我选择在其自己的组合 always 块中计算上述 DFF 之间的连接,但您可以根据需要将它们组合起来。
// 无论哪种方式,您都会得到相同的电路。
// 边沿触发 always 块:使用非阻塞分配。
always @(posedge clk) begin
if (reset)
q <= 5'h1;
else
q <= q_next;
end
endmodule
5 3-bit LFSR
题目:
为该顺序电路编写 Verilog 代码(子模块随意,但顶层必须命名为 top_module)。假设您要在 DE1-SoC 板上实现该电路。将 R 输入连接到 SW 开关,将 Clock 连接到 KEY[0],将 L 连接到 KEY[1]。将 Q 输出连接到红灯 LEDR。
答案:
module top_module (
input [2:0] SW, // R
input [1:0] KEY, // L and clk
output [2:0] LEDR); // Q
wire a_3;
MUX_DFF MUX_DFF_1(
.clk(KEY[0]),
.a(LEDR[2]),
.b(SW[0]),
.sel(KEY[1]),
.q(LEDR[0])
);
MUX_DFF MUX_DFF_2(
.clk(KEY[0]),
.a(LEDR[0]),
.b(SW[1]),
.sel(KEY[1]),
.q(LEDR[1])
);
MUX_DFF MUX_DFF_3(
.clk(KEY[0]),
.a(a_3),
.b(SW[2]),
.sel(KEY[1]),
.q(LEDR[2])
);
assign a_3 = LEDR[1] ^ LEDR[2];
endmodule
module MUX_DFF (
input clk,
input a,
input b,
input sel,
output q);
always@(posedge clk)begin
case(sel)
1'b0 : q <= a;
1'b1 : q <= b;
endcase
end
endmodule
6 32-bit LFSR
题目:
请参考Lfsr5,构建一个 32 位 Galois LFSR,其抽头位于位位置 32、22、2 和 1。
答案:
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[0] ^ q[22];
q_next[1] = q[0] ^ q[2];
q_next[0] = q[0] ^ q[1];
end
always @(posedge clk) begin
if (reset)
q <= 32'h1;
else
q <= q_next;
end
endmodule
7 Shift register
题目:
实现以下电路:
答案:
我的答案:
module top_module (
input clk,
input resetn, // synchronous reset
input in,
output out);
reg [3:0] q;
always @(posedge clk) begin
if (!resetn)
q <= 4'd0;
else begin
q[3] <= in;
q[2] <= q[3];
q[1] <= q[2];
q[0] <= q[1];
end
end
assign out = q[0];
endmodule
参考答案:
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
8 Shift register
题目:
考虑如下所示的 n 位移位寄存器电路:
为移位寄存器编写一个顶层 Verilog 模块(名为 top_module),假设 n = 4。在顶层模块中实例化 MUXDFF 子电路的四个副本。假设您要在 DE2 板上实现该电路。
-
将 R 输入连接到 SW 开关,
-
clk 连接到 KEY[0],
-
E 连接到 KEY[1],
-
L 连接到 KEY[2],
-
w 连接到 KEY[3]。
将输出连接到红灯 LEDR[3:0]。
(复用 exams/2014_q4a 中的 MUXDFF。)
答案:
module top_module (
input [3:0] SW,
input [3:0] KEY,
output [3:0] LEDR
); //
MUXDFF MUXDFF_0(
.clk(KEY[0]),
.w(KEY[3]),
.R(SW[3]),
.E(KEY[1]),
.L(KEY[2]),
.Q(LEDR[3])
);
MUXDFF MUXDFF_1(
.clk(KEY[0]),
.w(LEDR[3]),
.R(SW[2]),
.E(KEY[1]),
.L(KEY[2]),
.Q(LEDR[2])
);
MUXDFF MUXDFF_2(
.clk(KEY[0]),
.w(LEDR[2]),
.R(SW[1]),
.E(KEY[1]),
.L(KEY[2]),
.Q(LEDR[1])
);
MUXDFF MUXDFF_3(
.clk(KEY[0]),
.w(LEDR[1]),
.R(SW[0]),
.E(KEY[1]),
.L(KEY[2]),
.Q(LEDR[0])
);
endmodule
module MUXDFF (
input clk,
input w, R, E, L,
output Q
);
reg mux1;
always@(*)begin
if (E) begin
mux1 = w;
end
else begin
mux1 = Q;
end
end
reg mux2;
always@(*)begin
if (L) begin
mux2 = R;
end
else begin
mux2 = mux1;
end
end
always@(posedge clk)begin
Q <= mux2;
end
endmodule
9 3-input LUT
题目:
在本题中,你将设计一个 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 );
reg [7:0] Q;
always @(posedge clk) begin
if (enable)
Q <= {Q[6:0], S};
else
Q <= Q;
end
always @(*) begin
case({A,B,C})
3'd0 : Z = Q[0];
3'd1 : Z = Q[1];
3'd2 : Z = Q[2];
3'd3 : Z = Q[3];
3'd4 : Z = Q[4];
3'd5 : Z = Q[5];
3'd6 : Z = Q[6];
3'd7 : Z = Q[7];
default Z = Z;
endcase
end
endmodule
- END -
相关推荐文章,点击跳转: