`timescale 1ns/1ps // Capture-and-dump trace memory. // // V2.2 internal record width is deliberately reduced to 64 bits: // timestamp[15:0] + event/state ID[15:0] + data[31:0] // // The UART protocol still sends a 32-bit timestamp; the top expands the stored // 16-bit timestamp with zeroes. With the default TRACE_DEPTH=1024 and the // full-cycle template (one trace per active algorithm cycle), 16 timestamp bits // are far more than required and save block-RAM resources versus the old 80-bit // record. // // Memory is NOT cleared between runs. Only count/pointers are reset. module trace_capture_ram #( parameter integer TRACE_DEPTH = 1024, parameter integer TRACE_ADDR_W = 10 )( input wire clk, input wire reset_n, input wire capture_reset, input wire trace_valid, input wire [15:0] trace_id, input wire [15:0] trace_timestamp, input wire [31:0] trace_data, output reg [15:0] captured_count, output reg [31:0] drop_count, output reg overflow, input wire rd_en, input wire [TRACE_ADDR_W-1:0] rd_addr, output reg [63:0] rd_data ); reg [63:0] mem [0:TRACE_DEPTH-1]; reg [TRACE_ADDR_W-1:0] wr_addr; always @(posedge clk or negedge reset_n) begin if (!reset_n) begin wr_addr <= {TRACE_ADDR_W{1'b0}}; captured_count <= 16'd0; drop_count <= 32'd0; overflow <= 1'b0; end else if (capture_reset) begin wr_addr <= {TRACE_ADDR_W{1'b0}}; captured_count <= 16'd0; drop_count <= 32'd0; overflow <= 1'b0; end else if (trace_valid) begin if (captured_count < TRACE_DEPTH) begin mem[wr_addr] <= {trace_timestamp, trace_id, trace_data}; wr_addr <= wr_addr + 1'b1; captured_count <= captured_count + 1'b1; end else begin drop_count <= drop_count + 1'b1; overflow <= 1'b1; end end end // Synchronous read: friendlier to true block-RAM inference. always @(posedge clk) begin if (rd_en) rd_data <= mem[rd_addr]; end endmodule