HDLBits中文版,标准参考答案 | 3.3 Building Larger Circuits | 构建更大的电路

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

这是望森的第 21 期分享

作者 | 望森
来源 | 望森FPGA

目录

[1 Counter with period 1000](#1 Counter with period 1000)

[2 4-bit shift register and down counter](#2 4-bit shift register and down counter)

[3 FSM: Sequence 1101 recognizer](#3 FSM: Sequence 1101 recognizer)

[4 FSM: Enable shift register](#4 FSM: Enable shift register)

[5 FSM: The complete FSM](#5 FSM: The complete FSM)

[6 The complete timer](#6 The complete timer)

[7 FSM: One-hot logic equations](#7 FSM: One-hot logic equations)


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

练习的官方网站是:https://hdlbits.01xz.net/

注:作者将每个练习的知识点都放在了题目和答案之后


1 Counter with period 1000

题目:

构建一个计数器,计数范围从 0 到 999(含 0 和 999),周期为 1000 个周期。复位输入是同步的,应将计数器复位为 0。

答案:

module top_module (
    input clk,
    input reset,
    output [9:0] q);
        
        reg [9:0] cnt;
    wire end_cnt;
    parameter x = 10'd1000;
        always@(posedge clk) begin
        if(reset)begin
            cnt <= 0;
        end
        else if(end_cnt)begin
            cnt <= 0;
        end
        else begin
            cnt <= cnt + 1;
        end
    end
    assign end_cnt = cnt==x-1;
         
        assign q = cnt;
endmodule

2 4-bit shift register and down counter

题目:

构建一个四位移位寄存器,该寄存器也可用作减计数器。当 shift_ena 为 1 时,数据首先以最高有效位移位。当 count_ena 为 1 时,移位寄存器中的当前数字会减少。由于整个系统从不一起使用 shift_ena 和 count_ena,因此如果两个控制输入都是 1,您的电路做什么都无关紧要(这主要意味着哪种情况具有更高的优先级并不重要)。

答案:

module top_module (
    input clk,
    input shift_ena,
    input count_ena,
    input data,
    output reg [3:0] q);

        always@(posedge clk)begin
        if(shift_ena)begin
            q <= {q[2:0],data};
        end
        if(count_ena)begin
            q <= q-1;
        end
    end
         
endmodule

3 FSM: Sequence 1101 recognizer

题目:

构建一个有限状态机,在输入位流中搜索序列 1101。找到该序列后,它应将 start_shifting 设置为 1,直到重置。卡在最终状态旨在模拟在尚未实现的更大的 FSM 中进入其他状态。我们将在接下来的几个练习中扩展此 FSM。

答案:

1.状态转换图

2.代码

module top_module (
    input clk,
    input reset,      // Synchronous reset
    input data,
    output start_shifting);
    
    parameter IDLE  =3'd0;
    parameter S0    =3'd1;
    parameter S1    =3'd2;
    parameter S2    =3'd3;
    parameter S3    =3'd4;
    
        reg [2:0] state,next_state;
    
    wire IDLE2IDLE,IDLE2S0;
    wire S02IDLE,S02S1;
    wire S12S2,S12S1;
    wire S22IDLE,S22S3;
    
    always@(posedge clk) begin
        if(reset)
            state <= IDLE;
        else        
            state <= next_state;
        end
    
    always@(*) begin
        case(state)
            IDLE:begin
                if (IDLE2IDLE)begin
                    next_state = IDLE;
                end
                else if (IDLE2S0)begin
                    next_state = S0;
                end
            end
            S0: begin
                if (S02IDLE)begin
                    next_state = IDLE;
                end
                else if (S02S1)begin
                    next_state = S1;
                end
            end
            S1: begin
                if (S12S2)begin
                    next_state = S2;
                end
                else if (S12S1)begin
                    next_state = S1;
                end
            end
            S2: begin
                if (S22IDLE)begin
                    next_state = IDLE;
                end
                else if (S22S3)begin
                    next_state = S3;
                end
            end
            S3: begin
                next_state = S3;
            end
            default next_state = IDLE;
        endcase
        end
    
    assign IDLE2IDLE        = data==1'b0;
    assign IDLE2S0          = data==1'b1;
    assign S02IDLE          = data==1'b0;
    assign S02S1            = data==1'b1;
    assign S12S2            = data==1'b0;
    assign S12S1            = data==1'b1;
    assign S22IDLE          = data==1'b0;
    assign S22S3            = data==1'b1;
    
    assign start_shifting   = (state == S3);
    
endmodule

4 FSM: Enable shift register

题目:

作为控制移位寄存器的 FSM 的一部分,我们希望能够在检测到正确的位模式时启用移位寄存器恰好 4 个时钟周期。我们在 Exams/review2015_fsmseq 中处理序列检测,因此 FSM 的这一部分仅处理启用移位寄存器 4 个周期。

每当 FSM 重置时,置位 shift_ena 4 个周期,然后永远置位 0(直到重置)。

答案:

module top_module (
    input clk,
    input reset,      // Synchronous reset
    output reg shift_ena
);
    
    parameter x = 4;
    
    //counter
    reg [1:0] cnt;
    wire add_cnt;
    wire end_cnt;
    always@(posedge clk)begin
        if(reset)begin
            cnt <= 0;
        end
        else if(add_cnt)begin
            if(end_cnt)begin
                cnt <= 0;
            end
            else begin
                cnt <= cnt + 1;
            end
        end
    end
    assign add_cnt = !reset;
    assign end_cnt = add_cnt && cnt==x-1;
    
    //
    always@(posedge clk)begin
        if(reset)begin
            shift_ena <= 1;
        end
        else if(cnt==x-1)begin
            shift_ena <= 0;
        end
    end
    
endmodule

5 FSM: The complete FSM

题目:

您可能希望先执行 FSM:启用移位寄存器和 FSM:序列识别器。

我们想要创建一个计时器:

1.在检测到特定模式 (1101) 时启动,

2.shift 4 个比特以确定延迟的持续时间,

3.等待计数器完成计数

4.通知用户并等待用户确认计时器。

在此问题中,仅实现控制计时器的有限状态机。数据路径(计数器和一些比较器)不包括在这里。

串行数据在数据输入引脚上可用。当接收到模式 1101 时,状态机必须输出正好 4 个时钟周期的 shift_ena 高电平。

此后,状态机 counting 输出为高电平以指示它正在等待计数器,并等待输入 done_counting 为高。

此时,状态机必须拉高 done 以通知用户计时器已超时,并等待输入 ack 为 1,然后重置以查找下一个起始序列 (1101)。

状态机应重置为开始搜索输入序列 1101 的状态。

以下是预期输入和输出的示例。"x"状态可能读起来有点混乱。它们表示 FSM 不应该关心该周期中的特定输入信号。例如,一旦检测到 1101 模式,FSM 就不再查看数据输入,直到完成所有其他操作后才恢复搜索。

答案:

module top_module (
    input clk,
    input reset,      // Synchronous reset
    input data,
    output shift_ena,
    output counting,
    input done_counting,
    output done,
    input ack );
    
    parameter S     =4'd0;
    parameter S1    =4'd1;
    parameter S11   =4'd2;
    parameter S110  =4'd3;
    parameter B0    =4'd4;
    parameter B1    =4'd5;
    parameter B2    =4'd6;
    parameter B3    =4'd7;
    parameter Count =4'd8;
    parameter Wait  =4'd9;
    
    
    reg [3:0] state, next_state;
    
    wire S2S,S2S1;
    wire S12S,S12S11;
    wire S112S110,S112S11;
    wire S1102S,S1102B0;
    wire Count2Count,Count2Wait;
    wire Wait2Wait,Wait2S;
    
    //状态跳转
    always @(posedge clk) begin
        if(reset)begin
            state <= S;
        end
        else begin
            state <= next_state;
        end
    end
    
    //状态跳转控制
    always @(*) begin
        case(state)
            S : begin
                if (S2S)begin
                    next_state = S;
                end
                else if(S2S1)begin
                    next_state = S1;
                end
            end
            S1 : begin
                if (S12S)begin
                    next_state = S;
                end
                else if(S12S11)begin
                    next_state = S11;
                end
            end
            S11 : begin
                if (S112S110)begin
                    next_state = S110;
                end
                else if(S112S11)begin
                    next_state = S11;
                end
            end
            S110 : begin
                if (S1102S)begin
                    next_state = S;
                end
                else if(S1102B0)begin
                    next_state = B0;
                end
            end
            B0 : begin
                next_state = B1;
            end
            B1 : begin
                next_state = B2;
            end
            B2 : begin
                next_state = B3;
            end
            B3 : begin
                next_state = Count;
            end
            Count : begin
                if (Count2Count)begin
                    next_state = Count;
                end
                else if(Count2Wait)begin
                    next_state = Wait;
                end
            end
            Wait : begin
                if (Wait2Wait)begin
                    next_state = Wait;
                end
                else if(Wait2S)begin
                    next_state = S;
                end
            end
            default next_state = S;
        endcase
    end
    
    //状态跳转控制条件
    assign S2S          = data == 0;
    assign S2S1         = data == 1;
    assign S12S         = data == 0;
    assign S12S11       = data == 1;
    assign S112S110     = data == 0;
    assign S112S11      = data == 1;
    assign S1102S       = data == 0;
    assign S1102B0      = data == 1;
    assign Count2Count  = done_counting == 0;
    assign Count2Wait   = done_counting == 1;
    assign Wait2Wait    = ack == 0;
    assign Wait2S       = ack == 1;
    
    //输出信号
    assign shift_ena    = state==B0 || state==B1 || state==B2 || state==B3;
    assign counting     = state==Count;
    assign done         = state==Wait;
    
    
endmodule

知识点:

提示:


6 The complete timer

题目:

这是由几个较小的电路构建复杂计数器的五个练习系列中的第五个组件。您可能希望先进行前面四个练习(计数器、序列识别器 FSM、FSM 延迟和组合 FSM)。

我们想要创建一个具有一个输入的计时器,该计时器:

1.在检测到特定输入模式 (1101) 时启动,

2.shift 4 比特以确定延迟持续时间,

3.等待计数器完成计数

4.通知用户并等待用户确认计时器。

串行数据在数据输入引脚上可用。当接收到模式 1101 时,电路必须移入接下来的 4 位,优先移入最高有效位。这 4 位决定了计时器延迟的持续时间。我将其称为 delay[3:0] 。

之后,状态机拉高其 counting output 以指示它正在计数。状态机必须精确计数 (delay[3:0] + 1) * 1000 个时钟周期。例如,delay=0 表示计数 1000 个周期,delay=5 表示计数 6000 个周期。同时输出当前剩余时间。这应该等于延迟 1000 个周期,然后延迟 1 1000 个周期,依此类推,直到 1000 个周期为 0。当电路不计数时,count[3:0] 输出无关紧要(无论你方便实现什么值)。

此时,电路必须拉高 done 以通知用户计时器已超时,并等待输入 ack 为 1,然后重置以查找下一个出现的起始序列(1101)。

电路应重置为开始搜索输入序列 1101 的状态。

以下是预期输入和输出的示例。 "x"状态可能读起来有点混乱。它们表示 FSM 不应该关心该周期中的特定输入信号。例如,一旦读取了 1101 和 delay[3:0],电路就不再查看数据输入,直到完成所有其他操作后才恢复搜索。在此示例中,电路计数 2000 个时钟周期,因为 delay[3:0] 值为 4'b0001。最后几个周期以 delay[3:0] = 4'b1110 开始另一个计数,这将计数 15000 个周期。

答案:

1.状态转换图

2.代码

module top_module (
    input clk,
    input reset,      // Synchronous reset
    input data,
    output [3:0] count,
    output counting,
    output done,
    input ack );
    
    parameter S     =4'd0;
    parameter S1    =4'd1;
    parameter S11   =4'd2;
    parameter S110  =4'd3;
    parameter B0    =4'd4;
    parameter B1    =4'd5;
    parameter B2    =4'd6;
    parameter B3    =4'd7;
    parameter Count =4'd8;
    parameter Wait  =4'd9;
    
    
    reg [3:0] state, next_state;
    
    wire S2S,S2S1;
    wire S12S,S12S11;
    wire S112S110,S112S11;
    wire S1102S,S1102B0;
    wire Count2Count,Count2Wait;
    wire Wait2Wait,Wait2S;
    
    //状态跳转
    always @(posedge clk) begin
        if(reset)begin
            state <= S;
        end
        else begin
            state <= next_state;
        end
    end
    
    //状态跳转控制
    always @(*) begin
        case(state)
            S : begin
                if (S2S)begin
                    next_state = S;
                end
                else if(S2S1)begin
                    next_state = S1;
                end
            end
            S1 : begin
                if (S12S)begin
                    next_state = S;
                end
                else if(S12S11)begin
                    next_state = S11;
                end
            end
            S11 : begin
                if (S112S110)begin
                    next_state = S110;
                end
                else if(S112S11)begin
                    next_state = S11;
                end
            end
            S110 : begin
                if (S1102S)begin
                    next_state = S;
                end
                else if(S1102B0)begin
                    next_state = B0;
                end
            end
            B0 : begin
                next_state = B1;
            end
            B1 : begin
                next_state = B2;
            end
            B2 : begin
                next_state = B3;
            end
            B3 : begin
                next_state = Count;
            end
            Count : begin
                if (Count2Count)begin
                    next_state = Count;
                end
                else if(Count2Wait)begin
                    next_state = Wait;
                end
            end
            Wait : begin
                if (Wait2Wait)begin
                    next_state = Wait;
                end
                else if(Wait2S)begin
                    next_state = S;
                end
            end
            default next_state = S;
        endcase
    end
    
    //
    reg [3:0] cnt_num;
    always@(posedge clk)begin
        if(reset)begin
            cnt_num <= 0;
        end
        else begin
            case(state)
                B0:     cnt_num[3] <= data;
                B1:     cnt_num[2] <= data;
                B2:     cnt_num[1] <= data;
                B3:     cnt_num[0] <= data;
                default cnt_num <= cnt_num;
            endcase
        end
    end
    
    //计数器
    wire done_counting;
    reg [31:0] cnt;
    wire add_cnt,end_cnt;
    always@(posedge clk)begin
        if(reset)begin
            cnt <= 0;
        end
        else if(add_cnt)begin
            if(end_cnt)begin
                cnt <= 0;
            end
            else begin
                cnt <= cnt + 1;
            end
        end
    end
    assign add_cnt = state==Count;
    assign end_cnt = add_cnt && cnt==(cnt_num+1)*1000-1;
    assign done_counting = end_cnt;
    
    //状态跳转控制条件
    assign S2S          = data == 0;
    assign S2S1         = data == 1;
    assign S12S         = data == 0;
    assign S12S11       = data == 1;
    assign S112S110     = data == 0;
    assign S112S11      = data == 1;
    assign S1102S       = data == 0;
    assign S1102B0      = data == 1;
    assign Count2Count  = done_counting == 0;
    assign Count2Wait   = done_counting == 1;
    assign Wait2Wait    = ack == 0;
    assign Wait2S       = ack == 1;
    
    //输出信号
    assign count        = cnt_num - cnt/1000;
    assign counting     = state==Count;
    assign done         = state==Wait;
    
    
endmodule

7 FSM: One-hot logic equations

题目:

给定以下具有 3 个输入、3 个输出和 10 个状态的状态机:

假设使用以下独热编码,通过检查得出下一状态逻辑方程和输出逻辑方程:(S、S1、S11、S110、B0、B1、B2、B3、Count、Wait) = (10'b0000000001、10'b0000000010、10'b0000000100、...、10'b1000000000)

假设使用独热编码,通过检查得出状态转换和输出逻辑方程。

仅为此状态机实现状态转换逻辑和输出逻辑(组合逻辑部分)。

编写生成以下方程的代码:

  • B3_next - 下一状态为状态 B3

  • S_next

  • S1_next

  • Count_next

  • Wait_next

  • done - 输出逻辑

  • Counting

  • shift_ena

答案:

module top_module(
    input d,
    input done_counting,
    input ack,
    input [9:0] state,    // 10-bit one-hot current state
         
    output B3_next,
    output S_next,
    output S1_next,
    output Count_next,
    output Wait_next,
    output done,
    output counting,
    output shift_ena
);
    
    parameter S     =4'd0;
    parameter S1    =4'd1;
    parameter S11   =4'd2;
    parameter S110  =4'd3;
    parameter B0    =4'd4;
    parameter B1    =4'd5;
    parameter B2    =4'd6;
    parameter B3    =4'd7;
    parameter Count =4'd8;
    parameter Wait  =4'd9;
    
    //输出信号
    assign B3_next          =   state[B2];
    assign S_next           =   (state[S] && d==0) || 
    (state[S1] && d==0) || (state[S110] && d==0) || (state[Wait] && ack==1);
    assign S1_next          =   state[S] && d==1;
    assign Count_next       =   state[B3] || (state[Count] && done_counting==0);
    assign Wait_next        =   (state[Count] && done_counting==1) || 
    (state[Wait] && ack==0);
    assign done             =   state[Wait];
    assign counting         =   state[Count];
    assign shift_ena        =   (state[B0]) || (state[B1]) || (state[B2]) || (state[B3]);
    
endmodule

- END -

公z号/CSDN/知乎搜索【望森FPGA】,查看更多FPGA资讯~

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

望森FPGA的HDLBits合集

相关推荐
朝九晚五ฺ4 小时前
【Linux探索学习】第十四弹——进程优先级:深入理解操作系统中的进程优先级
linux·运维·学习
猫爪笔记5 小时前
前端:HTML (学习笔记)【1】
前端·笔记·学习·html
pq113_66 小时前
ftdi_sio应用学习笔记 3 - GPIO
笔记·学习·ftdi_sio
澄澈i6 小时前
设计模式学习[8]---原型模式
学习·设计模式·原型模式
爱米的前端小笔记7 小时前
前端八股自学笔记分享—页面布局(二)
前端·笔记·学习·面试·求职招聘
alikami7 小时前
【前端】前端学习
学习
一只小菜鸡..7 小时前
241118学习日志——[CSDIY] [ByteDance] 后端训练营 [06]
学习
fei_sun8 小时前
【Verilog】第一章作业
fpga开发·verilog
Hacker_Oldv9 小时前
网络安全的学习路线
学习·安全·web安全
蒟蒻的贤9 小时前
vue学习11.21
javascript·vue.js·学习