HDLBits中文版,标准参考答案 | 3.2.3 Shift Registers | 移位寄存器

关注👆 望森FPGA 👆 查看更多FPGA资讯

这是望森的第 14 期分享

作者 | 望森
来源 | 望森FPGA(ID:wangsenfpga)
转载请联系授权(微信ID:wangsen094)

目录

1 4-bit shift register

2 Left/right rotator

3 Left/right arithmetic shift by 1 or 8

4 5-bit LFSR

5 3-bit LFSR

6 32-bit LFSR

7 Shift register

8 Shift register

9 3-input LUT


本文中的代码都能够正常运行,请放心食用😋~

练习的官方网站是: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 -

相关推荐文章,点击跳转:

望森FPGA的HDLBits合集

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

望森Eric

谢谢你的支持,这对我很重要~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值