4.2 HDLBits —— 时序逻辑电路之计数器

4 位二进制计数器

搭建一个 4 位二进制计数器,计数范围包含 0~15,计数周期为 16。复位信号为同步复位,复位时计数器数值置 0。

参考答案

java 复制代码
// synthesis verilog_input_version verilog_2001
//-----------------------------------------------------------------------------
// 模块名称:top_module
// 电路功能:4位二进制同步加法计数器
// 参数特性:计数区间0~15、完整循环周期16个时钟周期,支持高电平同步复位
// 工作规则:
// 1.时钟上升沿统一执行复位判定或自增运算,全程同步时序
// 2.reset拉高时计数器立刻清零;复位撤销后每个时钟沿数值+1
// 3.4位天然模16计数:q=15再加1自动溢出回到0,循环往复
// 端口释义
// clk    系统时钟,上升沿触发所有状态更新
// reset  高电平同步复位,仅时钟上升沿生效,优先级高于计数自增
// q[3:0] 4位计数输出,取值范围十进制0~15
//-----------------------------------------------------------------------------
module top_module (
    input        clk,      // 系统时钟,上升沿触发寄存器状态刷新
    input        reset,    // 外部高电平同步复位,时钟上升沿采样生效
    output reg [3:0] q     // 4位计数输出,时序块赋值声明reg,范围0~15
);

// 同步时序逻辑块:所有状态变更仅在时钟上升沿执行
always @(posedge clk) begin
    // 同步复位分支:复位优先级最高,满足条件直接清零计数器
    if (reset) begin
        q <= 4'd0;
    end
    // 正常计数分支:无复位时每个时钟周期数值自增1
    // 4位位宽限制:15+1溢出自动归零,天然实现模16循环计数
    else begin
        q <= q + 1'b1;
    end
end

endmodule

输出结果

模 10 计数器

设计一个十进制计数器,计数范围包含0至9,计数周期为10。复位信号为同步复位,复位时计数器置零。

参考答案

java 复制代码
// synthesis verilog_input_version verilog_2001
//-----------------------------------------------------------------------------
// 模块名称:top_module
// 电路功能:模10同步加法十进制计数器(计数范围0~9,循环周期10个时钟周期)
// 控制规则:高电平同步复位优先级最高;计数到9后下一周期强制归零,实现十进制循环
// 端口释义
// clk        系统时钟,所有计数、复位动作仅在上升沿同步执行
// reset      高电平同步复位,需等待时钟上升沿采样生效,直接清零输出
// q[3:0]     4位计数输出,合法取值0~9,超出范围会被逻辑拦截归零
//-----------------------------------------------------------------------------
module top_module (
    input               clk,        // 系统时钟,仅上升沿执行计数/复位逻辑
    input               reset,      // 同步复位信号,高电平有效
    output reg [3:0]    q           // 4位计数输出,取值 0 ~ 9
);

