RAM读写顺序异常求助:写入与读取结果错位
Verilog RAM模块读写错位问题排查与修复
问题现象
向RAM的000地址写入'A'、001地址写入'B'……111地址写入'H',读取时000地址显示'B',001地址显示'C',后续结果依次错位。
原设计模块代码
module task ( input [2:0] address_ram, input [7:0] data_in, output [(DATA_WIDTH-1):0] q_ram, input clk, input rst, input we ); parameter DATA_WIDTH = 8; parameter ADDR_WIDTH = 8; // RAM content reg [DATA_WIDTH-1:0] ram [2**ADDR_WIDTH-1:0]; reg [ADDR_WIDTH-1:0] addr_r; always @(posedge clk or negedge rst) begin if (rst) begin // Reset condition addr_r <= 8'b0; end else begin // WRITE to RAM if (we) begin ram[addr_r] <= data_in; end // READ from RAM addr_r <= address_ram; end end assign q_ram = ram[address_ram]; endmodule
原测试平台代码
// Code your testbench here // or browse Examples module task_tb; // Parameters parameter DATA_WIDTH = 8; parameter ADDR_WIDTH = 8; // Inputs and Outputs reg clk, rst, we; reg [DATA_WIDTH-1:0] data_in; reg [2:0] address_ram; wire [(DATA_WIDTH-1):0] q_ram_out; // Instantiate the home_task module home_task uut ( .clk(clk), .rst(rst), .we(we), .address_ram(address_ram), .data_in(data_in), .q_ram(q_ram_out) ); // Clock Generation always begin #5 clk = ~clk; // Toggle the clock every 5 time units end // Initial Block initial begin clk = 0; rst = 0; // Assert reset initially we = 0; data_in = 8'b01000001; address_ram = 3'b000; result = 1; // Apply reset for some time #10 rst = 0; #10; // Write data to RAM we = 1; address_ram = 3'b000; data_in = 8'b01000001; // 'A' #10; we = 1; address_ram = 3'b001; data_in = 8'b01000010; // 'B' #10; we = 1; address_ram = 3'b010; data_in = 8'b01000011; // 'C' #10; we = 1; address_ram = 3'b011; data_in = 8'b01000100; // 'D' #10; we = 1; address_ram = 3'b100; data_in = 8'b01000101; // 'E' #10; we = 1; address_ram = 3'b101; data_in = 8'b01000110; // 'F' #10; we = 1; address_ram = 3'b110; data_in = 8'b01000111; // 'G' #10; we = 1; address_ram = 3'b111; data_in = 8'b01001000; // 'H' #10; address_ram = 3'b000; repeat (2**3) begin $display("Read Data from RAM at address %b: %c", address_ram, q_ram_out); #10; address_ram = address_ram + 1; end // Add more stimulus as needed #100 $finish; end endmodule
问题根源
- 写入地址错误:设计模块中写操作使用
addr_r寄存器而非输入的address_ram。addr_r在时钟沿更新为当前address_ram,导致第二次写操作时,addr_r还保持上一个周期的地址,将当前数据写入了错误的地址(比如把'B'写入000地址,覆盖了之前的'A')。 - 冗余寄存器干扰:
addr_r寄存器对异步读取逻辑完全无用,反而引入地址延迟,引发写入错位。 - 测试平台瑕疵:模块实例化名称不匹配(设计模块是
task,测试平台用home_task)、未定义变量result、复位信号未有效触发。
修复后的代码
修复后的设计模块
module ram_task ( input [2:0] address_ram, input [7:0] data_in, output [(DATA_WIDTH-1):0] q_ram, input clk, input rst_n, input we ); parameter DATA_WIDTH = 8; parameter ADDR_WIDTH = 8; reg [DATA_WIDTH-1:0] ram [2**ADDR_WIDTH-1:0]; always @(posedge clk or negedge rst_n) begin if (!rst_n) begin // 可选:复位时初始化RAM,此处暂不做全量初始化 end else begin // 直接使用输入地址作为写入目标 if (we) begin ram[address_ram] <= data_in; end end end // 异步读取:直接输出对应地址的RAM内容 assign q_ram = ram[address_ram]; endmodule
修复后的测试平台
module ram_task_tb; parameter DATA_WIDTH = 8; parameter ADDR_WIDTH = 8; reg clk, rst_n, we; reg [DATA_WIDTH-1:0] data_in; reg [2:0] address_ram; wire [(DATA_WIDTH-1):0] q_ram_out; ram_task uut ( .clk(clk), .rst_n(rst_n), .we(we), .address_ram(address_ram), .data_in(data_in), .q_ram(q_ram_out) ); // 时钟生成 always begin #5 clk = ~clk; end initial begin clk = 0; rst_n = 0; we = 0; data_in = 8'b0; address_ram = 3'b000; // 释放复位 #10 rst_n = 1; #10; // 写入数据 we = 1; address_ram = 3'b000; data_in = 8'b01000001; #10; // 'A' address_ram = 3'b001; data_in = 8'b01000010; #10; // 'B' address_ram = 3'b010; data_in = 8'b01000011; #10; // 'C' address_ram = 3'b011; data_in = 8'b01000100; #10; // 'D' address_ram = 3'b100; data_in = 8'b01000101; #10; // 'E' address_ram = 3'b101; data_in = 8'b01000110; #10; // 'F' address_ram = 3'b110; data_in = 8'b01000111; #10; // 'G' address_ram = 3'b111; data_in = 8'b01001000; #10; // 'H' // 关闭写使能,开始读取 we = 0; address_ram = 3'b000; repeat (2**3) begin $display("Read Data from RAM at address %b: %c", address_ram, q_ram_out); #10; address_ram = address_ram + 1; end #100 $finish; end endmodule
关键修复点
- 写入地址修正:直接使用输入的
address_ram作为写入地址,确保数据写入指定位置。 - 移除冗余逻辑:删除无用的
addr_r寄存器,消除地址延迟干扰。 - 测试平台修正:匹配模块实例化名称,添加有效复位,移除未定义变量,读取前关闭写使能。
内容的提问来源于stack exchange,提问作者Fatima Ismail
相关产品推荐
相关产品推荐

