首页 > 其他分享 >HDLBits答案(1)_移位寄存器+更多电路

HDLBits答案(1)_移位寄存器+更多电路

时间:2024-07-25 19:55:37浏览次数:21  
标签:clk always HDLBits module 寄存器 input 移位

前言

        由于开发板教学内容部分,代码涉及到状态机内容,HDLBits题库只刷到了计数器,因此后续3至4天决定继续刷题,刷完状态机和全部HDLBits题库。今天刷完移位寄存器+更多电路,以下是书写的代码。


题库

Question1:

构建一个 4 位移位寄存器(右移),具有异步复位、同步加载和使能功能。

  • areset:将移位寄存器重置为零。
  • load:加载带有 data[3:0] 的移位寄存器,而不是移位。
  • ena:向右移动(q[3] 变为零,q[0] 移出并消失)。
  • 问:移位寄存器的内容。

如果 load 和 ena 输入都置位 (1),则负载输入具有更高的优先级。

Solution: 

        这里的异步复位,同步释放的内容,建议参考:深入理解复位---同步复位,异步复位,异步复位同步释放(含多时钟域)_画出支持异步复位dff的电路图-CSDN博客

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 [3:0] <= 0;
        else if(load)
            q <= data;
        else if(ena)
            q <= {1'b0,q[3:1]}; //向右移位
        else
            q <= q;
    end 
endmodule

Question2:

构建一个 100 位左/右旋转器,同步加载和左/右使能。旋转器从寄存器的另一端移入移出位,这与移位器丢弃移出位并移位为零的移位器不同。如果启用,旋转器将旋转位,并且不会修改/丢弃它们。

  • load:加载带有数据的移位寄存器[99:0],而不是旋转。
  • ena[1:0]:选择是否旋转以及旋转方向。
    • 2'B01 向右旋转一位
    • 2'b10 向左旋转一位
    • 2'B00 和 2'B11 不旋转。
  • 问:旋转器的内容。

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]};//right
                2'b10:q = {q[98:0],q[99]};//left
                default:q = q;
            endcase    
        end      
	end
endmodule

Question3:

建立一个具有同步加载功能的 64 位算术移位寄存器。移位寄存器既可以左移,也可以右移,移位位数可以是 1 位,也可以是 8 位。

算术右移时,移入的是移位寄存器中数字(本例中为 q[63])的符号位,而不是逻辑右移时的零。算术右移的另一种思路是,它假定被移位的数字是带符号的,并保留符号,因此算术右移是将带符号的数字除以 2 的幂。

逻辑左移和算术左移没有区别。

加载: 用数据[63:0]加载移位寄存器,而不是移位。
ena: 选择是否移位。
amount: 数量: 选择移位方向和移位量。
2'b00:左移 1 位。

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 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
    end
endmodule

Question4:

        线性反馈移位寄存器是一种移位寄存器,通常有几个 XOR 门来产生移位寄存器的下一个状态。伽罗瓦线性反馈移位寄存器(Galois LFSR)是一种特殊的排列方式,其中带有 "抽头 "的比特位置与输出比特进行 XOR,以产生下一个值,而没有抽头的比特位置则进行移位。如果对抽头位置进行精心选择,LFSR 就可以做到 "最大长度"。一个 n 位的最大长度 LFSR 在重复之前会循环经过 2n-1 个状态(永远不会达到全零状态)。

下图显示了一个最大长度为 5 位的伽罗瓦 LFSR,抽头位于第 5 位和第 3 位(抽头位置通常从 1 开始编号)。请注意,为了保持一致,我将 XOR 门画在了第 5 位,但 XOR 门的一个输入端为 0。
amount: 数量: 选择移位方向和移位量。
2'b00:左移 1 位。
2'b01:左移 8 位。
2'b10:右移 1 位。

Solution: 

module top_module(
    input clk,
    input reset,    // Active-high synchronous reset to 5'h1
    output [4:0] q
); 
    always @(posedge clk) begin
        if(reset)
            q <= 5'h1			;
        else begin
            q[4] <= q[0] ^ 1'b0	;
			q[3] <= q[4]		;
        	q[2] <= q[3] ^ q[0] ;
			q[1] <= q[2]		;
			q[0] <= q[1]		;
        end
    end
endmodule