// 同步时序逻辑块:状态更新严格对齐时钟上升沿,无时钟边沿不会改变数值
always @(posedge clk) begin
    // 分支1(最高优先级):同步复位触发,直接强制计数器清零
    if (reset) begin
        q <= 4'd0;
    end
    // 分支2:无复位且已计到十进制最大值9,下一时钟沿回到起点0完成循环
    else if (q == 4'd9) begin 
        q <= 4'd0;
    end
    // 分支3:常规计数阶段,每个时钟周期数值自增1
    else begin
        q <= q + 1'b1;
    end
end

endmodule

输出结果

十进制计数器

设计一个十进制计数器,计数范围包含 1 至 10。复位信号为同步复位,复位后计数器数值置为 1。

参考答案

java 复制代码
// synthesis verilog_input_version verilog_2001
//-----------------------------------------------------------------------------
// 模块名称:top_module
// 电路功能:模10同步加法计数器,计数区间1~10(首尾包含),循环周期10个时钟周期
// 控制规则:
// 1.高电平同步复位优先级最高,复位生效时计数器强制置初始值1
// 2.正常计数逐拍自增,计数到达上限10后,下一时钟沿跳转回1循环往复
// 端口释义
// clk        系统时钟,全部计数、复位逻辑仅上升沿同步执行
// reset      高电平同步复位,需等待时钟上升沿采样生效
// q[3:0]     4位计数输出,取值范围十进制1~10,10对应二进制1010
//-----------------------------------------------------------------------------
module top_module (
    input               clk,        // 输入时钟,上升沿触发所有时序逻辑
    input               reset,      // 同步复位信号,高电平有效
    output reg [3:0]    q           // 4位寄存器输出,最大数值10,二进制1010
);

// 同步时序逻辑块:所有计数值变更严格对齐时钟上升沿
always @(posedge clk) begin
    // 分支1(最高优先级):同步复位触发,强制回到计数起始值1
    if (reset) begin
        q <= 4'd1;
    end
    // 分支2:无复位且计数达到最大值10,执行循环归零跳转,回到起点1
    else if (q == 4'd10) begin
        q <= 4'd1;
    end
    // 分支3:常规区间正常逐拍自增1
    else begin
        q <= q + 4'd1;
    end
end

endmodule

输出结果

慢速十进制计数器

设计一个十进制计数器,计数范围包含0至9,计数周期为10。复位输入为同步复位,复位时将计数器置0。我们需要实现计数器暂停功能,使其不必在每个时钟周期都执行自增操作,slowena输入信号用于控制计数器何时进行数值递增。

参考答案

java 复制代码
// synthesis verilog_input_version verilog_2001
//-----------------------------------------------------------------------------
// 模块名称:top_module
// 电路功能:带计数使能的模10同步十进制计数器(0~9循环计数)
// 控制逻辑优先级:同步复位 > 使能暂停保持 > 满值归零循环 > 正常自增
// 信号规则:
// 1.reset高电平同步复位,时钟上升沿生效,计数值强制清零
// 2.slowena高电平允许计数、低电平冻结当前数值,实现慢速启停控制
// 3.计数到9后下一拍回到0,完成十进制循环
// 端口释义
// clk        系统时钟,所有时序动作仅上升沿同步执行
// slowena    计数使能,高有效;控制计数器启停
// reset      高电平同步复位,优先级最高
// q[3:0]     外部计数输出端口,由内部寄存器直通驱动
// 内部信号释义
// q_reg[3:0] 4位计数寄存器,保存0~9实时计数值,时序块内赋值
//-----------------------------------------------------------------------------
module top_module (
    input        clk,               // 系统时钟,上升沿触发全部时序逻辑
    input        slowena,           // 计数使能信号:高电平允许计数,低电平保持当前数值
    input        reset,             // 同步复位,高电平有效,复位后计数值置0
    output [3:0] q                  // 计数输出端口,默认wire类型,承接内部寄存器结果
);
reg [3:0] q_reg;           // 内部计数寄存器,存储0~9范围的实时计数值

// 同步时序逻辑块:仅时钟上升沿更新寄存器状态
always @(posedge clk) begin
    // 分支1(最高优先级):同步复位触发,直接清空计数值
    if (reset) begin
        q_reg <= 4'd0;
    end
    // 分支2:使能无效,冻结计数,保持原有数值不变
    else if (~slowena) begin
        q_reg <= q_reg;
    end
    // 分支3:使能有效且计数达到上限9,下一周期归零循环
    else if (q_reg == 4'd9) begin
        q_reg <= 4'd0;
    end
    // 分支4:使能有效且未到上限,常规逐拍自增1
    else begin
        q_reg <= q_reg + 4'd1;
    end
end

// 组合逻辑直通输出:内部寄存结果直接对外引出
assign q = q_reg;

endmodule

输出结果

模12计数器

设计一个计数范围 1~12 的计数器,包含以下输入、输出端口:

输入信号

  1. Reset:同步高电平复位;复位触发时强制计数器数值置为 1
  2. Enable:计数使能;置高电平时计数器才正常计数
  3. Clk:上升沿触发时钟输入
    输出信号
  4. Q 3:0:计数器数值输出
  5. c_enable、c_load、c_d 3:0:送往底层 4 位计数器的控制信号,用于校验电路逻辑是否正确
    可用器件资源
  6. 下方给出的 4 位二进制计数器模块 count4:自带使能输入、同步并行置数输入;置数 load 优先级高于计数使能 enable。该模块已预先提供,需要在代码中例化调用。
  7. 各类逻辑门电路
    count4 模块端口说明
java 复制代码
module count4(
        input clk,
        input enable, // 计数使能
        input load, // 同步并行置数使能(优先级更高)
        input [3:0] d, // 并行置数输入数据
        output reg [3:0] Q
);

补充说明

输出 c_enable、c_load、c_d 分别直接连接内部例化 count4 模块的 enable、load、d 端口;设置这几组对外输出,是为了方便外部观测、校验内部控制信号是否逻辑正确。

参考答案

java 复制代码
// synthesis verilog_input_version verilog_2001
//-----------------------------------------------------------------------------
// 模块名称:top_module
// 功能概述:控制内置count4子模块实现1~12循环计数,支持同步复位启停控制
// 计数规则:
// 1.复位触发/计数溢出时,同步载入初始值1;正常使能开启逐拍自增
// 2.计数上限12,仅使能有效时溢出才会回到1;使能关闭则数值冻结保持12不变
// 端口释义
// clk        系统时钟,上升沿驱动底层count4寄存器更新
// reset      同步高电平复位,触发底层同步置数、强制载入初始值1
// enable     全局计数使能:高电平允许自增/溢出重置,低电平暂停所有计数动作
// Q[3:0]     最终计数输出,合法取值范围1~12
// c_enable   转发至count4的使能信号,引出端口便于波形仿真观测
// c_load     转发至count4的同步置数控制信号,高电平触发载入c_d数值
// c_d[3:0]   转发至count4的置数常量数据,固定十进制1
// 子模块说明:count4为平台预置4位同步置数计数器,自带enable、load、d、Q标准接口
//-----------------------------------------------------------------------------
module top_module (
    input clk,               // 系统时钟,上升沿触发count4内部寄存器更新
    input reset,             // 同步高电平复位,复位时强制计数器置数值1
    input enable,            // 全局计数使能:高电平允许自增;低电平保持当前数值
    output [3:0] Q,          // 计数器对外输出,数值范围 1~12
    output c_enable,         // 送给底层count4的使能信号,引出端口用于仿真校验
    output c_load,           // 送给底层count4的同步置数信号,引出端口用于仿真校验
    output [3:0] c_d         // 送给底层count4的置数数据,固定为十进制1,引出端口校验
); 

// 逻辑1:顶层全局使能直通底层计数器,启停控制完全同步
assign c_enable = enable;

// 逻辑2:预置固定置数初值,复位、溢出重置场景统一载入十进制1(二进制0001)
assign c_d = 4'b0001;

// 逻辑3:同步置数触发条件(或逻辑二选一触发)
// 条件A:外部同步复位拉高,强制重置初值
// 条件B:使能开启+当前计数达到上限12,执行循环重置回到起点1
// 关键约束:使能关闭时即使Q=12也不触发重置,保持数值冻结
assign c_load = reset || (enable && (Q == 4'b1100));

// 例化内置4位同步置数计数器子模块count4
count4 cnt(
    .clk(clk),        // 时钟信号直连顶层全局时钟
    .enable(c_enable),// 接入顶层转发的计数使能
    .Q(Q),            // 计数输出引出至顶层,同时反馈参与溢出判断
    .load(c_load),    // 接入组合逻辑生成的同步置数控制信号
    .d(c_d)           // 接入固定初值1作为置数数据源
);

endmodule

输出结果

模1000 计数器

从 1000 Hz 时钟导出 1 Hz 信号,称为 OneHertz,该信号可用于驱动一组时/分/秒计数器的使能(Enable)输入,从而构成数字挂钟。由于我们希望时钟每秒计数一次,OneHertz 信号必须在每一秒内恰好有效(高电平)一个时钟周期。请使用模 10(BCD)计数器构建该分频器,并尽量少用其他逻辑门。同时,输出您所使用的每个 BCD 计数器的使能信号(c_enable0 对应最快计数器,c_enable2 对应最慢计数器)。

提供以下 BCD 计数器模块。enable 必须为高才能使计数器运行。reset 为同步复位,置高时将计数器强制清零。您电路中的所有计数器都必须直接使用相同的 1000 Hz 时钟信号。

java 复制代码
module bcdcount (
    input clk,
    input reset,
    input enable,
    output reg [3:0] Q
);

参考答案

java 复制代码
// synthesis verilog_input_version verilog_2001
//-----------------------------------------------------------------------------
// 模块名称:top_module
// 电路功能:3位BCD级联模1000分频电路,输入高频时钟分频输出1Hz脉冲
// 计数架构:个位、十位、百位3个十进制BCD计数器逐级进位,累计1000个时钟周期产生一次脉冲
// 控制逻辑:低位计满9才开放高位使能,实现逢十进位;全位为9时输出1Hz标志脉冲
// 端口释义
// clk         高频输入时钟,全局计数节拍基准
// reset       全局同步复位,高电平清零所有计数器,从头开始计数
// OneHertz    1Hz分频脉冲输出,个位+十位+百位同时等于9时拉高
// c_enable[2:0] 三级计数器独立使能总线,依次控制百位、十位、个位启停
// 内部信号释义
// Q0[3:0] 个位BCD计数输出(0~9)
// Q1[3:0] 十位BCD计数输出(0~9)
// Q2[3:0] 百位BCD计数输出(0~9)
// 子模块说明:bcdcount为标准带使能同步复位十进制(0~9)BCD加法计数器
//-----------------------------------------------------------------------------
module top_module (
    input clk,              // 输入时钟信号,整个计数电路的心跳节拍源
    input reset,            // 全局复位,触发后三级计数器全部清零,重启计数流程
    output OneHertz,        // 1Hz分频脉冲输出,累计满1000个时钟周期拉高一次
    output [2:0] c_enable   // 3位使能控制线:c_enable[0]个位、c_enable[1]十位、c_enable[2]百位
); 

// 三级BCD计数器输出连线,分别寄存个位、十位、百位实时计数值(取值0~9)
wire [3:0] Q0,Q1,Q2;

// 个位计数器常驻使能,每个时钟上升沿固定自增,是进位链路最基础节拍单元
assign c_enable[0] = 1'b1;

// 进位规则1:个位计满最大值9(4'b1001),十位获得计数使能,下一拍十位+1、个位归零
assign c_enable[1] = (Q0 == 4'b1001); 

// 进位规则2:个位、十位同时计满9,百位获得计数使能,实现逢百进位
assign c_enable[2] = (Q0 == 4'b1001) && (Q1 == 4'b1001); 

// 满1000周期判定:个位、十位、百位全部等于9,完成一轮0~999循环,输出1Hz脉冲标记
assign OneHertz = (Q0 == 4'b1001) && (Q1 == 4'b1001) && (Q2 == 4'b1001);

// 例化个位BCD计数器:永久使能,逐时钟自增
bcdcount counter0 (clk, reset, c_enable[0], Q0);
// 例化十位BCD计数器:仅个位满9时允许进位计数
bcdcount counter1 (clk, reset, c_enable[1], Q1);
// 例化百位BCD计数器:仅个位、十位同时满9时允许进位计数
bcdcount counter2 (clk, reset, c_enable[2], Q2);

endmodule

输出结果

4 位十进制计数器(BCD 计数器)

搭建一个4 位 BCD 十进制计数器。 每一位十进制数字用 4 位二进制编码表示:

  • q3:0:个位;
  • q7:4:十位; 更高位以此类推。
    针对第 1、2、3 位高位数字(十位、百位、千位,对应整体位段3:1),额外输出一组使能信号;该信号用于标识:对应高位数字何时需要加 1 进位。
    提示:你可以实例化或复用单路模 10 十进制(decade)计数器模块完成设计。

参考答案

java 复制代码
// synthesis verilog_input_version verilog_2001
//-----------------------------------------------------------------------------
// 顶层模块功能:4位BCD级联同步十进制计数器,计数范围0000~9999(模10000循环)
// 架构说明:个位/十位/百位/千位共4组独立模10计数器,低位满9触发高位进位使能
// 端口释义
// clk        全局同步时钟,所有计数器共用同一节拍
// reset      高电平同步复位,时钟上升沿生效,所有计数位强制清零
// ena[3:1]   进位使能输出:ena[1]十位、ena[2]百位、ena[3]千位进位开启信号
// q[15:0]    16位拼接输出:q15~q12千位、q11~q8百位、q7~q4十位、q3~q0个位
// 内部信号释义
// q0[3:0] 个位计数值 0~9
// q1[3:0] 十位计数值 0~9
// q2[3:0] 百位计数值 0~9
// q3[3:0] 千位计数值 0~9
//-----------------------------------------------------------------------------
module top_module (
    input clk,                // 全局时钟,所有十进制计数器共用节拍源
    input reset,              // 同步高电平复位,所有计数位统一清零重启
    output [3:1] ena,         // 进位使能输出:ena[1]十位、ena[2]百位、ena[3]千位进位控制
    output [15:0] q           // 16位拼接总输出:{千位,百位,十位,个位}
);
    
    // 4组4位连线,分别寄存个位、十位、百位、千位实时BCD计数值
    wire [3:0] q0,q1,q2,q3;

    // 十位进位条件:个位计数满最大值9,开放十位计数权限
    assign ena[1] = (q0 == 4'd9);
    // 百位进位条件:个位、十位同时满9,开放百位计数权限
    assign ena[2] = (q0 == 4'd9) && (q1 == 4'd9);
    // 千位进位条件:个位、十位、百位同时满9,开放千位计数权限
    assign ena[3] = (q0 == 4'd9) && (q1 == 4'd9) && (q2 == 4'd9);
    
    // 位拼接组合逻辑:高位在前、低位在后,合并4组BCD值为16位总线输出
    assign q = {q3,q2,q1,q0};
    
    // 个位计数器:永久使能,每个时钟周期固定自增,进位链路最基础单元
    decade_counter cnt0(
        .clk(clk),
        .reset(reset),
        .en(1'b1),
        .q(q0)
    );
    // 十位计数器:仅个位满9时开启计数,实现逢十进位
    decade_counter cnt1(
        .clk(clk),
        .reset(reset),
        .en(ena[1]),
        .q(q1)
    );
    // 百位计数器:仅个位+十位同时满9时开启计数,实现逢百进位
    decade_counter cnt2(
        .clk(clk),
        .reset(reset),
        .en(ena[2]),
        .q(q2)
    );
    // 千位计数器:仅低三位同时满9时开启计数,实现逢千进位
    decade_counter cnt3(
        .clk(clk),
        .reset(reset),
        .en(ena[3]),
        .q(q3)
    );

endmodule

//-----------------------------------------------------------------------------
// 底层子模块:单位模10 BCD同步加法计数器(计数区间0~9循环)
// 控制规则:同步复位优先级最高;使能拉高逐拍自增,计到9自动归零
// 端口释义
// clk  时钟节拍
// reset 高电平同步复位,上升沿清零输出
// en   计数使能,高电平允许自增,低电平数值保持
// q    4位BCD计数输出,取值0~9
//-----------------------------------------------------------------------------
module decade_counter(
    input clk,        
    input reset,      
    input en,         
    output reg [3:0] q
);
// 同步时序逻辑:仅时钟上升沿更新状态
always @(posedge clk) begin
    if(reset)
        q <= 4'd0;          // 复位触发,强制清零计数器
    else if(en) begin       // 无复位且使能有效,执行计数逻辑
        if(q == 4'd9)
           q <= 4'd0;      // 达到十进制上限9,下一拍归零循环
        else
           q <= q + 4'd1;  // 未到上限,常规逐拍自增1
    end     
end
endmodule

输出结果

12 小时制时钟

设计一组适用于 12 小时制时钟的计数器(附带上午 / 下午标识位)。计数器由高速时钟clk驱动;每当时钟需要走时(即每秒一次)时,使能信号ena产生脉冲。复位信号reset会将时钟重置为上午 12:00。pm为 0 代表上午,为 1 代表下午。hh、mm、ss均各由两位 BCD 码(二进制编码十进制)组成:小时范围 01--12,分钟 00--59,秒钟 00--59。 复位优先级高于使能,即便使能未开启,复位也能生效。 下方时序图展示两种切换逻辑:上午 11:59:59 跳转为下午 12:00:00 的进位规则,以及同步复位、使能的时序行为。

参考答案

java 复制代码
//========================================================================
// 子模块1:十进制BCD个位计数器(0~9循环)
// 复用场景:秒个位、分钟个位共用此模块
// 端口说明:
// clk     同步时钟,上升沿更新寄存器数值
// reset   同步高电平复位,优先级高于计数使能
// en      计数使能,高电平允许数值自增1
// q       4bit 8421BCD输出,数值范围0~9
// carry   进位输出标志,仅当q==9且en=1时carry=1,用于向高位进位
// 计数规则:0→1→2...→9→0,满9归零并输出进位
//========================================================================
module bcd_0to9
#(
    parameter RST_DATA = 4'd0  // 复位后默认输出数值为0
)
(
    input               clk,
    input               reset,
    input               en,
    output reg [3:0]    q,
    output              carry
);
// 组合逻辑生成进位信号:数值到9且使能打开,进位拉高
assign carry = (q == 4'd9) && en;

always @(posedge clk) begin
    // 复位优先级最高,复位触发直接赋值初始值
    if(reset) begin
        q <= RST_DATA;
    end
    // 无复位、计数使能有效,执行BCD循环计数
    else if(en) begin
        if(q == 4'd9) begin
            q <= 4'd0; // 个位计满9归零,同时carry输出进位给高位
        end
        else begin
            q <= q + 1'b1; // 未到最大值,正常自增1
        end
    end
end
endmodule

//========================================================================
// 子模块2:六进制BCD十位计数器(0~5循环)
// 复用场景:秒十位、分钟十位共用,00~59计时高位最大仅到5
// 端口功能与bcd_0to9完全一致,仅计数上限改为5
// 计数规则:0→1→2...→5→0,满5归零并输出进位
//========================================================================
module bcd_0to5
(
    input               clk,
    input               reset,
    input               en,
    output reg [3:0]    q,
    output              carry
);
// 进位逻辑:数值等于5且使能打开,进位输出高电平
assign carry = (q == 4'd5) && en;

always @(posedge clk) begin
    if(reset) begin
        q <= 4'd0; // 分、秒十位复位统一清零
    end
    else if(en) begin
        if(q == 4'd5) begin
            q <= 4'd0; // 十位计满5归零,向更高一级输出进位
        end
        else begin
            q <= q + 1'b1;
        end
    end
end
endmodule

//========================================================================
// 子模块3:12小时制双BCD状态机(FPGA工程三分支优化写法)
// 硬件存储:两组独立4bit寄存器分别存放小时十位hr_high、个位hr_low
// 全部有效状态(两位BCD):01,02,03,04,05,06,07,08,09,10,11,12
// 完整循环流转顺序:12 → 01 → 02 → 03~09 → 10 → 11 → 12
// 端口说明:
// clk      同步时钟上升沿更新小时状态
// reset    同步复位,复位后固定状态12,pm=0代表上午AM
// en_h     小时切换使能,仅时间走到59分59秒时拉高,才更新小时
// hr_low   小时个位BCD寄存器输出
// hr_high  小时十位BCD寄存器输出
// pm       上下午标识,0=上午,1=下午;仅11跳转12时翻转电平
// 分支设计优势:仅3层判断,减少组合逻辑级数,降低FPGA LUT消耗、时序更稳
// 分支划分:
// 1. 单独处理特殊状态12,强制跳转01,无PM翻转
// 2. 单独处理特殊状态11,跳转12并翻转PM标识
// 3. 剩余01~10全部共用一套通用自增逻辑,无特殊操作
//========================================================================
module hour_2bcd_12
(
    input               clk,
    input               reset,
    input               en_h,
    output reg [3:0]    hr_low,
    output reg [3:0]    hr_high,
    output reg          pm
);
always @(posedge clk) begin
    // 复位逻辑:强制小时BCD输出12,pm置0代表上午
    if(reset) begin
        hr_high <= 4'd1;
        hr_low  <= 4'd2;
        pm      <= 1'b0;
    end
    // 只有分秒同时满59,en_h=1,才执行一次小时状态更新
    else if(en_h) begin
        // ========== 分支1:当前小时BCD为12(十位1,个位2) ==========
        // 特殊跳转:正常+1会得到13,不符合12小时制,强制赋值为01
        // 上下午标识pm保持原有电平,不翻转
        if(hr_high == 4'd1 && hr_low == 4'd2) begin
            hr_high <= 4'd0;
            hr_low  <= 4'd1;
        end
        // ========== 分支2:当前小时BCD为11(十位1,个位1) ==========
        // 特殊跳转:跳转为12,同时翻转pm电平,实现上下午切换
        else if(hr_high == 4'd1 && hr_low == 4'd1) begin
            hr_high <= 4'd1;
            hr_low  <= 4'd2;
            pm      <= ~pm;
        end
        // ========== 分支3:剩余所有常规小时 01,02,03~09,10 通用逻辑 ==========
        // 该区间所有小时自增规则完全统一,无需拆分多个if判断,节约硬件资源
        // 规则:个位数值+1;若个位计满9,则个位清零、十位自增1(09进位到10)
        else begin
            // 个位到达9,需要向十位进位
            if(hr_low == 4'd9) begin
                hr_low  <= 4'd0;        // 个位归零
                hr_high <= hr_high + 1'b1; // 十位自增1
            end
            else begin
                hr_low <= hr_low + 1'b1;    // 个位未到9,仅个位数字+1
            end
        end
    end
end
endmodule

//========================================================================
// 顶层总模块 top_module
// 设计约束硬性要求:秒个位计数器使能端口直接连接顶层全局计时开关ena
// 输出格式说明:hh/mm/ss均为8位双8421BCD,高4bit是十位,低4bit是个位
// 复位规则:reset复位优先级高于ena,复位后全局时间锁定12:00:00 AM
// 进位联动机制:低位计数器计满产生进位,逐级控制高位计数使能,实现60进制时分秒
//========================================================================
module top_module(
    input               clk,        // 系统全局同步时钟
    input               reset,      // 同步复位信号
    input               ena,        // 全局计时总开关,高电平时钟正常走时,低电平全部暂停
    output              pm,         // 向外输出上下午标识信号
    output [7:0]        hh,         // 小时8位BCD输出,范围01~12
    output [7:0]        mm,         // 分钟8位BCD输出,范围00~59
    output [7:0]        ss          // 秒钟8位BCD输出,范围00~59
);
// ---------------------- 内部连线定义:时分秒十位、个位4位BCD信号 ----------------------
wire [3:0] sec_low,  sec_high;  // sec=秒,low个位,high十位
wire [3:0] min_low,  min_high;  // min=分钟,low个位,high十位
wire [3:0] hr_low,   hr_high;   // hr=小时,low个位,high十位

// ---------------------- 底层计数器进位输出信号定义 ----------------------
wire carry_sec_low;  // 秒个位bcd_0to9模块的进位输出
wire carry_sec_high; // 秒十位bcd_0to5模块的进位输出
wire carry_min_low;  // 分钟个位bcd_0to9模块的进位输出
wire carry_min_high; // 分钟十位bcd_0to5模块的进位输出

// ---------------------- 各级计数器计数使能信号(由进位组合逻辑生成) ----------------------
wire en_sec_high;    // 秒十位计数器的计数允许开关
wire en_min_low;     // 分钟个位计数器的计数允许开关
wire en_min_high;    // 分钟十位计数器的计数允许开关
wire en_hour;        // 小时状态跳转使能,仅59分59秒时有效

// ====================== 进位逐级传递逻辑详细注释 ======================
// 规则:只有低位完整计满、进位标志为1时,高位才获得计数使能,实现逢十/逢六十进位
// en_sec_high:秒十位使能,仅秒个位走到9(carry_sec_low=1)时允许秒十位+1
assign en_sec_high = carry_sec_low;

// en_min_low:分钟个位使能,必须秒钟刚好走完完整60秒(秒个位9+秒十位5,两个进位同时为1)
// 到达整分钟节点,分钟数值才+1
assign en_min_low  = carry_sec_low && carry_sec_high;

// en_min_high:分钟十位使能,两个条件同时成立
// 条件1:秒钟满60秒;条件2:分钟个位走到9
// 只有分钟个位到9且秒走完60秒,分钟十位才能进位自增
assign en_min_high = carry_sec_low && carry_sec_high && carry_min_low;

// en_hour:小时切换总使能,四个进位全部同时拉高代表当前时间为XX:59:59
// 秒个位满9 + 秒十位满5 + 分个位满9 + 分十位满5
// 仅此时刻en_hour=1,小时状态执行一次更新
assign en_hour     = carry_sec_low && carry_sec_high && carry_min_low && carry_min_high;

// ==================== 秒钟双BCD模块例化(实现00~59六十秒循环) ====================
// 秒个位模块:严格遵循要求,使能en直接连接顶层全局计时开关ena,无中间逻辑中转
bcd_0to9 sec_unit_low(
    .clk(clk),
    .reset(reset),
    .en(ena),
    .q(sec_low),
    .carry(carry_sec_low) // 模块进位输出绑定信号carry_sec_low ,做为秒 十 位的使能信号
);
// 秒十位模块:0~5六进制计数器,计数使能来自秒个位进位carry_sec_low
bcd_0to5 sec_unit_high(
    .clk(clk),
    .reset(reset),
    .en(en_sec_high),
    .q(sec_high),
    .carry(carry_sec_high)
);

// ==================== 分钟双BCD模块例化(实现00~59六十分循环) ====================
bcd_0to9 min_unit_low(
    .clk(clk),
    .reset(reset),
    .en(en_min_low),
    .q(min_low),
    .carry(carry_min_low)
);
bcd_0to5 min_unit_high(
    .clk(clk),
    .reset(reset),
    .en(en_min_high),
    .q(min_high),
    .carry(carry_min_high)
);

// ==================== 12小时三分支状态机模块例化 ====================
hour_2bcd_12 hour_unit(
    .clk(clk),
    .reset(reset),
    .en_h(en_hour),
    .hr_low(hr_low),
    .hr_high(hr_high),
    .pm(pm)
);

// ==================== 8位双BCD输出拼接逻辑 ====================
// 拼接规则:{十位4bitBCD,个位4bitBCD},组合为8位输出供给数码管显示
assign ss = {sec_high, sec_low};
assign mm = {min_high, min_low};
assign hh = {hr_high, hr_low};

endmodule

输出结果

相关推荐
FPGA小迷弟6 小时前
FPGA时序收敛实战:从约束编写到布局布线优化全流程
fpga开发·fpga·硬件开发
FPGA小迷弟7 小时前
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#
鬼手点金2 天前
FPGA常用型号参考
fpga开发·verilog·vivado·xilinx·vhdl·altera·lattice
FPGA-ADDA2 天前
雷通微系统推出RTSD2605:RFSoC + 英伟达GPU一体化信号处理平台
信号处理·fpga·rfsoc·zu47dr·47dr
Kong_19943 天前
芯片开发学习笔记·二十九——大模型基础知识与 KV Cache 详解
fpga开发·芯片开发