4.1 HDLBits —— 时序逻辑电路之锁存器与触发器

D触发器1

D触发器是一种可存储1位二进制数的电路,其状态会周期性更新,更新时刻通常为时钟信号的上升沿。

当使用带时钟的always块时,逻辑综合器会生成D触发器(参见alwaysblock2)。D触发器是"组合逻辑模块后接触发器"结构中最简单的形式,其中组合逻辑部分仅为一根导线。生成一个独立的D触发器。

参考答案

java 复制代码
// synthesis verilog_input_version verilog_2001
//-----------------------------------------------------------------------------
// 模块名称      : top_module
// 电路类型      : 上升沿触发基础D触发器(D Flip-Flop)
// 核心功能      : 时钟上升沿采样输入d,更新输出q;其余时刻q保持原有状态不变
// 适用场景      : 基础时序寄存、数据同步、流水线单级寄存器设计
// 关键规范      : 时序逻辑采用非阻塞赋值<=,输出定义reg型适配always块赋值
//-----------------------------------------------------------------------------
module top_module (
    input  clk,     // 全局时钟信号,上升沿触发采样动作
    input  d,       // D端串行数据输入
    output reg q    // 触发器状态输出,reg类型用于时序过程块赋值
);

// 敏感列表限定仅时钟上升沿触发,典型边沿触发时序写法
always @(posedge clk) begin
    q <= d; // 非阻塞赋值:时钟上升沿同步采样d的值更新q,硬件映射标准D触发器
end

endmodule

输出结果

D触发器2

创建8个D触发器,所有D触发器均由时钟信号的上升沿触发

参考答案

java 复制代码
// synthesis verilog_input_version verilog_2001
//-----------------------------------------------------------------------------
// 模块名称      : top_module
// 电路类型      : 8位并行上升沿D触发器组
// 核心功能      : 时钟上升沿同步采样8位并行输入d,整体刷新8位输出q;非边沿时刻保持输出稳定
// 硬件映射      : 综合生成8个相互独立、共用时钟的单比特D触发器,实现8bit数据同步寄存
// 适用场景      : 并行数据打拍、字节级流水线寄存、8位总线同步采样
//-----------------------------------------------------------------------------
module top_module (
    input         clk,      // 全局时钟信号,上升沿触发采样
    input  [7:0]  d,        // 8位并行数据输入总线
    output reg [7:0] q      // 8位寄存结果输出总线,reg类型适配always时序块赋值
);

// 敏感列表限定仅时钟上升沿触发,标准边沿时序写法
always @(posedge clk) begin
    q <= d; // 非阻塞赋值,8位总线整体同步更新,逐位映射独立D触发器
end

endmodule

输出结果

带同步复位的D触发器1

创建8个带高电平有效同步复位功能的D触发器,所有D触发器均由时钟信号的上升沿触发。

参考答案

java 复制代码
// synthesis verilog_input_version verilog_2001
//-----------------------------------------------------------------------------
// 模块名称      : top_module
// 电路类型      : 带高电平同步复位的8位上升沿D触发器组
// 触发规则      : 时钟上升沿采样;复位信号仅在时钟上升沿判定生效(同步复位特性)
// 端口说明      : clk系统时钟、reset高有效同步复位、d[7:0]8位输入、q[7:0]8位寄存输出
// 硬件映射      : 8个共用时钟与复位的D触发器并行排布,适用于字节级同步寄存场景
//-----------------------------------------------------------------------------
module top_module (
    input         clk,      // 系统时钟,上升沿作为唯一状态更新时刻
    input         reset,    // 同步复位,高电平有效,仅clk上升沿被采样判定
    input  [7:0]  d,        // 8位并行待寄存数据输入
    output reg [7:0] q      // 8位寄存器输出,reg类型适配always时序块赋值
);

