4位地址4元素直接映射Cache仿真无法终止问题求助
问题排查与解决方案
我来帮你拆解两个核心问题:仿真无法自动终止,以及直接映射Cache的命中逻辑错误,这俩问题都会影响你的仿真结果和运行流程。
一、仿真无法终止的原因与修复
你的测试平台在读完文件后,时钟仍然一直在翻转,仿真没收到停止指令,所以会无限运行。另外,$fscanf和$feof的使用时机也有问题:
- 当
$feof(data_file)为真时,你既没停止赋值,也没终止仿真; - 每次时钟沿都执行
$fscanf,哪怕文件已经读完,会重复读取最后一个值或者产生无效数据。
修复后的测试平台核心逻辑
修改always @(posedge clk)块,在文件读完后主动停止仿真,同时避免无效读取:
always @(posedge clk) begin if (!$feof(data_file)) begin scan_file = $fscanf(data_file, "%h\n", captured_data); read_addr <= captured_data; end else begin // 文件读取完成,打印统计结果并停止仿真 $display("Simulation finished. Hit count: %d, Miss count: %d", uut.hit_count, uut.miss_count); $fclose(data_file); // 关闭文件释放资源 $finish; end end
另外,初始化时建议先执行复位操作,让Cache进入初始无效状态:
initial begin clk = 0; reset = 1; // 先拉复位 #20 reset = 0; // 20ns后释放复位 data_file = $fopen("data_file.txt", "r"); // 增加文件打开失败的判断 if(data_file == 0) begin $display("Error: Failed to open data_file.txt!"); $finish; end end
二、直接映射Cache的命中逻辑错误
你当前的Cache逻辑完全不符合直接映射的规则:
- 4位地址应该拆分为2位标记位(Tag) + 2位索引位(Index):索引位用来选择对应的Cache行,然后比较该行的标记位和地址的标记位是否相等;
- 你现在只比较地址的标记位和
c1[0],这完全错误,应该根据索引位选择对应的c1元素再做比较。
修复后的Cache模块
module cache_memory_direct_mapped( input clk, input reset, input [3:0]read_addr, output reg hit, output reg miss, output [7:0]hit_count, // 把计数做成输出,方便测试平台打印 output [7:0]miss_count ); reg [1:0]c1[3:0]; // 每个Cache行存储2位标记位 reg [7:0]hit_count_reg = 8'h00; reg [7:0]miss_count_reg = 8'h00; // 拆分地址:[3:2]是标记位,[1:0]是索引位 wire [1:0]tag = read_addr[3:2]; wire [1:0]index = read_addr[1:0]; assign hit_count = hit_count_reg; assign miss_count = miss_count_reg; always @(posedge clk, posedge reset) begin if(reset) begin // 复位时将所有Cache行标记为无效(用x表示) c1[0] <= 2'hx; c1[1] <= 2'hx; c1[2] <= 2'hx; c1[3] <= 2'hx; hit_count_reg <= 8'h00; miss_count_reg <= 8'h00; hit <= 0; miss <= 0; end else begin // 直接映射命中判断:对应索引行的标记位等于当前地址的标记位,且标记位不是初始无效状态 if(c1[index] == tag && c1[index] !== 2'hx) begin hit <= 1; hit_count_reg <= hit_count_reg + 1; miss <= 0; end else begin hit <= 0; miss <= 1; miss_count_reg <= miss_count_reg + 1; // 缺失时,将当前地址的标记位写入对应索引的Cache行 c1[index] <= tag; end end end endmodule
三、整合后的完整测试平台
把上面的修改整合后,测试平台可以正确读取地址文件、统计命中缺失,并且自动终止仿真:
module Tb_direct_mapped; // Inputs reg clk; reg reset; reg [3:0] read_addr; // Outputs wire hit; wire miss; wire [7:0]hit_count; wire [7:0]miss_count; integer data_file ; integer scan_file ; reg [3:0]captured_data; // 地址是4位,不需要5位宽 // 例化Cache模块 cache_memory_direct_mapped uut ( .clk(clk), .reset(reset), .read_addr(read_addr), .hit(hit), .miss(miss), .hit_count(hit_count), .miss_count(miss_count) ); initial begin clk = 0; reset = 1; #20 reset = 0; data_file = $fopen("data_file.txt", "r"); if(data_file == 0) begin $display("Error: Failed to open data_file.txt!"); $finish; end end always #10 clk= ~clk; always @(posedge clk) begin if (!$feof(data_file)) begin scan_file = $fscanf(data_file, "%h\n", captured_data); read_addr <= captured_data; // 可选:打印每一步的访问结果,方便调试 $display("Address: %h, Hit: %b, Miss: %b", captured_data, hit, miss); end else begin $display("=== Final Statistics ==="); $display("Hit count: %d", hit_count); $display("Miss count: %d", miss_count); $fclose(data_file); $finish; end end endmodule
关键说明
- 地址拆分逻辑:4位地址拆分为2位标记和2位索引,完美对应4个Cache行的直接映射规则;
- 无效状态处理:复位时Cache行标记为
x,第一次访问对应行必然是缺失,直到标记被写入; - 仿真终止逻辑:用
$finish在文件读完后主动停止仿真,避免无限循环; - 调试友好性:增加了文件打开失败判断、每步访问结果打印,方便排查问题。
内容的提问来源于stack exchange,提问作者eliesmith
相关产品推荐
相关产品推荐