Question5:

        编写该顺序电路的 Verilog 代码(子模块也可以,但顶层必须命名为 top_module)。假设要在 DE1-SoC 板上实现该电路。将 R 输入连接到 SW 开关,将 Clock 连接到 KEY[0],将 L 连接到 KEY[1]。将 Q 输出端连接至红灯 LEDR。

Solution: 

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
        if(KEY[1]) begin
            LEDR[0] <= SW[0];
        	LEDR[1] <= SW[1];
        	LEDR[2] <= SW[2];
        end
        else begin
            LEDR[0] <= LEDR[2];
        	LEDR[1] <= LEDR[0];
        	LEDR[2] <= LEDR[2] ^ LEDR[1];
        end
	end
endmodule

Question6:

有关解释,请参见 Lfsr5。
构建一个 32 位伽罗瓦 LFSR,在第 32、22、2 和 1 位上设置抽头。

Solution: 

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

Question7:

Solution: 

module top_module (
    input clk,
    input resetn,   // synchronous reset
    input in,
    output out);
    reg q1,q2,q3;
    always @(posedge clk) begin
        if(!resetn)
        	{out,q1,q2,q3} <= 4'b0;
        else
        	{out,q1,q2,q3} <= {q1,q2,q3,in};
    end
endmodule

Question8:

Solution: 

module top_module (
    input [3:0] SW,
    input [3:0] KEY,
    output [3:0] LEDR
); //
    MUXDFF DE2(
        .R		(SW		)	,
        .clk	(KEY[0]	)	,
        .E		(KEY[1]	)	,
        .L		(KEY[2]	)	,
        .w		(KEY[3]	)	,
        .Q		(LEDR	)
    );
endmodule

module MUXDFF (
    input  [3:0] R		,
    input 		 clk	,
    input 		 E		,
    input 		 L		,
    input 		 w		,
    output [3:0] Q
);
    always @(posedge clk) begin
        if(L)
            Q <= R;
        else if(E)begin
            Q[3] <= w;
        	Q[2] <= Q[3];
            Q[1] <= Q[2];
            Q[0] <= Q[1];
        end
        else begin
            Q[3] <= Q[3];
            Q[2] <= Q[2];
            Q[1] <= Q[1];
            Q[0] <= Q[0];
        end
    end
endmodule

Question9:

        在本题中,您将设计一个 8x1 存储器的电路,其中写入存储器是通过移位完成的,而读取则是 "随机存取",就像典型的 RAM 一样。然后,您将使用该电路实现 3 输入逻辑功能。
        首先,用 8 个 D 型触发器创建一个 8 位移位寄存器。将触发器的输出标记为 Q[0]...Q[7]。移位寄存器的输入应称为 S,它馈入 Q[0] 的输入(MSB 先移入)。使能输入控制是否移位。然后,扩展电路,增加 3 个输入端 A、B、C 和一个输出端 Z。电路的行为应如下:当 ABC 为 000 时,Z=Q[0];当 ABC 为 001 时,Z=Q[1],以此类推。您的电路应只包含 8 位移位寄存器和多路复用器。(注:该电路称为 3 输入查找表(LUT))。

Solution: 

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
    
    assign Z = Q[{A,B,C}];
endmodule

