Muller C门(C-element)是异步电路最基本也最重要的构建块,由David Muller于1959年提出。它是一种状态保持逻辑门,其行为不同于任何标准组合逻辑门:
关键洞察:C门本质上是带状态的AND门——输出变1需要两个输入都为1(像AND),但输出变0也需要两个输入都为0(像OR取反)。当输入不一致时,它"记住"上一次一致时的值。
C门有多种电路实现方式。最经典的是使用弱反馈反相器保持状态:
// muller_c_element.v
// Muller C门 — 异步电路基本构建块
// 当输入一致时输出跟随,不一致时保持
module muller_c_element (
input wire a,
input wire b,
output reg c_out
);
always @(*) begin
if (a == b)
c_out = a; // 输入一致:输出跟随
// else: c_out 保持不变(reg的默认行为)
end
endmodule
上述行为级模型在综合时可能产生意外结果——标准综合工具会尝试将C门优化为纯组合逻辑。实际工程中有几种处理方法:
// muller_c_gate_equiv.v
// 用标准门等效实现Muller C门
// C = AB + (A+B)C_prev = AB + AC_prev + BC_prev
module muller_c_gate_equiv (
input wire a,
input wire b,
output wire c_out
);
// C门布尔方程:
// 当 A=B=1: C = 1
// 当 A=B=0: C = 0
// 当 A≠B: C = C_prev
//
// 实现:C = AB + (A+B)·C_prev
// 等价于:C = AB + AC_prev + BC_prev
// 这就是C门的SR锁存器视角
wire ab, a_or_b;
assign ab = a & b; // 一致为1
assign a_or_b = a | b; // 至少一个为1
// C = AB + (A+B)·C_prev
// 使用SR锁存器结构
// S = AB (置位条件)
// R = ~A·~B (复位条件)
// 当 S=R=0 (输入不一致),锁存器保持
// 用门级实现(反馈环)
wire s_n, r_n, c_int;
assign s_n = ~(a & b); // 置位(低有效)
assign r_n = ~(~a & ~b); // 复位(低有效)
// 交叉耦合NAND构成SR锁存器
assign c_int = ~(s_n & c_out); // 这里c_out是反馈
assign c_out = ~(r_n & c_int); // 形成2-NAND锁存器
endmodule
// muller_c_reset.v
// 带异步复位的Muller C门
// 复位信号可以强制输出为0,不受输入影响
module muller_c_reset (
input wire a,
input wire b,
input wire rst_n, // 异步复位(低有效)
output reg c_out
);
always @(*) begin
if (!rst_n)
c_out = 1'b0; // 复位优先
else if (a == b)
c_out = a; // 输入一致:跟随
// else: 保持不变
end
endmodule
C门可以推广到N个输入——只有所有输入都为1时输出才变1,所有输入都为0时输出才变0:
// muller_c_n_input.v
// N输入Muller C门
// 所有输入一致时输出跟随,否则保持
module muller_c_n_input #(
parameter N = 4
)(
input wire [N-1:0] inputs,
output reg c_out
);
wire all_one, all_zero;
assign all_one = &inputs; // 所有位为1
assign all_zero = ~|inputs; // 所有位为0
always @(*) begin
if (all_one)
c_out = 1'b1;
else if (all_zero)
c_out = 1'b0;
// else: 保持不变
end
endmodule
4-phase握手的完成检测(Completion Detection)是C门的经典应用——当所有数据位都稳定后,C门输出才变化:
// completion_detector.v
// 完成检测器 — 用C门检测所有数据位是否稳定
// 在双轨编码中,每个数据位用2根线表示,
// 当所有位的"有效"线都为1时,C门输出1表示数据全部就绪
module completion_detector #(
parameter WIDTH = 4 // 数据位宽
)(
input wire [WIDTH-1:0] valid_bits, // 每位的有效信号
output wire all_valid // 所有位都有效
);
// 使用N输入C门:所有valid_bits为1时输出1
// 所有valid_bits为0时输出0(表示需要新数据)
muller_c_n_input #(.N(WIDTH)) u_c (
.inputs(valid_bits),
.c_out(all_valid)
);
endmodule
这是C门最优雅的应用——用C门链构建异步流水线的控制电路。每一级的C门在前一级完成且后一级空闲时才传递数据:
// c_element_pipeline.v
// 用C门链实现异步流水线控制
// 经典的Sutherland微流水线(Micropipeline)结构
module c_element_pipeline #(
parameter STAGES = 4 // 流水线级数
)(
input wire rst_n,
input wire req_in, // 输入请求
output wire ack_in, // 输入应答
output wire [STAGES:0] req_chain, // 请求信号链
output wire [STAGES:0] ack_chain // 应答信号链
);
// 请求链:C门级联
// req[i] = C(req[i-1], ack[i+1])
// 含义:前级有请求 且 后级已空闲 → 传递请求
assign req_chain[0] = req_in;
genvar i;
generate
for (i = 1; i <= STAGES; i = i + 1) begin : gen_req_c
muller_c_reset u_c_req (
.a(req_chain[i-1]),
.b(ack_chain[i]),
.rst_n(rst_n),
.c_out(req_chain[i])
);
end
endgenerate
// 应答链:C门级联(反向传播)
// ack[i] = C(ack[i+1], req[i])
// 含义:后级已应答 且 当前级有请求 → 向前级应答
assign ack_chain[STAGES] = 1'b0; // 末端初始无应答
generate
for (i = STAGES-1; i >= 0; i = i - 1) begin : gen_ack_c
muller_c_reset u_c_ack (
.a(ack_chain[i+1]),
.b(req_chain[i+1]),
.rst_n(rst_n),
.c_out(ack_chain[i])
);
end
endgenerate
assign ack_in = ack_chain[0];
endmodule
1. 状态保持视角:C门是一个带条件的状态保持元件——只有输入一致时才允许状态改变。
2. SR锁存器视角:C门等价于一个带门控的SR锁存器:
3. 事件同步视角:C门是一个事件汇合点(Join)——两个事件都发生后才产生输出事件。
4. 一致性投票视角:N输入C门是一致性投票器——全员同意才改变决定。
// tb_muller_c_element.v
// Muller C门及其扩展模块测试
\`timescale 1ns/1ps
module tb_muller_c_element;
reg a, b, rst_n;
wire c_out;
muller_c_reset uut (
.a(a), .b(b), .rst_n(rst_n), .c_out(c_out)
);
// 测试序列
initial begin
$dumpfile("muller_c.vcd");
$dumpvars(0, tb_muller_c_element);
// 初始化
a = 0; b = 0; rst_n = 0;
#10 rst_n = 1;
// 测试1: 一致输入 → 输出跟随
$display("--- Test 1: Consistent inputs ---");
a = 0; b = 0; #5;
$display("a=%b b=%b c=%b (expect 0)", a, b, c_out);
a = 1; b = 1; #5;
$display("a=%b b=%b c=%b (expect 1)", a, b, c_out);
a = 0; b = 0; #5;
$display("a=%b b=%b c=%b (expect 0)", a, b, c_out);
// 测试2: 不一致输入 → 输出保持
$display("--- Test 2: Inconsistent inputs ---");
a = 0; b = 0; #5; // c=0
a = 1; b = 0; #5; // 不一致,c保持0
$display("a=%b b=%b c=%b (expect 0, held)", a, b, c_out);
a = 0; b = 1; #5; // 不一致,c保持0
$display("a=%b b=%b c=%b (expect 0, held)", a, b, c_out);
a = 1; b = 1; #5; // 一致,c变1
$display("a=%b b=%b c=%b (expect 1)", a, b, c_out);
a = 1; b = 0; #5; // 不一致,c保持1
$display("a=%b b=%b c=%b (expect 1, held)", a, b, c_out);
// 测试3: 复位
$display("--- Test 3: Reset ---");
a = 1; b = 1; #5; // c=1
rst_n = 0; #5; // 复位
$display("rst_n=%b c=%b (expect 0)", rst_n, c_out);
rst_n = 1; #5;
a = 0; b = 0; #5;
$display("After reset: a=%b b=%b c=%b (expect 0)", a, b, c_out);
// 测试4: 快速输入变化
$display("--- Test 4: Rapid changes ---");
repeat(20) begin
a = $random; b = $random;
#2;
$display("a=%b b=%b c=%b", a, b, c_out);
end
$display("=== C-element Test Complete ===");
$finish;
end
endmodule
虽然完整的异步FIFO将在后续课程实现,这里先揭示C门在其中的关键作用——跨时钟域的完成检测:
步进控制器(Steering Logic)是异步电路中控制数据流向的关键结构。C门在其中扮演"路由决策"的角色——根据握手信号的状态决定数据流向哪条路径:
// async_steering_logic.v
// 异步步进控制器 — 用C门实现数据路由
// 类似同步设计中的MUX,但由握手信号控制
module async_steering_logic #(
parameter DATA_WIDTH = 8
)(
input wire clk,
input wire rst_n,
// 输入握手
input wire [DATA_WIDTH-1:0] data_i,
input wire req_i,
output reg ack_o,
// 选择信号(来自控制器)
input wire sel, // 0→通道A, 1→通道B
// 输出通道A
output reg [DATA_WIDTH-1:0] data_a_o,
output reg req_a_o,
input wire ack_a_i,
// 输出通道B
output reg [DATA_WIDTH-1:0] data_b_o,
output reg req_b_o,
input wire ack_b_i
);
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
ack_o <= 1'b0;
data_a_o <= {DATA_WIDTH{1'b0}};
data_b_o <= {DATA_WIDTH{1'b0}};
req_a_o <= 1'b0;
req_b_o <= 1'b0;
end else begin
case (sel)
1'b0: begin // 路由到通道A
if (req_i && !req_a_o) begin
data_a_o <= data_i;
req_a_o <= 1'b1;
end
if (ack_a_i) begin
ack_o <= 1'b1;
req_a_o <= 1'b0;
end
if (!req_i && ack_o) begin
ack_o <= 1'b0;
end
end
1'b1: begin // 路由到通道B
if (req_i && !req_b_o) begin
data_b_o <= data_i;
req_b_o <= 1'b1;
end
if (ack_b_i) begin
ack_o <= 1'b1;
req_b_o <= 1'b0;
end
if (!req_i && ack_o) begin
ack_o <= 1'b0;
end
end
endcase
end
end
endmodule
步进逻辑的核心思想:数据通路(MUX)和控制通路(C门+握手)协同工作,控制通路决定数据通路的选择,数据通路的延迟由控制通路匹配。
| 参数 | 符号 | 典型值(65nm) | 说明 |
|---|---|---|---|
| 输入一致→输出变化 | tpd | ~80ps | 两个输入同时变化到输出变化 |
| 单输入变化→保持 | thold | N/A | 输出不变,无时序约束 |
| 输入建立时间 | tsu | ~30ps | 两个输入需同时有效的时间 |
| 状态保持时间 | tretain | 无限(静态) | 输出可无限期保持 |
C门链的延迟特性与反相器链不同——每个C门的延迟取决于其输入的"一致性到达时间"。如果两个输入精确同时到达,延迟最短;如果一个输入先到,C门需要等待另一个输入。
在流水线应用中,这意味着最慢的C门决定流水线吞吐率,类似于同步流水线中最慢的一级决定时钟频率。但关键区别是:异步流水线中,不同数据可能通过不同的路径(条件分支),每个数据的实际延迟取决于其路径。
1. 证明题:证明 C = AB + (A+B)C_prev 与C门的行为定义等价。提示:分A=B=1, A=B=0, A≠B三种情况代入验证。
2. 设计题:用C门实现一个3输入仲裁器的完成检测——3个处理单元都完成工作后才产生"全部完成"信号。
3. 编程题:实现c_element_pipeline的完整测试台,验证4级流水线中数据的正确传播和背压机制。
4. 分析题:在Sutherland微流水线中,如果某一级的C门由于工艺偏差延迟特别大,会对整体吞吐率产生什么影响?与同步流水线对比分析。
5. 思考题:现代FPGA中没有C门原语。如何在FPGA上高效实现C门?提示:考虑FPGA的LUT结构和反馈路径。
🎯 掌握了Muller C门的原理、实现与应用
📍 里程碑:理解了异步电路最核心的构建块
💡 下一步:学习异步控制路径设计