You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Verilog环形存储器实现1秒音频延迟的技术咨询

Fixing Your 1-Second Audio Delay Circular Buffer in Verilog

Hey there! Let's work through getting your circular buffer-based audio delay up and running correctly. I can see the core idea is solid, but there are a few critical adjustments needed for proper functionality.

Key Issues in the Original Code

Let's break down what's missing or misconfigured:

  • Unupdated Write Index: Your code never increments write_index, so you're always writing to the same memory address—this means you're not actually storing a stream of audio samples, just overwriting the first location repeatedly.
  • Blocking Assignment for Read Index: Using read_index = read_index + 1; (blocking assignment) in a clocked always block can lead to unexpected timing behavior. In synchronous designs, we should use non-blocking assignments (<=) for all register updates.
  • Index Out-of-Bounds Risk: The initial read_index value is 20000 (binary 0100111000100000), but your memory is defined as [0:20000]—that's 20001 locations, while 1 second at 20kHz only needs 20000 samples. This leads to an off-by-one error, and the initial index points to an address outside your intended delay buffer.
  • No Circular Wraparound: Once write_index or read_index reaches the end of the buffer, they'll keep incrementing beyond the memory range, causing undefined behavior.

Revised Implementation

Here's a fixed version of your code with explanations of each change:

module delay( 
    input [11:0] data_in, 
    input delay_clk, // 20kHz clock
    output reg [11:0] data_out 
);

// Define parameters for flexibility
parameter DELAY_SAMPLES = 20000; // 1s * 20kHz = 20000 samples
parameter DATA_WIDTH = 12;
localparam INDEX_WIDTH = $clog2(DELAY_SAMPLES); // Auto-calculate index bit width

// Circular buffer: 20000 x 12-bit storage locations
reg [DATA_WIDTH-1:0] memory[0:DELAY_SAMPLES-1];
reg [INDEX_WIDTH-1:0] write_index;
reg [INDEX_WIDTH-1:0] read_index;

initial begin
    write_index = {INDEX_WIDTH{1'b0}};
    // Start read index 20000 samples behind write index. Since we start at 0,
    // this means read index also starts at 0—after 20000 cycles, read will pull 1s-old data
    read_index = {INDEX_WIDTH{1'b0}};
end

always@(posedge delay_clk) begin
    // 1. Write incoming sample to current write address
    memory[write_index] <= data_in;
    
    // 2. Read delayed sample from current read address
    data_out <= memory[read_index];
    
    // 3. Increment indices with circular wraparound
    write_index <= (write_index == DELAY_SAMPLES - 1) ? {INDEX_WIDTH{1'b0}} : write_index + 1'b1;
    read_index <= (read_index == DELAY_SAMPLES - 1) ? {INDEX_WIDTH{1'b0}} : read_index + 1'b1;
end

endmodule

Critical Changes Explained

  • Parameterized Design: Using parameters makes it easy to adjust delay length or sample width later without rewriting the whole module. $clog2 automatically calculates the required index bit width (15 bits for 20000 samples, since 2^14=16384 < 20000 < 2^15=32768).
  • Synchronous Register Updates: All index updates use non-blocking assignments (<=) to ensure proper sequential behavior on the clock edge, avoiding race conditions.
  • Circular Wraparound: The ternary operator checks if the index has reached the last memory location—if so, it resets to 0; otherwise, it increments by 1. This prevents invalid memory access.
  • Index Alignment: Starting both indices at 0 means the buffer fills for the first 20000 cycles, after which the output will consistently return samples from 1 second prior. If you want silent initial output instead of undefined values, you can initialize all memory locations to 0 (see optional improvement below).

Optional Improvements

  • Reset Signal: Add a synchronous or asynchronous reset to initialize indices and memory to known values on startup—standard practice for real-world designs.
  • Silent Initialization: To ensure the initial output is 0 instead of undefined, add this to the initial block:
    integer i;
    initial begin
        for(i=0; i<DELAY_SAMPLES; i=i+1) begin
            memory[i] = {DATA_WIDTH{1'b0}};
        end
        write_index = 0;
        read_index = 0;
    end
    
  • Variable Delay: If you want runtime-adjustable delay, replace the fixed DELAY_SAMPLES parameter with an input signal, and calculate the read index as (write_index - delay_length) % DELAY_SAMPLES (be sure to handle underflow with proper signed arithmetic or offsetting).

内容的提问来源于stack exchange,提问作者prof zhj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:23:09