Question10:

        规则 90 是一种具有有趣特性的一维蜂窝自动机。
        规则很简单。有一个由单元格(开或关)组成的一维数组。在每个时间步,每个单元格的下一个状态是该单元格当前两个相邻单元格的 XOR。下表是表达这一规则的更详细的方法,其中一个单元格的下一个状态是其自身和两个相邻单元格的函数:

        (规则 90 "的名称来源于阅读 "下一状态 "列: 01011010 是十进制 90)。
        在该电路中,创建一个 512 单元系统(q[511:0]),每个时钟周期前进一个时间步进。加载输入表示系统的状态应加载数据[511:0]。假设边界(q[-1] 和 q[512])均为零(关闭)。 

Solution: 

用卡诺图化简真值表,难度一般。其中LEFT向右移动1位,RIGHT向左移动1位。

module top_module(
    input clk,
    input load,
    input [511:0] data,
    output [511:0] q ); 
    always @(posedge clk) begin
        if(load)
            q <= data;
        else
            q <= {1'b0,q[511:1]}^{q[510:0],1'b0};
    end
endmodule

Question11:

        规则 110 是一个具有有趣特性(如图灵完备)的一维单元自动机。
        有一个一维单元阵列(开或关)。在每个时间步,每个单元的状态都会发生变化。在规则 110 中,每个单元格的下一个状态只取决于它自己和它的两个相邻单元格,如下表所示:

         (规则 110 "的名称来源于阅读 "下一状态 "列: 01101110 是十进制 110)。
        在该电路中,创建一个 512 单元系统(q[511:0]),每个时钟周期前进一个时间步进。加载输入表示系统的状态应加载数据[511:0]。假设边界(q[-1] 和 q[512])均为零(关闭)。

Solution: 

用卡诺图化简真值表,难度一般。其中LEFT向右移动1位,RIGHT向左移动1位。

module top_module(
    input clk,
    input load,
    input [511:0] data,
    output [511:0] q
); 
    always @(posedge clk) begin
        if(load)
            q <= data;
        else
            q <= (~({q[510:0],1'b0})&q[511:0])|(q[511:0]&~({1'b0,q[511:1]}))|(~({1'b0,q[511:1]})&({q[510:0],1'b0}))|(~(q[511:0])&({q[510:0],1'b0}));
    end
endmodule

Question12:

康威生命游戏是一种二维细胞自动机。
游戏 "在一个二维单元格上进行,每个单元格要么是 1(活),要么是 0(死)。在每个时间步长内,每个单元格的状态变化取决于它有多少个邻居:
0-1 个邻居: 单元格变为 0。
2 个邻居: 小区状态不变。
3 个邻居: 单元变为 1。
4+ 个邻居: 单元格变为 0。
这个游戏是针对无限网格设计的。在本电路中,我们将使用 16x16 的网格。为了增加游戏的趣味性,我们将使用一个 16x16 的环形网格,网格的边环绕到网格的另一边。例如,角单元 (0,0) 有 8 个相邻单元:(15,1)、(15,0)、(15,15)、(0,1)、(0,15)、(1,1)、(1,0) 和 (1,15)。16x16 网格由长度为 256 的矢量表示,其中每行 16 个单元由一个子矢量表示:q[15:0] 表示第 0 行,q[31:16] 表示第 1 行,等等。
加载: 在下一个时钟沿将数据加载到 q 中,用于加载初始状态。
q:16x16 的游戏当前状态,每个时钟周期更新一次。
游戏状态应在每个时钟周期前进一个时间步。
约翰-康威(John Conway),数学家和生命游戏细胞自动机的创造者,于 2020 年 4 月 11 日因 COVID-19 病逝。

Solution: 

module top_module(
    input clk,
    input load,
    input [255:0] data,
    output [255:0] q ); 
    reg [3:0] sum;
    integer i	 ;
    always @(posedge clk) begin
        if(load)
            q <= data;
        
        else begin
            for(i=0;i<256;i++) begin//这里采用枚举法,分四种情况。
                if(i == 0) begin 	//情况1:四个角落,左上角,右上角,左下角,右下角
                    sum = q[15] + q[1] + q[31] + q[16] + q[17] + q[255] + q[240] + q[241];
                end
                else if(i == 15) begin
                    sum = q[254] + q[255] + q[240] + q[14] + q[0] + q[30] + q[31] + q[16];
                end
                else if(i == 240)begin
                    sum = q[239] + q[224] + q[225] + q[255] + q[241] + q[15] + q[0] + q[1];
                end
                else if(i == 255)begin
                    sum = q[238] + q[239] + q[224] + q[254] + q[240] + q[14] + q[15] + q[0];
                end
                else if(i>0 && i<15)begin//情况2:第0行,第15行
                    sum = q[i+240] + q[i+239] + q[i+241] + q[i-1] + q[i+1] + q[i+15] + q[i+16] + q[i+17];
                end
                else if(i>240 && i<255)begin
                    sum = q[i-17] + q[i-16] + q[i-15] + q[i-1] + q[i+1] + q[i-241] + q[i-240] + q[i-239];
                end
                else if(i%16 == 0)begin//情况3:第0列,第15列
                    sum = q[i-1] + q[i-16] + q[i-15] + q[i+15] + q[i+1] + q[i+31] + q[i+16] + q[i+17];
                end
                else if(i%16 == 15)begin
                    sum = q[i-17] + q[i-16] + q[i-31] + q[i-1] + q[i-15] + q[i+15] + q[i+16] + q[i+1];
                end
                else begin
                    sum = q[i-17] + q[i-16] + q[i-15] + q[i-1] + q[i+1] + q[i+15] + q[i+16] + q[i+17];
                end
                case(sum)
                    4'd2  	   :q[i] <= q[i] ;
                    4'd3  	   :q[i] <= 1 	;
                    default:q[i] <= 0 		;
                endcase
            end	
        end
    end
endmodule

注:

        本题,遇到了一个非常严重的问题,即阻塞赋值和非阻塞赋值,我原先的代码是这样的。即循环中的if语句我用的是非阻塞赋<=(时序电路),而case语句我用的阻塞赋值=(组合逻辑),发生了报错。首先在for循环语句的时序逻辑中必须使用阻塞赋值,不能使用非阻塞赋值。如果用阻塞赋值,在循环中,这里sum会被一直赋值,会成为0或者不定态。

        具体内容参考:FPGA学习笔记:Verilog中for循环的阻塞赋值与非阻塞赋值_时序逻辑下的for循环赋值是什么-CSDN博客

module top_module(
    input clk,
    input load,
    input [255:0] data,
    output [255:0] q ); 
    reg [3:0] sum;
    integer i	 ;
    always @(posedge clk) begin
        if(load)
            q <= data;
        
        else begin
            for(i=0;i<256;i++) begin//这里采用枚举法,分四种情况。
                if(i == 0) begin 	//情况1:四个角落,左上角,右上角,左下角,右下角
                    sum <= q[15] + q[1] + q[31] + q[16] + q[17] + q[255] + q[240] + q[241];
                end
                else if(i == 15) begin
                    sum <= q[254] + q[255] + q[240] + q[14] + q[0] + q[30] + q[31] + q[16];
                end
                else if(i == 240)begin
                    sum <= q[239] + q[224] + q[225] + q[255] + q[241] + q[15] + q[0] + q[1];
                end
                else if(i == 255)begin
                    sum <= q[238] + q[239] + q[224] + q[254] + q[240] + q[14] + q[15] + q[0];
                end
                else if(i>0 && i<15)begin//情况2:第0行,第15行
                    sum <= q[i+240] + q[i+239] + q[i+241] + q[i-1] + q[i+1] + q[i+15] + q[i+16] + q[i+17];
                end
                else if(i>240 && i<255)begin
                    sum <= q[i-17] + q[i-16] + q[i-15] + q[i-1] + q[i+1] + q[i-241] + q[i-240] + q[i-239];
                end
                else if(i%16 == 0)begin//情况3:第0列,第15列
                    sum <= q[i-1] + q[i-16] + q[i-15] + q[i+15] + q[i+1] + q[i+31] + q[i+16] + q[i+17];
                end
                else if(i%16 == 15)begin
                    sum <= q[i-17] + q[i-16] + q[i-31] + q[i-1] + q[i-15] + q[i+15] + q[i+16] + q[i+1];
                end
                else begin
                    sum <= q[i-17] + q[i-16] + q[i-15] + q[i-1] + q[i+1] + q[i+15] + q[i+16] + q[i+17];
                end
                case(sum)
                    4'd2  	   :q[i] = q[i] ;
                    4'd3  	   :q[i] = 1 	;
                    default:q[i] = 0 		;
                endcase
            end	
        end
    end
endmodule

        在Verilog中,case语句是用来进行多路分支选择的一种结构。在case语句中,可以使用非阻塞赋值<=, 也可以使用阻塞赋值=。 

        阻塞赋值在case语句中的使用方法如下:

always @(*) begin

    case (sel)

        'b00: out = a;

        'b01: out = b;

        'b10: out = c;

        default: out = d;

    endcase

end

        在这个例子中,out的赋值是阻塞的,即在同一个always块内,下一个赋值会等到当前赋值的结束后才进行。

        非阻塞赋值在case语句中的使用方法如下:

always @(posedge clk) begin

    case (sel)

        'b00: out <= a;

        'b01: out <= b;

        'b10: out <= c;

        default: out <= d;

    endcase

end

        在这个例子中,out的赋值是非阻塞的,即在时钟沿到来时,所有的非阻塞赋值同时进行。

        注意:在同一个always块中,不能同时使用阻塞赋值和非阻塞赋值来对同一个变量进行赋值。


参考内容

HDLBits刷题网站:HDLBits (01xz.net)

标签:clk,always,HDLBits,module,寄存器,input,移位
From: https://blog.csdn.net/weixin_58164636/article/details/140556483

相关文章

  • 使用GG获取函数寄存器地址
    此方法是从神秘老师(一只神秘)的视频得到的灵感,分享出来也是经过其本人的同意视频如下也希望大家多多支持神秘老师捏多的不说,少的不唠,也是进入正题我们先找到需要获取的函数然后进行分配内存页,保存该地址然后在函数头进行如下的操作码修改意思就是:把该地址传给r1再......
  • 7.用寄存器点亮LED
    7.用寄存器点亮LED7.1GPIO简介GPIO是通用输入输出端口的简称,简单来说就是STM32可控制的引脚。通过将STM32芯片的GPIO引脚与外部设备连接,可以实现外部通信、控制以及数据采集的功能。STM32芯片的GPIO被分成很多组,每组有16个引脚。例如,STM32F103VET6的芯片有GPIOA至GPIOE......
  • HDLBits答案(3)_状态机(2)
      前言    今天刷完状态机的2/3,以下是书写的代码。题库1:Lemmings2:        除了向左和向右走之外,如果下面的地面消失,旅鼠还会摔倒(大概会“啊啊!”)。        除了左右行走和撞到时改变方向外,当地面=0时,旅鼠还会摔倒并说“啊!当地面重新出现(地面=1)......
  • STM32寄存器操作、模板构建
    2024年7月18日发布于博客园,本文涉及到STM32F4XX和STM32F1XX系列目录外设寄存器查找①名称②偏移地址③寄存器位表④位功能说明寄存器基本操作C语言的置位和清零具体方法设置GPIO流程给寄存器赋值带参数宏STM32F1xx芯片识别存储器映射寄存器映射让GPIOB端口的16个引脚输......
  • 一起学RISC-V汇编第3讲之寄存器
    寄存器是处理器中最常用的处理单元,RISC-V指令的操作数除了立即数就是寄存器。RISC-V指令集包含了多种不同类型的寄存器,用于不同目的和功能:对于rv32imafd架构而言,包含如下寄存器:通用寄存器:32个通用整数寄存器,分别标记为x0-x31,如果是fd扩展,还有32个独立的浮点寄存器,分别标记为f......
  • AvalonMM接口Interval Timer IP的寄存器介绍和Interval Timer寄存器读写操作详解
    一、间隔定时器结构间隔定时器的结构框图: 该间隔定时器有如下两个特点:-Avalon-MM接口,提供对6个16位寄存器的访问;-有一个脉冲输出接口(可选),可用作周期性脉冲发生器;该间隔定时器的所有寄存器都是16位的,可兼容16-bit和32-bit处理器。某些寄存器只存在于特定的配置中,例如,当该......
  • 【C语言】移位操作详解 - 《凌波微步 ! 》
    这里写目录标题C语言移位操作(BitwiseShiftOperators)详解1.移位操作符概述1.1左移操作符(`<<`)1.2右移操作符(`>>`)2.使用示例2.1左移操作符示例2.2右移操作符示例2.3有符号和无符号右移3.注意事项3.1超出位数范围的移位3.2移位操作的性能4.移位操......
  • HAL库源码移植与使用之高级定时器REP寄存器
    高级定时器的溢出中断信号与更新要想输出,要经过一个重复计数寄存器,该寄存器由REP控制并由TIMX_RCR控制计数值它的原理是计数器每次上溢或下溢而输出中断信号和更新都能使重复计数器值减1,减到0时,再发生一次溢出就会产生更新事件所以如果设置RCR为N,更新事件将在N+1次溢出时发......
  • BKP备份寄存器和实时时钟笔记
    BKP(BackupRegisters)备份寄存器BKP可用于存储用户应用程序数据。当VDD(2.0~3.6V)电源被切断,他们仍然由VBAT(1.8~3.6V)维持供电。当系统在待机模式下被唤醒,或系统复位或电源复位时,他们也不会被复位TAMPER引脚产生的侵入事件将所有备份寄存器内容清除RTC引脚输出RTC校准时钟、RTC闹......
  • 最简 INA226 写寄存器的代码
    #include"hardware/i2c.h"#include"pico/binary_info.h"#defineI2C_SDA16#defineI2C_SCL17voidsetup(){//putyoursetupcodehere,torunonce:Serial.begin(115200);i2c_init(i2c_default,100*1000);gpio_set_functio......