多核系统的数据一致性:MESI协议状态机
单核系统中Cache对软件透明。但多核系统中,每个核心有自己的私有Cache,同一内存地址在不同Cache中可能有不同的副本和不同的值:
| 协议 | 状态数 | 代表 | 特点 |
|---|---|---|---|
| MSI | 3 | 简单多核 | 最基础,无Exclusive状态 |
| MESI | 4 | x86, ARM | 增加Exclusive,减少总线流量 |
| MOESI | 5 | AMD, ARM | 增加Owner,优化共享脏行 |
| MOESIF | 6 | Intel | 增加Forward,优化广播 |
// Lesson 38: MESI Cache Controller (simplified per-line)
module mesi_cache #(
parameter ADDR_W = 32, DATA_W = 32, ID = 0
)(
input wire clk, rst_n,
input wire [ADDR_W-1:0] cpu_addr_i,
input wire [DATA_W-1:0] cpu_wdata_i,
input wire cpu_we_i, cpu_req_i,
output reg [DATA_W-1:0] cpu_rdata_o,
output reg cpu_hit_o,
// Bus snooping interface
input wire bus_grant_i,
input wire [DATA_W-1:0] bus_data_i,
input wire [ADDR_W-1:0] bus_addr_i,
input wire bus_valid_i, bus_we_i,
output reg [ADDR_W-1:0] bus_addr_o,
output reg [DATA_W-1:0] bus_data_o,
output reg bus_req_o, bus_we_o,
output reg bus_valid_o
);
localparam M=2'd3, E=2'd2, S=2'd1, I=2'd0;
reg [1:0] state;
reg [DATA_W-1:0] line_data;
reg [ADDR_W-1:0] line_tag;
reg line_valid;
wire tag_match = line_valid && (line_tag == cpu_addr_i);
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state <= I; line_data <= 0;
line_tag <= 0; line_valid <= 0;
bus_req_o <= 0; bus_valid_o <= 0;
end else begin
bus_req_o <= 0; bus_valid_o <= 0;
bus_we_o <= 0; cpu_hit_o <= 0;
// Snoop: 远程写 → 失效
if (bus_valid_i && bus_we_i && line_valid
&& bus_addr_i == line_tag) begin
if (state == M) begin
bus_req_o <= 1; bus_data_o <= line_data;
end
state <= I;
end
// Snoop: 远程读 → 降级
else if (bus_valid_i && !bus_we_i && line_valid
&& bus_addr_i == line_tag) begin
if (state == M) begin
bus_req_o <= 1; bus_data_o <= line_data;
state <= S;
end else if (state == E) state <= S;
end
// 本地访问
else if (cpu_req_i) begin
if (tag_match) begin // 命中
cpu_hit_o <= 1; cpu_rdata_o <= line_data;
if (cpu_we_i) begin
line_data <= cpu_wdata_i;
state <= M;
end
end else begin // 未命中
cpu_hit_o <= 0;
if (bus_grant_i) begin
bus_req_o <= 1; bus_valid_o <= 1;
bus_addr_o <= cpu_addr_i;
if (cpu_we_i) begin
bus_we_o <= 1;
line_data <= cpu_wdata_i;
state <= M;
end
end
if (bus_grant_i && !cpu_we_i && bus_valid_i) begin
line_data <= bus_data_i;
line_tag <= cpu_addr_i;
line_valid <= 1;
cpu_rdata_o <= bus_data_i;
cpu_hit_o <= 1;
state <= E;
end
end
end
end
end
endmodule
| 操作 | 总线消息 | 延迟 | 频率 |
|---|---|---|---|
| E状态写(独占写) | 0 | 1周期 | ~30% |
| S→M升级写 | 1 (Invalidate) | ~5周期 | ~15% |
| I→M写未命中 | 2 (Read + Invalidate) | ~20周期 | ~10% |
| M→S共享降级 | 1 (Write-back) | ~30周期 | ~5% |