5 HDLBits —— 构建更大的电路

周期为1000的计数器

搭建一个计数范围包含0至999的计数器,总计数周期为1000个时钟周期。复位信号为同步复位,触发后计数器归零。

参考答案

java 复制代码
/*
================================================================================
模块功能:10位宽同步循环加法计数器,计数范围 0 ~ 999,到达上限自动归零循环
时序规则:同步高电平复位,仅时钟上升沿完成状态刷新
端口说明:
clk:系统时钟,上升沿触发计数更新
reset:同步高电平复位,拉高强制清零计数器
q[9:0]:10位计数输出,取值区间0~999(10bit最大可存1023,空间冗余满足需求)
================================================================================
*/
module top_module (
    input clk,               // 系统时钟,上升沿触发计数更新
    input reset,             // 同步复位信号,高电平有效复位
    output reg [9:0] q       // 10位计数输出寄存器,计数范围0~999
);
 
// 同步时序逻辑块:复位优先、正常累加、溢出归零三段分支
always @(posedge clk) begin
    if (reset) begin
        // 复位优先级最高:复位拉高时,计数器直接清零
        q <= 10'd0;
    end else if(q == 10'd999) begin
        // 计数触达周期上限999,下一拍回到初始值0,完成循环
        q <= 10'd0;
    end else begin
        // 未达到上限,每个时钟周期数值自增1
        q <= q + 10'd1;
    end
end

endmodule

输出结果

4位移位寄存器与递减计数器

本模块是五道系列习题的首题,整套题目将通过多个小型子电路搭建一套复杂计数器,整体电路架构可查阅最后一题。

请设计一款兼具4 位移位寄存器与递减计数器功能的电路:

  1. 移位使能shift_ena有效(高电平)时,串行输入数据流高位先行移入寄存器;(题目未指明送往低位还是高位,但是仿真结果是送往低位)
  2. 计数使能count_ena有效(高电平)时,寄存器内存储数值执行自减 1 操作。
    完整系统运行时,shift_ena与count_ena不会同时有效;因此若两个控制信号同时为高,电路行为不作约束(即无需规定两种功能的执行优先级)。

参考答案

java 复制代码
/*
================================================================================
模块功能:4位多功能同步寄存器,支持两种互斥工作模式
1. 串行右移模式:shift_ena=1,高位优先串行移入单bit数据data
2. 递减计数模式:count_ena=1,寄存器数值逐周期自减1
优先级规则:移位使能 > 计数使能;双使能全无效则保持数值不变
时序规则:所有更新仅在时钟上升沿执行,纯同步逻辑无异步毛刺
端口说明:
clk:系统时钟,上升沿触发寄存器刷新
shift_ena:移位模式使能,高电平开启串行右移写入
count_ena:计数模式使能,高电平开启自减计数
data:串行输入比特,4bit数据高位优先送入
q[3:0]:4位输出寄存器,q[3]最高位、q[0]最低位
移位细节:拼接式右移 {q[2:0],data},旧数据整体右移、新data补最低位,适配高位先发的串行数据流
================================================================================
*/
module top_module (
    input        clk,        // 系统时钟,上升沿触发寄存器全部更新操作
    input        shift_ena,  // 移位使能,高电平有效,开启串行移位写入模式
    input        count_ena,  // 计数使能,高电平有效,开启4位递减计数模式
    input        data,       // 串行单bit输入,整套4bit数据高位优先依次发送
    output reg [3:0] q       // 4位多功能寄存器,q[3]最高位、q[0]最低位
);
    
always @(posedge clk) begin 
    // 同步时序:仅时钟上升沿判定模式、更新寄存器值
    if(shift_ena) begin
        /* 右移逻辑解析:
        1. q[2:0]原有低3位整体左移一位到q[3:1]位置
        2. 最新串行输入data填充最低位q[0]
        3. 外部高位先发,连续移位4次后最早输入的比特最终落在最高位q[3],拼成完整并行4bit
        */
        q <= {q[2:0], data}; 
    end else if(count_ena) begin
        // 移位优先级更高;移位关闭、计数开启时,4位数值执行递减操作
        q <= q - 4'd1;
    end else begin
        // 两个使能同时无效,寄存器锁存当前值保持不变
        q <= q;
    end
end

endmodule

输出结果

有限状态机:1101序列检测器

本模块是五道系列习题的第二题,整套题目由多个小型子电路共同搭建一套复杂计数器,完整整体电路架构可查看最后一题。

设计一个有限状态机,用于在输入比特流中检测序列1101。一旦匹配到该序列,输出信号start_shifting置高并永久保持,直至复位信号到来。设计中停留在最终检测状态的机制,是用于模拟接入更大状态机中其他未实现状态的过渡逻辑,我们会在后续习题中对该有限状态机进行功能扩展。

参考答案

java 复制代码
/*
================================================================================
模块功能:串行比特流检测固定序列1101,匹配成功后拉高start_shifting并冻结状态机不再响应新输入
核心特性:
1. 复位规格:高电平同步复位,时钟上升沿生效,复位清空状态与输出标志
2. 序列捕获:逐级匹配1→1→0→1,支持重叠式序列识别逻辑
3. 锁定机制:匹配成功后start_shifting永久置1、状态机停止跳转,仅复位可解除锁定
端口说明:
clk:系统时钟,上升沿更新状态与输出
reset:同步高电平复位,复位回到空闲态、清除输出标志
data:串行单bit待检测输入
start_shifting:序列1101完整匹配后拉高的锁定输出信号
状态定义(2bit二进制编码):
IDLE=00 空闲等待首位1;S1=01 捕获第1位1;S11=10 连续捕获两位1;S110=11 捕获前三位110
================================================================================
*/
module top_module (
    input clk,
    input reset,          // 同步复位,高电平有效
    input data,           // 串行待检测比特输入
    output reg start_shifting // 1101匹配成功后拉高锁定的输出标志
);

    // 四级状态宏定义,逐级跟踪110前3位匹配进度
    localparam IDLE = 2'b00,
               S1   = 2'b01,
               S11  = 2'b10,
               S110 = 2'b11;

    reg [1:0] state, next_state;

    //==================== 时序逻辑段:状态寄存 + 输出标志更新 ====================
    always @(posedge clk) begin
        if (reset) begin
            // 同步复位优先执行:回到空闲态,清除锁定输出
            state <= IDLE;
            start_shifting <= 1'b0;
        end else begin
            state <= next_state;
            // 判定完整匹配:已走完110(S110)、新输入末位data=1,凑齐1101,拉高启动标志
            if (next_state == S110 && data == 1'b1) begin
                start_shifting <= 1'b1;
            end
            // 条件不满足不赋值,寄存器保持原有电平,实现标志锁存效果
        end
    end

    //==================== 组合逻辑段:次态跳转 + 命中冻结控制 ====================
    always @(*) begin
        if (start_shifting) begin
            // 已匹配成功:冻结状态机,禁止任何状态跳转,无视后续输入data变化
            next_state = state;
        end else begin
            case (state)
                IDLE:   next_state = (data == 1'b1) ? S1 : IDLE;   // 空闲等待首位1,遇0停留
                S1:     next_state = (data == 1'b1) ? S11 : IDLE; // 第1位1后再遇1进S11,遇0重置空闲
                S11:    next_state = (data == 1'b0) ? S110 : S11; // 连续两位1,遇0进S110,遇1保持支持重叠检测
                S110:   next_state = (data == 1'b1) ? S110 : IDLE;// 前三位110,遇1完整匹配停S110,遇0重置空闲
                default: next_state = IDLE; // 非法状态兜底复位空闲
            endcase
        end
    end

endmodule

输出结果

有限状态机:移位寄存器使能控制

这是由五个练习组成的系列中的第三个子电路,该系列利用若干较小的电路构建一个复杂计数器。整体设计请参见最后一个练习。

作为控制移位寄存器的有限状态机的一部分,我们希望能够在检测到正确的位模式时,恰好使能移位寄存器 4 个时钟周期。序列检测在 Exams/review2015_fsmseq 中处理,因此本部分的有限状态机仅负责处理使能移位寄存器 4 个周期。

每当该有限状态机复位时,将 shift_ena 置为有效并持续 4 个周期,之后永久保持为 0(直到下一次复位)。

参考答案

java 复制代码
/*
================================================================================
模块功能:同步高电平复位触发,产生固定4个时钟周期宽度的shift_ena高脉冲,脉冲结束后输出永久拉低、等待下次复位重启
时序规则:全部逻辑仅时钟上升沿更新,reset为同步高有效复位
端口说明:
clk:系统时钟,上升沿触发寄存器刷新
reset:同步高电平复位脉冲,拉高启动一轮4周期脉冲输出
shift_ena:脉冲输出信号,复位后连续4拍高电平,之后保持低电平
内部信号:
count[1:0]:2位循环计数器,计数范围0~3,标记4个脉冲周期进度
active:计数运行使能标志,高电平代表处于脉冲输出阶段
工作流程:
1. reset拉高:计数器归零、开启计数使能、shift_ena立刻拉高
2. active有效期间:count从0逐拍累加,count=0/1/2/3对应4个高电平周期
3. count到达最大值3:关闭使能、拉低输出,后续无复位则永久保持低电平
================================================================================
*/
module top_module (
    input clk,
    input reset,          // 同步复位,高有效(通常为单周期脉冲)
    output reg shift_ena  // 4周期高脉冲输出
);

    reg [1:0] count;      // 2位计数器,覆盖0~3共4个计数状态
    reg active;           // 计数阶段使能标志,控制脉冲起止

    always @(posedge clk) begin
        if (reset) begin
            // 复位优先触发:初始化计数起点、开启计数流程、拉高输出脉冲
            count     <= 2'd0;
            active    <= 1'b1;
            shift_ena <= 1'b1;
        end else if (active) begin
            if (count == 2'd3) begin
                // 走完4个周期(0/1/2/3),关闭计数流程、拉低输出
                active    <= 1'b0;
                shift_ena <= 1'b0;
            end else begin
                // 计数未到终点:计数器自增,维持输出高电平
                count     <= count + 1'b1;
                shift_ena <= 1'b1;
            end
        end else begin
            // 脉冲阶段结束,输出永久保持低电平,等待下一次复位触发
            shift_ena <= 1'b0;
        end
    end

endmodule

输出结果

有限状态机:完整状态机设计

这是由五个练习组成的系列中的第四个组件,该系列利用若干较小的电路构建一个复杂计数器。整体设计请参见最后一个练习。

建议您先完成练习 "FSM:移位寄存器使能" 和 "FSM:序列识别器"。

我们要设计一个定时器,其功能如下:

  • 当检测到特定序列(1101)时启动;
  • 再移入 4 位数据,以确定延迟时长;
  • 等待计数器完成计数;
  • 通知用户,并等待用户确认定时器完成。
    在本问题中,仅需实现控制该定时器的有限状态机。数据通路(计数器和部分比较器)不包含在本练习中。
    串行数据通过 data 输入引脚提供。当接收到序列 1101 时,状态机必须将输出 shift_ena 置为有效,并恰好持续 4 个时钟周期。
    之后,状态机将输出 counting 置为有效,以指示其正在等待计数器工作,并一直等待,直到输入 done_counting 变为高电平。
    此时,状态机必须将 done 置为有效,以通知用户定时已到,并等待输入 ack 变为 1,之后才复位并重新开始搜索下一次起始序列(1101)。
    状态机应复位到开始搜索输入序列 1101 的状态。
    以下是预期的输入输出示例。其中的 "x" 状态可能读起来稍显困惑,它表示在该时钟周期内,有限状态机不关心该特定输入信号的值。例如,一旦检测到 1101 序列,状态机将不再关注 data 输入,直到所有其他操作完成并恢复搜索为止。

参考答案

java 复制代码
/*
================================================================================
题目整体流程拆解:
1. 空闲态IDLE串行检测比特流,匹配序列`1101`
2. 匹配成功进入SHIFT态,拉高shift_ena持续4个时钟周期完成移位采样
3. 移位结束进入COUNT态,拉高counting等待外部计数器反馈done_counting
4. 计数完成进入DONE态,拉高done等待用户ack确认,收到ack回到IDLE重启检测
复位规则:同步高电平复位,时钟上升沿生效,复位回到空闲态、清空移位计数器
端口说明:
clk:系统时钟,所有状态、寄存器仅上升沿刷新
reset:同步高电平复位,强制整机回到初始空闲状态
data:串行单bit待检测输入流
shift_ena:移位阶段输出高电平,持续4拍控制外部移位寄存器工作
counting:计数等待阶段标志,高电平表示等待外部计数完成信号
done:全流程结束通知信号,高电平提示任务完成
done_counting:外部模块反馈,高电平代表计时/计数环节执行完毕
ack:用户握手确认信号,拉高后释放DONE态回到IDLE
内部信号:
state/next_state:现态、次态寄存器,7个状态用4bit编码冗余充足
shift_cnt[1:0]:移位周期计数器,0~3计数,精准控制4拍移位时长
状态流转链路:
IDLE → S1(收1) → S11(再收1) → S110(收0) → SHIFT(收1匹配1101) → COUNT → DONE →(ack)IDLE
================================================================================
*/
module top_module (
    input clk,
    input reset,           // 同步复位,高电平有效
    input data,            // 串行输入比特流
    output shift_ena,      // 移位使能,SHIFT状态持续4个时钟周期拉高
    output counting,       // COUNT状态拉高,指示等待外部计数器完成
    input done_counting,   // 外部计数器完成反馈信号
    output done,           // DONE状态拉高,全流程完成通知
    input ack              // 用户确认握手信号,收到后回到空闲重启检测
);

    // 7个工作状态本地参数定义,4位位宽预留冗余容错
    localparam IDLE  = 4'd0,  // 空闲待机:等待序列首位1
               S1    = 4'd1,  // 捕获第1位1
               S11   = 4'd2,  // 连续捕获两位1
               S110  = 4'd3,  // 捕获前三位110
               SHIFT = 4'd4,  // 4周期移位执行阶段
               COUNT = 4'd5,  // 等待外部计数完成阶段
               DONE  = 4'd6;  // 任务完成等待用户确认阶段

    reg [3:0] state, next_state;
    reg [1:0] shift_cnt;   // 移位计时计数器,取值0~3覆盖4个时钟周期

    // -------------------- 时序逻辑段:状态寄存 + 移位计数器管理 --------------------
    always @(posedge clk) begin
        if (reset) begin
            // 同步复位优先级最高:状态回归空闲、移位计数器清零
            state     <= IDLE;
            shift_cnt <= 2'd0;
        end else begin
            state <= next_state;
            // 移位计数器专属控制逻辑:进入SHIFT瞬间清零,SHIFT周期逐拍自增
            if (state == SHIFT) begin
                // 处于移位阶段,每个时钟周期计数+1
                shift_cnt <= shift_cnt + 1'b1;
            end else if (next_state == SHIFT) begin
                // 即将切入移位阶段,提前清零计数器,保证从0开始计时4拍
                shift_cnt <= 2'd0;
            end else begin
                // 非移位阶段保持计数值不变,等待下次触发
                shift_cnt <= shift_cnt;
            end
        end
    end

    // -------------------- 组合逻辑段:全状态次态跳转规则 --------------------
    always @(*) begin
        next_state = state;   // 默认保持现态,兜底规避漏分支生成隐式锁存
        case (state)
            IDLE: begin
                // 空闲等待序列首位1:data=1进入一级匹配态S1,否则持续待机
                if (data == 1'b1)
                    next_state = S1;
                else
                    next_state = IDLE;
            end

            S1: begin
                // 已拿到首位1,等待第二位1:data=1进入S11,遇0匹配失败重置空闲
                if (data == 1'b1)
                    next_state = S11;
                else
                    next_state = IDLE;
            end

            S11: begin
                // 已拿到连续两位1,等待第三位0;持续收到1保留S11,兼容重叠序列检测
                if (data == 1'b0)
                    next_state = S110;
                else
                    next_state = S11;
            end

            S110: begin
                // 已拿到前三位110,末位收1完整匹配1101进入移位阶段;收0重置从头检测
                if (data == 1'b1)
                    next_state = SHIFT;
                else
                    next_state = IDLE;
            end

            SHIFT: begin
                // 移位计时:计数走到3代表4拍移位结束,跳转等待计数态COUNT
                if (shift_cnt == 2'd3)
                    next_state = COUNT;
                else
                    next_state = SHIFT;
            end

            COUNT: begin
                // 轮询外部完成信号:收到done_counting拉高,跳转完成态DONE
                if (done_counting)
                    next_state = DONE;
                else
                    next_state = COUNT;
            end

            DONE: begin
                // 等待用户握手确认:ack拉高释放状态,回到IDLE开启新一轮序列检测
                if (ack)
                    next_state = IDLE;
                else
                    next_state = DONE;
            end

            default: next_state = IDLE; // 非法状态兜底复位空闲,增强鲁棒性
        endcase
    end

    // -------------------- Moore型组合输出译码:输出仅由当前状态决定,无输入毛刺 --------------------
    assign shift_ena = (state == SHIFT); // 仅移位阶段开启移位使能
    assign counting  = (state == COUNT); // 仅等待计数阶段拉高等待标志
    assign done      = (state == DONE);  // 仅完成阶段输出任务结束通知

endmodule

输出结果

完整定时器电路

这是由五个练习组成的系列中的第五个组件,该系列利用若干较小的电路构建一个复杂计数器。建议您先完成前四个练习(计数器、序列识别器 FSM、FSM 延时、组合 FSM)。

我们要设计一个具有单路输入的定时器,其功能如下:

  • 当检测到特定输入序列(1101)时启动;
  • 再移入 4 位数据,以确定延迟时长;
  • 等待计数器完成计数;
  • 通知用户,并等待用户确认定时器完成。

串行数据通过 data 输入引脚提供。当接收到序列 1101 时,电路必须紧接着移入后续 4 位数据,最高有效位优先。这 4 位数据决定了定时器的延迟时长,以下称为 delay3:0

之后,状态机将输出 counting 置为有效,以指示其正在计数。状态机必须计数恰好 (delay3:0 + 1) × 1000 个时钟周期。例如,delay = 0 表示计数 1000 个周期,delay = 5 表示计数 6000 个周期。同时需要输出当前剩余时间 count3:0。该输出在计数的前 1000 个周期应等于 delay,接下来的 1000 个周期等于 delay-1,依此类推,直到最后 1000 个周期为 0。当电路不处于计数状态时,count3:0 输出为无关项(您可根据实现方便自行决定其值)。

此时,电路必须将 done 置为有效,以通知用户定时已到,并等待输入 ack 变为 1,之后才复位并重新开始搜索下一次起始序列(1101)。

电路应复位到开始搜索输入序列 1101 的状态。

以下是预期的输入输出示例。其中的 "x" 状态可能读起来稍显困惑,它表示在该时钟周期内,电路不关心该特定输入信号的值。例如,一旦 1101 和 delay3:0 被读取完毕,电路将不再关注 data 输入,直到所有其他操作完成并恢复搜索为止。在该示例中,电路计数了 2000 个时钟周期,因为 delay3:0 的值为 4'b0001。最后几个周期开始了另一次计数,其 delay3:0 = 4'b1110,这将计数 15000 个周期。

参考答案

java 复制代码
//=============================================
//模块1:模1000同步循环计数器(0~999累加循环)
//功能:产生固定1000时钟周期延时基准,高电平同步复位清零
//复位规则:同步高有效,仅时钟上升沿生效
//输出q:10位宽,范围0~999,到达999自动归零循环
//=============================================
module mod_1000_cnt (
    input clk,          //系统时钟,上升沿触发计数更新
    input reset,        //同步高电平复位,拉高计数器立刻清零
    output reg [9:0] q  //计数输出总线,10bit最大可存1023,覆盖0~999需求
);
always @(posedge clk) begin
    if (reset) begin
        q <= 10'd0;         //复位优先级最高,强制清空计数值
    end else if(q == 10'd999) begin
        q <= 10'd0;         //计数触达上限999,下一拍归零开启新一轮循环
    end else begin
        q <= q + 10'd1;     //未到上限,每个时钟周期数值自增1
    end
end
endmodule

//=============================================
//模块2:4位多功能复用寄存器(串行右移写入/递减计数互斥工作)
//模式优先级:移位使能shift_ena > 计数使能count_ena
//移位规则:高位优先串行输入,{q[2:0],data}逻辑右移,新比特补最低位
//计数规则:移位关闭时,每个时钟周期数值自减1;双使能无效保持原值
//=============================================
module shift_dec_reg (
    input        clk,        //系统时钟,上升沿刷新寄存器
    input        shift_ena,  //移位模式使能,高电平开启串行写入
    input        count_ena,  //递减模式使能,高电平开启数值自减
    input        data,       //串行单bit输入,原始数据高位优先发送
    output reg [3:0] q       //4位并行输出,q[3]最高位、q[0]最低位
);
always @(posedge clk) begin
    if(shift_ena) begin
        //原有低3位整体右移一位,最新输入data填充最低位,适配高位先发数据流
        q <= {q[2:0], data};
    end else if(count_ena) begin
        //移位关闭、计数使能有效,执行逐拍递减
        q <= q - 4'd1;
    end else begin
        //两个使能同时无效,寄存器锁存当前数值保持不变
        q <= q;
    end
end
endmodule

//=============================================
//模块3:主控三段式有限状态机(核心调度单元)
//完整流转链路:IDLE空闲检测→S1(收1)→S11(连续收1)→S110(收0)→SHIFT(4拍移位)→COUNT(分段延时)→DONE(握手等待)→ack触发回到IDLE
//序列规则:匹配串行比特流1101,S11连续遇1保留状态支持重叠序列识别
//输出规则:Moore型输出,电平仅由当前状态决定,抗组合毛刺干扰
//=============================================
module main_ctrl_fsm (
    input clk,               //系统时钟,状态/计数器仅上升沿更新
    input reset,             //同步高电平复位,强制回到空闲态IDLE
    input data,              //串行待检测比特输入流
    output shift_ena,        //移位阶段标志,SHIFT状态持续拉高控制移位寄存器写入
    output counting,         //分段延时阶段标志,COUNT状态拉高
    input done_counting,     //外部延时完成反馈信号,全段倒计时结束触发跳转DONE
    output done,             //任务完成通知,DONE状态拉高等待用户确认
    input ack                //用户握手确认信号,拉高释放DONE回到IDLE重启检测
);
//7个工作状态本地参数定义,4bit位宽预留冗余容错空间
localparam IDLE  = 4'd0,   //空闲待机态:等待序列首位1输入
           S1    = 4'd1,   //一级匹配态:成功捕获第1位1
           S11   = 4'd2,   //二级匹配态:连续捕获两位1
           S110  = 4'd3,   //三级匹配态:捕获前三位110
           SHIFT = 4'd4,   //移位执行态:持续4周期写入4位寄存器
           COUNT = 4'd5,   //分段延时态:等待外部逐段倒计时完成
           DONE  = 4'd6;   //完成握手态:等待用户ack确认复位

reg [3:0] state, next_state; //现态、次态寄存器
reg [1:0] shift_cnt;         //移位计时计数器,0~3覆盖4个移位时钟周期

//--------------------------时序逻辑段:状态寄存+移位周期计数管理--------------------------
always @(posedge clk) begin
    if (reset) begin
        state     <= IDLE;    //复位清空状态,回到初始空闲态
        shift_cnt <= 2'd0;    //同步清零移位计时计数器
    end else begin
        state <= next_state;  //无复位时加载组合逻辑推导的次态
        if (state == SHIFT) begin
            //处于移位阶段,每个时钟周期计数自增
            shift_cnt <= shift_cnt + 1'b1;
        end else if (next_state == SHIFT) begin
            //即将切入移位阶段,提前清零计数器,保证从0开始精准计时4拍
            shift_cnt <= 2'd0;
        end else begin
            //非移位阶段冻结计数值,维持原有结果不变
            shift_cnt <= shift_cnt;
        end
    end
end

//--------------------------组合逻辑段:全状态次态跳转推导--------------------------
always @(*) begin
    next_state = state; //默认保持现态,兜底规避分支遗漏生成隐式锁存器
    case (state)
        IDLE:  next_state = (data) ? S1 : IDLE;   //空闲遇首位1进入一级匹配,否则持续等待
        S1:    next_state = (data) ? S11 : IDLE;   //已收1再收1进二级匹配,遇0匹配失败重置空闲
        S11:   next_state = (data) ? S11 : S110;   //连续收1保持二级态兼容重叠检测,遇0进入三级匹配
        S110:  next_state = (data) ? SHIFT : IDLE;//前三位110末位收1完整匹配1101开启移位,遇0重置空闲
        SHIFT: next_state = (shift_cnt == 2'd3) ? COUNT : SHIFT;//4拍移位结束进入分段延时,否则维持移位
        COUNT: next_state = (done_counting) ? DONE : COUNT;//收到外部完成信号跳转握手态,否则持续等待延时
        DONE:  next_state = (ack) ? IDLE : DONE;   //收到用户确认回到空闲重启检测,否则保持完成态
        default: next_state = IDLE;                //非法异常状态兜底复位空闲,提升鲁棒性
    endcase
end

//--------------------------Moore组合输出译码:输出仅绑定当前状态--------------------------
assign shift_ena = (state == SHIFT); //仅移位阶段开启写入使能
assign counting  = (state == COUNT); //仅分段延时阶段拉高等待标志
assign done      = (state == DONE);  //仅任务完成阶段输出通知信号
endmodule

//=============================================
//顶层集成模块top_module:完成所有子模块例化、内部信号互联、握手条件生成
//对外接口:原始时钟复位、串行输入、分段剩余值输出、阶段标志、握手信号
//核心联动逻辑:移位寄存保存分段数量→每满1000周期数值减1→数值归零+计时满触发完成握手
//=============================================
module top_module (
    input clk,               //全局系统时钟
    input reset,             //全局同步高电平复位,整机强制重置
    input data,              //全局串行序列检测输入
    output [3:0] count,      //对外输出分段剩余倒计时数值
    output counting,         //对外输出分段延时阶段标志
    output done,             //对外输出全流程完成通知
    input ack                //全局用户确认握手信号
);

//--------------------------内部连线信号声明--------------------------
wire shift_ena_w;        //主控FSM输出的移位使能内部连线
wire done_counting_w;    //分段延时完成反馈内部连线,传回主控FSM
wire [3:0] delay_reg_w; //4位分段倒计时寄存器内部数值
wire [9:0] cnt_val;     //模1000计数器实时计数值
wire mod1000_full;      //单轮1000周期计时满标志
reg count_ena_w;        //分段递减寄存器的计数使能
wire mod1000_rst;       //模1000计数器专属复位信号

//--------------------------例化核心主控状态机--------------------------
main_ctrl_fsm u_main_fsm (
    .clk(clk),
    .reset(reset),
    .data(data),
    .shift_ena(shift_ena_w),
    .counting(counting),
    .done_counting(done_counting_w),
    .done(done),
    .ack(ack)
);

//--------------------------生成分段递减使能:仅延时阶段+单轮1000周期结束才允许数值减1--------------------------
always @(*) begin
    count_ena_w = counting && mod1000_full;
end

//--------------------------例化4位移位递减复用寄存器--------------------------
shift_dec_reg u_shift_reg (
    .clk(clk),
    .shift_ena(shift_ena_w),
    .count_ena(count_ena_w),
    .data(data),
    .q(delay_reg_w)
);
assign count = delay_reg_w; //寄存器数值直接对外暴露

//--------------------------例化模1000周期计数器,提供单轮延时基准--------------------------
//复位条件:全局复位生效 或 退出分段延时阶段,立刻清零计时
assign mod1000_rst = reset || (~counting);
mod_1000_cnt u_mod1000_cnt (
    .clk(clk),
    .reset(mod1000_rst),
    .q(cnt_val)
);
assign mod1000_full = (cnt_val == 10'd999); //计数值到上限判定一轮延时结束

//--------------------------全流程完成判定:处于延时阶段+单轮计时满+分段剩余值归零--------------------------
assign done_counting_w = counting && mod1000_full && (delay_reg_w == 4'd0);

endmodule

输出结果

有限状态机:独热编码逻辑表达式

给定如下状态机,该状态机包含3路输入、3路输出以及10个状态:

采用下述独热编码(one-hot encoding),通过直观观察法推导次态逻辑方程与输出逻辑方程: 状态映射关系:(S, S1, S11, S110, B0, B1, B2, B3, Count, Wait) = (10'b0000000001, 10'b0000000010, 10'b0000000100, ... , 10'b1000000000)

假定使用独热编码,通过直观观察法推导状态转移逻辑方程与输出逻辑方程。 仅实现本状态机的状态转移逻辑与输出逻辑(组合逻辑部分)。 测试平台会采用非独热码输入进行测试,以此确保你的代码没有实现多余复杂逻辑。 参考fsm3onehot习题说明,了解独热状态机中 "通过直观观察推导逻辑方程" 的定义。

编写代码实现以下信号对应的逻辑方程:

  • B3_next:状态 B3 的次态逻辑
  • S_next:状态 S 的次态逻辑
  • S1_next:状态 S1 的次态逻辑
  • Count_next:状态 Count 的次态逻辑
  • Wait_next:状态 Wait 的次态逻辑
  • done:输出逻辑
  • counting:输出逻辑
  • shift_ena:输出逻辑

参考答案

java 复制代码
/*
================================================================================
模块功能说明
本模块为10位独热编码有限状态机的【组合逻辑层】,仅负责推导次态跳转信号与Moore型输出:
1. 输入:现态独热码state、串行比特d、计数完成反馈done_counting、握手确认ack
2. 输出:各目标状态跳转使能信号 + 阶段标志输出(counting/shift_ena/done)
3. 状态编码规则:10位独热码state[9:0],同一时刻仅有1bit为高电平,分别对应10个独立状态
状态映射表:
S(0)    空闲待机态,等待序列起始比特1
S1(1)   已捕获第1位1(一级匹配)
S11(2)  连续捕获两位1(二级匹配,支持重叠序列识别)
S110(3) 捕获前三位110(三级匹配)
B0(4)   移位第1拍,写入第1位串行数据
B1(5)   移位第2拍,写入第2位串行数据
B2(6)   移位第3拍,写入第3位串行数据
B3(7)   移位第4拍,写入第4位串行数据
Count(8)分段延时计数等待态
Wait(9) 任务完成、等待用户握手确认态
整体流转主线:S→S1→S11→S110→B0→B1→B2→B3→Count→Wait→(ack有效)回到S
匹配失败分支直接回落S重启检测
================================================================================
*/
module top_module(
    input d,                // 串行输入比特流,用于1101序列匹配判定
    input done_counting,    // 外部延时模块反馈:单轮1000周期计数完成标志,高有效
    input ack,              // 用户握手确认信号,高电平代表确认任务完成、复位回空闲态
    input [9:0] state,      // 10bit独热编码现态,单比特高有效,表征当前所处状态
    output B3_next,         // 跳转至B3状态的组合使能信号
    output S_next,          // 跳转/保持空闲S状态的组合使能信号
    output S1_next,        // 跳转至S1状态的组合使能信号
    output Count_next,      // 跳转/保持Count计数态的组合使能信号
    output Wait_next,       // 跳转/保持Wait握手等待态的组合使能信号
    output done,            // Moore输出:任务完成通知,仅Wait状态拉高
    output counting,        // Moore输出:计数阶段标识,仅Count状态拉高
    output shift_ena        // Moore输出:移位使能,B0~B3移位阶段全程拉高
);

// 定义10个状态对应的独热码位索引常量
parameter S     = 0,
          S1    = 1,
          S11   = 2,
          S110  = 3,
          B0    = 4,
          B1    = 5,
          B2    = 6,
          B3    = 7,
          Count = 8,
          Wait  = 9;

//==================== 次态跳转组合逻辑:逐分支推导跳转触发条件 ====================
// B3_next触发规则:仅处于移位第3拍B2时,无条件顺序跳转至移位末拍B3
assign B3_next = state[B2];

/*
S_next触发规则:四类场景跳转/保持空闲态S
1. 当前处于S、输入d=0:未检测到起始1,停留空闲重新等待
2. 当前处于S1、输入d=0:第二位匹配失败,序列中断重置回S
3. 当前处于S110、输入d=0:末位匹配失败,1101序列不成立,重置回S
4. 当前处于Wait、ack=1:用户确认任务完成,闭环回到S开启新一轮检测
*/
assign S_next = (state[S]    & ~d)
              | (state[S1]   & ~d)
              | (state[S110] & ~d)
              | (state[Wait] & ack);

// S1_next触发规则:仅处于空闲S、检测到起始比特d=1,跳转一级匹配态S1
assign S1_next = state[S] & d;

/*
Count_next触发规则:两类场景进入/保持计数态
1. 移位4拍全部结束(B3),无条件跳转分段延时Count阶段
2. 已处于Count阶段、外部计数未完成(done_counting=0),持续保持等待不跳转
*/
assign Count_next = state[B3] | (state[Count] & ~done_counting);

/*
Wait_next触发规则:两类场景进入/保持握手等待态
1. Count阶段收到计数完成反馈done_counting=1,跳转Wait等待用户确认
2. 已处于Wait阶段、未收到ack确认(ack=0),持续锁定等待状态
*/
assign Wait_next = (state[Count] & done_counting) | (state[Wait] & ~ack);

//==================== Moore型输出逻辑:电平仅由现态决定,不受输入瞬时毛刺干扰 ====================
// counting:仅分段延时Count阶段拉高,对外标识正在等待外部计时完成
assign counting = state[Count];

// shift_ena:4个连续移位节拍B0/B1/B2/B3全程拉高,控制移位寄存器串行写入4bit数据
assign shift_ena = state[B0] | state[B1] | state[B2] | state[B3];

// done:仅Wait握手等待阶段拉高,对外通知整体任务已完成,等待用户确认
assign done = state[Wait];

endmodule

输出结果

相关推荐
156082072192 小时前
直流耦合采集卡前端电路调试
嵌入式硬件·fpga开发
芯路行者2 小时前
4.3 HDLBits —— 时序逻辑电路之移位寄存器
fpga开发·verilog·fpga·hdlbits
芯路行者3 小时前
4.2 HDLBits —— 时序逻辑电路之计数器
fpga开发·verilog·fpga·hdlbits
FPGA小迷弟8 小时前
FPGA时序收敛实战:从约束编写到布局布线优化全流程
fpga开发·fpga·硬件开发
FPGA小迷弟8 小时前
AXI4-Stream协议详解与Vivado自定义IP核封装实战
网络协议·tcp/ip·fpga开发·fpga·硬件开发
zlinear数据采集卡1 天前
数据采集卡从入门到精通(10):采样率与分辨率的核心关系——反比律、架构分布与过采样
arm开发·嵌入式硬件·算法·fpga开发·架构·开源
zlinear数据采集卡1 天前
数据采集卡从入门到精通(9):分辨率与精度——16位卡不等于1/65536的精度
开发语言·数据库·fpga开发·开源·c#
Hello-FPGA1 天前
AI 如何自动通过 PDF 原理图生成管脚映射
人工智能·fpga开发·pdf
zlinear数据采集卡1 天前
数据采集卡从入门到精通(7):流水线型ADC——级级接力,高速与高精的平衡术
开发语言·arm开发·嵌入式硬件·fpga开发·c#