HDLBits刷题Day11

本文介绍了使用Verilog实现不同类型的移位寄存器,包括4-bit右移寄存器、双向移位寄存器、算术移位寄存器以及线性反馈移位寄存器(LFSR)。详细展示了各种移位操作的Verilog代码,包括异步复位、同步置位、算术左移和右移、以及LFSR的生成。同时还讨论了复位策略和LFSR的工作原理。


强烈建议大家去看看HDLBits 中文导学,原文在知乎
链接: link.

106.4-bit shift register

一个4bit异步复位,拥有同步置位使能的右移移位寄存器
同步复位:复位信号和时钟同步,当时钟上升沿检测到复位信号,执行复位操作
异步复位:不受时钟影响,只要复位信号有效,就会进行复位。
移位寄存器:数电简明教程P349;

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'b0; 
        end
    else if(load)
         q<=data;
    else if(ena)
        q<={1'b0,q[3:1]};//右移一位且将最左位置0;
        //q<=q[3:1] 缺少的位会直接置0;
        end

endmodule

在verilog中最好的复位方式是采用:异步复位,同步释放的方式;
具体介绍的连接 link

107.Left/right rotator

类似双向移位寄存器,加入左/右移的信号;

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)begin
            q<=data;
        end
     else if(ena==2'b01)begin
         q<={q[0],q[99:1]};
        end
    else if(ena==2'b10)begin
        q<={q[98:0],q[99]};
        end
    else if(ena==2'b00||ena==2'b11)
        q<=q;
        
    end
endmodule

108.Left/right arithmetic shift by 1 or 8

添加一个amount来控制移动的方向和次数,
算术左移和逻辑左移没有区别;
算术右移和逻辑右移:
算术右移是保留符号位之后,在进行右移操作;
逻辑右移是直接将移位的位补零;
这里在寄存器的高低位上,因为太久没看了,忘记了。。。。
看了半天还是没看懂。。。

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)
        if(load)begin
            q<=data;
        end
    else if(ena)begin
        if(amount==2'b00)
            
            q<={q[62:0],1'b0};
            
        else if(amount==2'b01)
            
            q<={q[55:0],8'b0};
            
        else if(amount==2'b10)
            
            q<={q[63],q[63:1]};
            
        else if(amount==2'b11)
            q<={{8{q[63]}},q[63-:56]};
            //解析上是说用用符号位填充寄存器的高56位,woshi没看懂
            //右移8位为啥要填充高56位,q[63-:56]这个数组表达了啥
          /*
          else if(ena&amount==2'b10)
               q[62:0]<={q[63:1]};
          else if(ena&amount==2'b11)
               q[62:0]<={{7{q[63]}},q[63:8]};
               q[63:0] 63是高位
  */
            end
endmodule

109.5-bit LFSR

linear feedback shift register 线性回馈移位寄存器
关于LFSR的具体介绍可以看这里link
这里我们没有深入的去搞清楚LFSR的具体原理,但是通过题目给的电路图是可以看出怎么写出代码的;

module top_module(
   input clk,
   input reset,    // Active-high synchronous reset to 5'h1
   output [4:0] q
); 
   always@(posedge clk)
       if(reset)
           q<=5'b00001;
   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

endmodule

110.3-bit LFSR

其实相当于将输入输出变成了实际的类型;

module top_module (
   input [2:0] SW,      // R
   input [1:0] KEY,     // L and clk
   output [2:0] LEDR);  // Q
   always@(posedge KEY[0])
       begin
           LEDR[2]<=KEY[1]?SW[2]:LEDR[1]^LEDR[2];
           LEDR[1]<=KEY[1]?SW[1]:LEDR[0];
           LEDR[0]<=KEY[1]?SW[0]:LEDR[2];
       end
endmodule

111.32-bit LFSR

注意tap点的位置;看完知乎大佬的方法,就是先整体做一个右移一位的寄存器;然后再将具体的tap的位置改写;

module top_module(
   input clk,
   input reset,    // Active-high synchronous reset to 32'h1
   output [31:0] q
); 
   always@(posedge clk)
       if(reset)
           q<=32'h1;
   else 
       begin
           q<={q[0],q[31:23],q[22]^q[0],q[21:3],q[2]^q[0],q[1]^q[0]};
       end

endmodule

112.Shift Register(Exams/m2014 q4k)

module top_module (
   input clk,
   input resetn,   // synchronous reset
   input in,
   output out);
   reg q0,q1,q2;
   always@(posedge clk)
       if(~resetn)begin     //Synchronous active-low reset
          q0<=1'b0;
          q1<=1'b0;
          q2<=1'b0;
          out<=1'b0;
       end
       else begin
          q0<=in;
          q1<=q0;
          q2<=q1;
          out<=q2;
       end
endmodule

113.Shift Register(Exams/m2014 q4b)

module top_module (
    input [3:0] SW,
    input [3:0] KEY,
    output [3:0] LEDR
); 
    wire [3:0] w_in={KEY[3],LEDR[3],LEDR[2],LEDR[1]};
    generate
        genvar i;
        for( i=0;i<4;i=i+1)begin:muxdff //调用下面的模块
            MUXDFF(
                .clk(KEY[0]),
                .W(w_in[i]),//需要手动输入
                .R(SW[i]),
                .E(KEY[1]),
                .L(KEY[2]),
                .Q(LEDR[i])
            
            );
        end
    endgenerate

endmodule

  //单个的选择器的模块
module MUXDFF (    
       input clk,
       input W,R,E,L,
       output Q
);
    reg Q_r;  //中间变量;
    wire d_in=(L)?R:(E)?W:Q_r; 
    //L为真就选择R,否则选择前一项,而前一项同样是由一个选择语句构成,E为真就选W,否则就选Qn-1;
    always@(posedge clk)begin
        Q_r<=d_in; //
    end
    assign Q = Q_r;
endmodule

114.Shift Register(Exams/m2014 q4k)

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)begin
            Q<={S,Q[7:1]};
        end
    end
    wire [2:0] ABC={A,B,C};
    always@(*)begin
        case(ABC)
            3'b000:Z=Q[7];
            3'b001:Z=Q[6];
            3'b010:Z=Q[5];
            3'b011:Z=Q[4];
            3'b100:Z=Q[3];
            3'b101:Z=Q[2];
            3'b110:Z=Q[1];
            3'b111:Z=Q[0];
        endcase
    end

endmodule
module top_module (
	input clk,
	input enable,
	input S,
	
	input A, B, C,
	output reg Z
);

	reg [7:0] q;
	assign Z = q[ {A, B, C} ];
	//直接让Z赋值为ABC,
    //后面赋值的时候将S放在q[7]的位置,而不是在q[0];
	always @(posedge clk) begin
		if (enable)
			q <= {q[6:0], S};	
	end	
endmodule
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值