// 同步复位关键特征:敏感列表只写posedge clk,复位信号不加入敏感列表
always @(posedge clk) begin
    if (reset) begin
        q <= {8{1'b0}}; // 复位生效:8位输出统一清零,等价8'b00000000
    end
    else begin
        q <= d; // 复位解除:时钟沿采样输入d更新输出q
    end
end

endmodule

输出结果

带同步复位的D触发器2

创建8个带高电平有效同步复位功能的D触发器。这些触发器复位后输出值需为0x34,而非0;所有D触发器均由时钟信号的下降沿触发。

参考答案

java 复制代码
// synthesis verilog_input_version verilog_2001
//-----------------------------------------------------------------------------
// 模块名称      : top_module
// 电路类型      : 8位下降沿触发、高电平同步复位D触发器组
// 触发规则      : 时钟下降沿更新状态;reset高有效,仅下降沿采样判定生效
// 复位固定值    : 0x34(二进制8'b00110100)
// 端口说明      : clk时钟、reset同步复位、d[7:0]并行输入、q[7:0]寄存输出
//-----------------------------------------------------------------------------
module top_module (
    input         clk,      // 系统时钟,下降沿触发状态刷新
    input         reset,    // 高电平同步复位,仅时钟下降沿生效
    input  [7:0]  d,        // 8位并行待寄存数据
    output reg [7:0] q      // 8位输出,reg适配always时序块赋值
);

// 同步复位:敏感列表仅保留时钟下降沿,复位不加入敏感列表
always @(negedge clk) begin
    if (reset) begin
        q <= 8'h34;  // 复位生效,输出固定十六进制值0x34
    end
    else begin
        q <= d;      // 复位解除,下降沿采样输入d刷新输出
    end
end

endmodule

输出结果

带异步复位的D触发器

创建8个高电平有效异步复位的D触发器,所有D触发器均由时钟信号clk的上升沿触发。

参考答案

java 复制代码
// synthesis verilog_input_version verilog_2001
//-----------------------------------------------------------------------------
// 模块名称      : top_module
// 电路类型      : 8位上升沿触发、高电平异步复位D触发器组
// 触发规则      : 正常工作在clk上升沿采样更新;areset拉高立刻清零,不受时钟约束
// 端口说明      : clk系统时钟(上升沿触发)、areset高有效异步复位、d[7:0]8位并行输入、q[7:0]寄存输出
// 硬件映射      : 8路带异步复位D触发器并行排布,适合需要紧急立即清零的时序场景
//-----------------------------------------------------------------------------
module top_module (
    input         clk,        // 系统时钟,上升沿触发数据采样
    input         areset,     // 高电平异步复位,信号跳变可直接触发清零
    input  [7:0]  d,          // 8位并行待寄存数据
    output reg [7:0] q        // 8位输出总线,reg类型适配always时序块赋值
);

// 异步复位核心特征:时钟边沿 + 复位边沿同时加入敏感列表
always @(posedge clk or posedge areset) begin
    if (areset) begin
        q <= {8{1'b0}}; // 异步复位生效,无需等待时钟沿,输出立即全0
    end
    else begin
        q <= d;         // 复位撤销,时钟上升沿采样输入d刷新输出
    end
end

endmodule

输出结果

启用字节的D触发器

实例化 16 个 D 触发器。有时我们只需要修改一组触发器中的部分寄存器,字节使能输入信号用于控制每个时钟周期内 16 位寄存器中对应字节是否写入数据:byteena1 控制高字节输入d15:8,byteena0 控制低字节输入d7:0

resetn 为同步、低电平有效复位信号。

所有 D 触发器均在时钟clk上升沿触发。

参考答案

java 复制代码
// synthesis verilog_input_version verilog_2001
//-----------------------------------------------------------------------------
// 模块名称      : top_module
// 电路类型      : 带双字节独立写使能的16位同步低复位寄存器
// 触发规则      : clk上升沿动作;resetn低电平同步复位,仅时钟沿判定生效
// 控制逻辑      : byteena[1]控制高8位、byteena[0]控制低8位,分字节选择性写入
// 端口释义
// clk       系统时钟,上升沿触发寄存器更新
// resetn    同步低电平复位,拉低时16位输出整体清零
// byteena   2bit字节写使能总线,分段控制高低字节写入权限
// d[15:0]   16位并行输入数据
// q[15:0]   16位寄存输出总线
//-----------------------------------------------------------------------------
module top_module (
    input         clk,
    input         resetn,          // 同步低电平复位(后缀n代表低有效)
    input  [1:0]  byteena,         // 字节写使能:[1]高8位、[0]低8位
    input  [15:0] d,               // 16位原始输入数据
    output reg [15:0] q            // 16位分段可控寄存输出
);

// 同步复位:敏感列表仅保留时钟上升沿,复位随时钟采样判断
always @(posedge clk) begin
    if (~resetn) begin
        q <= 16'b0; // 复位有效,高低字节统一清零
    end
    else begin
        case(byteena)
            2'b00: ;                  // 双字节均禁止写入,q保持原有值
            2'b01: q[7:0]  <= d[7:0]; // 仅低8位刷新,高8位锁存不变
            2'b10: q[15:8] <= d[15:8];// 仅高8位刷新,低8位锁存不变
            2'b11: q       <= d;      // 高低8位同步完整刷新
        endcase
    end
end

endmodule

输出结果

D锁存器

搭建下述电路:

请注意这是锁存器,因此Quartus软件提示推断出锁存器的警告属于正常现象。

参考答案

java 复制代码
// synthesis verilog_input_version verilog_2001
//-----------------------------------------------------------------------------
// 模块名称      : top_module
// 电路类型      : 高电平使能D锁存器(D Latch,电平敏感型存储器件)
// 工作模式      : ena高电平直通透明、输出跟随d变化;ena低电平保持锁存旧值
// 端口释义
// d    串行数据输入端
// ena  电平型使能控制信号,高电平有效
// q    锁存结果输出(reg型适配组合always块赋值)
// 核心特征      : 电平触发,区别边沿触发的D触发器
//-----------------------------------------------------------------------------
module top_module (
    input d,        // 待锁存数据输入
    input ena,      // 锁存使能,高电平透明导通
    output reg q    // 锁存输出端
);

// *通配敏感列表:d、ena任意电平变化都会触发逻辑更新
always @(*) begin
    if (ena) begin
        q = d;  // 使能开启:直通模式,输出实时跟随输入d
    end
    // ena=0分支不赋值,综合工具会自动生成锁存结构保留q原有数值
end

endmodule

输出结果

异步复位D触发器

搭建下述电路:

参考答案

java 复制代码
// synthesis verilog_input_version verilog_2001
//-----------------------------------------------------------------------------
// 模块名称      : top_module
// 电路类型      : 高电平异步复位、上升沿触发D触发器
// 触发规则      : 正常模式clk上升沿采样更新;ar拉高立即清零,不受时钟约束
// 端口释义
// clk 系统时钟,上升沿触发数据寄存
// d   串行数据输入
// ar  高电平异步复位(asynchronous reset缩写)
// q   触发器状态输出,reg适配时序always块赋值
//-----------------------------------------------------------------------------
module top_module (
    input  clk,      
    input  d,        
    input  ar,       
    output reg q    
);

// 异步复位核心:时钟边沿+复位边沿同时写入敏感列表
always @(posedge clk or posedge ar) begin
    if (ar) begin
        q <= 1'b0; // 异步复位生效,无需等待时钟沿,输出立刻置低
    end else begin
        q <= d;    // 复位撤销,仅时钟上升沿采样d刷新q
    end
end

endmodule

输出结果

同步复位D触发器

参考答案

java 复制代码
// synthesis verilog_input_version verilog_2001
//-----------------------------------------------------------------------------
// 模块名称:top_module
// 器件类型:上升沿触发 + 高电平同步复位D触发器
// 工作规则:状态仅在clk上升沿更新;复位r高有效,需等待时钟边沿采样生效
// 端口说明:
// clk:系统时钟,上升沿触发采样
// d:串行数据输入
// r:高电平同步复位信号
// q:触发器输出,reg型适配时序过程块赋值
//-----------------------------------------------------------------------------
module top_module (
    input  clk,
    input  d,
    input  r,
    output reg q
);

// 同步复位核心:敏感列表仅保留时钟边沿,复位不参与触发
always @(posedge clk) begin
    if (r) begin
        q <= 1'b0;
    end else begin
        q <= d;
    end
end

endmodule

输出结果

D触发器与门电路

搭建下述电路:

参考答案

java 复制代码
// synthesis verilog_input_version verilog_2001
//-----------------------------------------------------------------------------
// 模块名称      : top_module
// 器件类型      : 带使能端上升沿T触发器(可配置二分频电路)
// 核心特性      : in=1时钟上升沿输出翻转;in=0输出保持原值;持续in=1实现标准二分频
// 端口释义
// clk 系统时钟,上升沿触发状态刷新
// in  翻转使能:高电平允许状态翻转、低电平锁定输出
// out 触发器时序输出,reg型适配always时序块赋值
// 特性方程     : Q* = T ^ Q(本题T对应输入in)
//-----------------------------------------------------------------------------
module top_module (
    input  clk,
    input  in,
    output reg out
);

// 仅时钟上升沿更新状态,异或实现条件翻转逻辑
always @(posedge clk) begin
    out <= in ^ out;
end

endmodule

输出结果

多路选择器与D触发器-1

节选自2015年ECE253课程期中试卷第5题 分析下述时序电路:

假设你要为该电路编写分层Verilog代码,需要三次实例化一个包含触发器与多路选择器的子模块。请编写一个名为top_module的Verilog子模块,该模块内部包含一个触发器和一个多路选择器

参考答案

java 复制代码
// synthesis verilog_input_version verilog_2001
//-----------------------------------------------------------------------------
// 模块名称:top_module
// 整体架构:2选1多路选择器(组合逻辑) + 上升沿D触发器(时序逻辑)级联
// 控制逻辑:L=1选中r_in、L=0选中q_in;仅时钟上升沿锁存选中结果输出
// 端口说明:
// clk    系统时钟,上升沿触发寄存更新
// L      多路选择控制信号
// r_in   外部并行输入支路
// q_in   反馈输入支路
// Q      同步寄存输出
// 中间信号D:MUX组合输出,直连D触发器数据端
//-----------------------------------------------------------------------------
module top_module (
    input  clk,
    input  L,
    input  r_in,
    input  q_in,
    output reg Q
);
wire D;
// 组合逻辑2选1MUX:输入电平变化即时更新,不受时钟约束
assign D = L ? r_in : q_in;

// 边沿时序逻辑:时钟上升沿采样MUX结果完成同步锁存
always @(posedge clk) begin
    Q <= D;
end

endmodule

输出结果

多路选择器与D触发器-2

请看下方所示的 n 位移位寄存器电路:

编写一个名为top_module的Verilog模块,用于实现该电路的单级结构,模块需同时包含触发器与多路选择器。

参考答案

java 复制代码
// synthesis verilog_input_version verilog_2001
//-----------------------------------------------------------------------------
// 模块名称      : top_module
// 电路结构      : 两级级联2选1多路选择器 + 上升沿D触发器(通用移位寄存器单级单元)
// 优先级规则    : 并行加载L > 串行移位E;L=1强制加载并行数据R,L=0由E控制移位/保持
// 端口释义
// clk 全局时钟,上升沿触发状态更新
// w   串行移位输入(前级传来的移位数据)
// R   本位并行预置数据
// E   移位使能:E=1选串行输入w移位;E=0保持本位旧值Q
// L   并行加载使能(最高优先级):L=1加载R,L=0执行移位/保持逻辑
// Q   触发器寄存输出
// 中间信号 mux_E:外层MUX输出,作为内层通路候选数据
//-----------------------------------------------------------------------------
module top_module (
    input  clk,
    input  w,
    input  R,
    input  E,
    input  L,
    output reg Q
);
wire mux_E;
// 外层MUX:移位通路选择,组合逻辑实时更新
assign mux_E = E ? w : Q;

// 时序寄存:时钟上升沿按优先级完成加载/移位/保持
always @(posedge clk) begin
    Q <= L ? R : mux_E;
end

endmodule

输出结果

D触发器与逻辑门

如图所示为有限状态机电路,假设在状态机开始工作前,各D触发器已初始复位至零,搭建该电路。

参考答案

java 复制代码
// synthesis verilog_input_version verilog_2001
//-----------------------------------------------------------------------------
// 模块名称:top_module
// 电路整体架构:3位同步状态寄存器 + 次态组合逻辑 + 输出译码组合逻辑
// 工作机制:
// 1.外部输入x参与计算3路触发器次态D值(组合逻辑实时运算)
// 2.时钟上升沿同步把D锁存到状态寄存器Q,完成状态更新
// 3.由当前状态Q经过或非运算得到最终输出z(纯组合通路,无时延寄存)
// 语法修正说明:时序块赋值的状态Q声明为reg,组合驱动的D保留wire,解决编译报错
//-----------------------------------------------------------------------------
module top_module (
    input clk,      // 全局同步时钟,上升沿触发3路D触发器同步刷新状态
    input x,        // 外部单比特控制输入,参与所有位的次态逻辑运算
    output z        // 纯组合逻辑输出,直接随Q电平实时变化,不经过寄存器打拍
); 
// Q:3位触发器当前状态,在时序always块内赋值,必须声明reg类型
reg [2:0] Q;    
// D:3路组合逻辑算出的触发器输入次态,由assign连续赋值驱动,使用wire类型
wire [2:0] D;   
// 中间过渡连线:存放Q0/Q1/Q2三路状态位相或的结果,拆分逻辑提升可读性
wire q0_or_q1_or_q2; 

//====================输出译码组合逻辑层====================
// 步骤1:对3位当前状态做按位或运算,任意一位为1结果即为1
assign q0_or_q1_or_q2 = Q[0] | Q[1] | Q[2];
// 步骤2:对或运算结果取反,只有Q[2:0]全0时z输出高电平,其余时刻z拉低
assign z = ~q0_or_q1_or_q2;

//====================次态生成组合逻辑层====================
// D[0]次态规则:本位旧状态Q0和输入x异或;x=1时钟沿状态翻转,x=0保持不变
assign D[0] = Q[0] ^ x;       
// D[1]次态规则:Q1取反后和x做与运算;仅x=1且原Q1=0时,次态才会置1
assign D[1] = (~Q[1]) & x;    
// D[2]次态规则:Q2取反后和x做或运算;x=1强制次态为1,x=0取原Q2相反电平
assign D[2] = (~Q[2]) | x;    

//====================同步时序寄存层====================
// 敏感列表仅时钟上升沿,保证3位状态同步更新,避免分步跳转产生毛刺
always @(posedge clk) begin
    // 边沿时刻统一锁存预先算好的次态D,赋值给当前状态Q,采用时序标准非阻塞赋值
    Q <= D;
end
    
endmodule

输出结果

根据真值表创建电路

JK触发器具有如下真值表。仅使用1个D型触发器与逻辑门搭建实现JK触发器。注:Qold为时钟上升沿到来前D触发器的输出值。

参考答案

java 复制代码
// synthesis verilog_input_version verilog_2001
//-----------------------------------------------------------------------------
// 模块名称:top_module
// 电路功能:用D触发器+组合逻辑搭建上升沿触发标准JK触发器
// 核心原理:套用JK触发器经典次态方程 Q* = J·~Q + ~K·Q
// 架构拆分:组合逻辑计算等效D值 → 时钟上升沿D触发器锁存更新状态
// 端口说明:
// clk 同步时钟,上升沿触发状态刷新
// j   JK触发器J控制输入
// k   JK触发器K控制输入
// Q   时序状态输出,always块内赋值声明为reg类型
// 中间信号D:JK逻辑换算后的等效D触发器输入
//-----------------------------------------------------------------------------
module top_module (
    input  clk,      // 同步时钟,上升沿触发JK触发器状态更新
    input  j,        // JK触发器J控制输入端
    input  k,        // JK触发器K控制输入端
    output reg Q     // 时序输出信号,时序always块赋值必须定义reg,使用非阻塞赋值
); 
wire D; // 连线型中间信号,承接JK组合逻辑结果,作为后端D触发器输入

// 组合逻辑实现JK触发器标准次态方程:Q_next = J·~Q + ~K·Q
// 逻辑含义:J=1、K=0置1;J=0、K=1置0;J=0、K=0保持;J=1、K=1翻转
assign D = (j & ~Q) | ((~k) & Q);

// 边沿时序逻辑:仅时钟上升沿锁存次态,完成JK状态更新
always @(posedge clk) begin
    Q <= D; // 时序电路标准非阻塞赋值,保证仿真与综合时序一致
end

endmodule

输出结果

边沿检测

对于8位向量中的每一位,检测输入信号在相邻时钟周期内从0跳变为1的时刻(类似于上升沿检测)。当发生0到1的跳变后,输出位需在下一个时钟周期置1。以下为相关示例。为便于区分,输入信号第1位与上升沿检测输出第1位分开展示。

参考答案

java 复制代码
// synthesis verilog_input_version verilog_2001
//-----------------------------------------------------------------------------
// 模块名称:top_module
// 功能概述:8位并行信号上升沿检测电路,检测输入每一位0→1跳变,结果延迟1个时钟周期输出
// 实现思路:
// 1. 寄存器缓存上一拍输入值,用于和当前输入做对比
// 2. 组合逻辑实时判定单比特上升沿(现态1、前态0)
// 3. 再用一级寄存器把跳变标记延后一拍输出,匹配题目延迟要求
// 端口释义
// clk       系统时钟,全部同步采样、延迟操作均在上升沿执行
// in[7:0]   8位待检测并行输入总线
// pedge[7:0]延迟一拍后的上升沿检测结果输出总线
// 内部信号释义
// in_prev[7:0] 寄存上一个时钟周期的输入快照,跳变比对基准
// rise_flag[7:0]组合逻辑实时上升沿标记,瞬时判定哪一位发生0→1跳变
// pedge_reg[7:0]寄存延迟后的检测结果,直接驱动对外输出
//-----------------------------------------------------------------------------
module top_module (
    input         clk,          // 系统时钟,所有信号变化只在时钟上升沿生效
    input  [7:0]  in,           // 8位输入信号,要给每一位单独检测0变1的上升沿
    output [7:0]  pedge         // 8位输出信号,检测到上升沿后,晚一个时钟再输出高电平1
);
reg [7:0] in_prev;     // 寄存器:缓存上一拍输入值,作为跳变比对的历史参考值
reg [7:0] pedge_reg;   // 寄存器:对实时跳变标记再打一拍延迟,满足延后输出要求
wire [7:0] rise_flag;  // 组合连线:实时标记当前周期出现0→1上升沿的比特位

// 时序逻辑1:时钟上升沿锁存当前输入,更新历史采样值
// 本周期输入存入in_prev,下个周期比对时in_prev就是上一拍输入
always @(posedge clk) begin
    in_prev <= in;
end

// 组合逻辑上升沿判定公式:rise_flag = 当前值 & ~历史值
// 单比特逻辑:in=1且前一拍in_prev=0 → 该位上升沿有效,标记1;其余情况0
assign rise_flag = in & ~in_prev;

// 时序逻辑2:对瞬时跳变标记做一级同步延迟,实现题目延后一拍输出约束
always @(posedge clk) begin
    pedge_reg <= rise_flag;
end

// 连续赋值:把延迟寄存后的结果直通对外输出端口
assign pedge = pedge_reg;

endmodule

输出结果

双边沿检查

对于8位向量中的每一位,检测输入信号在相邻时钟周期间的电平变化(检测所有跳变沿)。在发生0到1跳变后的那个时钟周期,对应输出位应置1。以下为示例。为便于区分,输入位in1与跳变检测位anyedge1分开展示

参考答案

java 复制代码
// synthesis verilog_input_version verilog_2001
//-----------------------------------------------------------------------------
// 模块名称:top_module
// 电路功能:8位并行总线双边沿检测电路
// 检测规则:输入任意比特发生0→1上升沿 / 1→0下降沿任意跳变,检测结果延迟1个时钟周期输出高电平
// 实现架构:
// 1.一级寄存器缓存上一拍输入快照,作为电平比对基准
// 2.组合逻辑用异或运算批量判定每一位是否电平翻转
// 3.二级寄存器延迟一拍输出标记,匹配题目延后输出约束
// 端口说明
// clk        全局同步时钟,所有寄存器仅上升沿采样更新
// in[7:0]    8位待检测并行输入总线
// anyedge[7:0] 延迟一拍的双边沿跳变检测结果输出总线
// 内部信号说明
// in_reg[7:0] 寄存上一个时钟周期输入值,用于新旧电平对比
// in_flag[7:0] 组合逻辑实时双边沿标记,电平不一致对应位拉高
// anyedge_reg[7:0] 寄存延迟后的最终检测结果,直通输出端口
//-----------------------------------------------------------------------------
module top_module (
    input         clk,                // 全局时钟,所有寄存器仅在上升沿更新数值
    input  [7:0]  in,                // 8位输入总线,每一位单独检测电平跳变
    output [7:0]  anyedge            // 8位输出总线:某一位只要发生0↔1任意跳变,下一个时钟周期该位输出1
);
reg  [7:0] in_reg;             // 一级采样寄存器:延迟1拍存储上周期输入电平,提供历史比对值
wire [7:0] in_flag;            // 组合连线:实时标记当前周期出现任意电平翻转的比特位
reg  [7:0] anyedge_reg;        // 二级延迟寄存器:缓存跳变标记,实现延后一拍输出

// 时序逻辑1:时钟上升沿锁存当前输入,更新历史采样值
// 本周期输入存入in_reg,下个周期比对时in_reg即为上一拍输入,新旧值做跳变判断
always @(posedge clk) begin
    in_reg <= in;
end

// 组合逻辑双边沿判定:异或运算天然适配双边沿检测
// 运算规则:新旧电平不同(0↔1翻转)结果为1、电平保持不变结果为0,覆盖上升沿+下降沿两种场景
assign in_flag = in_reg ^ in;

// 时序逻辑2:对瞬时跳变标记同步打一拍延迟
// 严格满足题目约束:跳变发生当周期输出不变,延迟至下一个时钟周期拉高对应位
always @(posedge clk) begin
    anyedge_reg <= in_flag;
end

// 连续赋值直通输出:把二级寄存后的稳定结果对外引出
assign anyedge = anyedge_reg;

endmodule

输出结果

边沿捕获寄存器

对于 32 位向量中的每一位,捕获输入信号从前一时钟周期为 1、下一时钟周期变为 0 的跳变时刻。"捕获" 的含义是:输出电平将持续保持为 1,直到寄存器被同步复位信号清零。

每一位输出的工作特性与 SR 触发器一致:当输入发生 1 到 0 的跳变后,输出位应在跳变发生后的下一个时钟周期被置 1;当复位信号为高电平时,时钟上升沿会将对应输出位清零。若置位、复位两种操作在同一时刻触发,复位拥有更高执行优先级。下方示例波形的最后四个周期中,复位事件比置位事件提前一个周期出现,因此二者不存在时序冲突。

为方便观察区分,下方波形图将复位信号、输入第 1 位信号、输出第 1 位信号分三路单独展示。

参考答案

java 复制代码
// synthesis verilog_input_version verilog_2001
//-----------------------------------------------------------------------------
// 模块名称:top_module
// 功能概述:32位独立通道下降沿锁存检测电路
// 核心特性:单比特检测到1→0下降沿后输出永久锁存高电平,仅同步高复位可强制清零,32位通道互不干扰
// 整体架构:
// 1.一级寄存缓存上一拍输入,组合逻辑批量识别每一路下降沿
// 2.按位或实现锁存逻辑:触发下降沿则置1、无跳变保留原有状态,复位全局清零
// 端口释义
// clk        全局同步时钟,所有寄存器仅上升沿更新
// reset      高电平同步复位,优先级最高,触发时全部输出位清零
// in[31:0]   32位并行输入总线,逐位检测1→0下降沿
// out[31:0]  32位锁存输出总线,下降沿触发后置1保持、复位清零
// 内部信号释义
// in_prev[31:0] 寄存上周期输入快照,作为下降沿比对的历史基准值
// set_flag[31:0]组合逻辑下降沿标记位,1代表对应比特出现1→0跳变
// out_reg[31:0]带锁存功能的输出寄存器,实现边沿触发后状态保持
//-----------------------------------------------------------------------------
module top_module (
    input         clk,               // 时钟,只有时钟上升沿到来时,内部寄存器的值才会更新
    input         reset,             // 同步复位,高电平生效;复位优先级最高,同一时刻有复位就先清零
    input  [31:0] in,                // 32位输入信号,每一位单独判断有没有从1变0,互不影响
    output [31:0] out                // 32位输出信号,抓到1→0跳变就一直输出1,只有复位才能把它清回0
);
reg  [31:0] in_prev;    // 一级采样寄存器:延迟1拍存储上一拍输入电平,用于新旧电平对比找下降沿
wire [31:0] set_flag;   // 组合连线:实时标记出现1→0下降沿的比特位
reg  [31:0] out_reg;    // 锁存输出寄存器:边沿触发后置1锁定,仅复位可全局清零

// 时序逻辑1:时钟上升沿锁存当前输入,刷新历史比对值
// 当前周期输入存入in_prev,下个周期比对时in_prev即为上一拍输入
always @(posedge clk) begin
    in_prev <= in;
end

// 组合逻辑下降沿判定公式:set_flag = ~当前输入 & 历史输入
// 判定条件:上一拍电平为1、当前电平为0 → 发生1→0下降沿,对应位置1
assign set_flag = ~in & in_prev;

// 时序逻辑2:带同步复位的锁存状态更新,复位优先级最高
always @(posedge clk) begin
    if(reset) begin
        // 同步复位触发:32路输出统一强制清零,解除所有锁存状态
        out_reg <= 32'b0;
    end else begin
        // 锁存逻辑:检测到下降沿则置1;无跳变继承原有输出值保持不变
        // 按位或实现自锁存:新触发标记覆盖旧状态,已置1的位不会自动清零
        out_reg <= set_flag | out_reg;
        // 右侧out_reg为本周期稳定旧值,左侧out_reg是本次沿计算的次态,下一时钟周期生效
    end
end

// 连续赋值直通端口:将锁存寄存器稳定状态对外引出
assign out = out_reg;

endmodule

输出结果

双边沿触发 D 触发器

你已经熟悉仅在时钟上升沿或时钟下降沿触发的触发器。双边沿触发器会在时钟的两个跳变沿(上升沿、下降沿)都触发更新。但 FPGA 器件内部并不原生提供双边沿触发器,并且 always @(posedge clk or negedge clk) 这种敏感列表写法是不合法的,无法综合。

请搭建一个电路,使其功能行为等价于双边沿触发器。

备注:不需要做到 100% 完美等价:原生触发器输出无毛刺,但模拟该行为的组合电路可能产生毛刺,本题忽略毛刺问题。

参考答案

java 复制代码
// synthesis verilog_input_version verilog_2001
//-----------------------------------------------------------------------------
// 模块名称:top_module
// 电路类型:基于两个单边沿D触发器搭建的**等效双边沿触发器**
// 核心功能:时钟上升沿、下降沿都能采样输入d更新输出q,一个完整时钟周期采样2次数据
// 实现原理:
// 1.上升沿触发器p、下降沿触发器n交替锁存d与另一寄存器旧值的异或结果
// 2.输出q=p^n,数学推导可保证任意时钟边沿结束后q=d,实现双边沿采样效果
// 端口释义
// clk 系统时钟,提供上升沿、下降沿两种触发时机
// d   串行数据输入
// q   双边沿采样后的等效输出
// 内部信号释义
// p:上升沿触发寄存器,仅clk 0→1跳变时更新数值
// n:下降沿触发寄存器,仅clk 1→0跳变时更新数值
//-----------------------------------------------------------------------------
module top_module(
    input  clk,    // 系统时钟信号,提供上升沿、下降沿两类触发时刻
    input  d,      // 串行数据输入,双边沿都会对该输入采样
    output q       // 等效双边沿触发器最终输出
);
reg p, n;      // 两组单边沿寄存单元
               // p:上升沿专用寄存器,仅时钟0→1跳变时刷新
               // n:下降沿专用寄存器,仅时钟1→0跳变时刷新

// 时序块1:时钟上升沿触发(电平0→1)
// 运算逻辑:用当前输入d异或n的旧状态,赋值更新p
always @(posedge clk)
    p <= d ^ n;

// 时序块2:时钟下降沿触发(电平1→0)
// 运算逻辑:用当前输入d异或p的旧状态,赋值更新n
always @(negedge clk)
    n <= d ^ p;

// 组合逻辑输出:两个寄存器值异或,数学上可保证每次边沿更新后q=d
assign q = p ^ n;    

endmodule

输出结果

相关推荐
芯路行者4 小时前
5 HDLBits —— 构建更大的电路
fpga开发·verilog·fpga·hdlbits
156082072194 小时前
直流耦合采集卡前端电路调试
嵌入式硬件·fpga开发
芯路行者4 小时前
4.3 HDLBits —— 时序逻辑电路之移位寄存器
fpga开发·verilog·fpga·hdlbits
芯路行者5 小时前
4.2 HDLBits —— 时序逻辑电路之计数器
fpga开发·verilog·fpga·hdlbits
FPGA小迷弟10 小时前
FPGA时序收敛实战:从约束编写到布局布线优化全流程
fpga开发·fpga·硬件开发
FPGA小迷弟11 小时前
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