audiosignal-processingveriloglibsndfileicarus

Simple Verilog VPI module to open audio files


I would like to write a VPI/PLI interface which will open audio files (i.e. wav, aiff, etc) and present the data to Verilog simulator. I am using Icarus at the moment and wish to use libsndfile to handle input file formats and data type conversion.

I am not quite sure what to use in the C code ... have looked at IEEE 1364-2001 and still confused which functions am I supposed to use.

Ideally I'd like to have a verilog module with data port (serial or parallel), clock input and start/stop pin. I'd like to implement two modules, one for playback from from a file, and another would record output from a filter under test.

Can I do it all in C and just instantiate the module in my testbench or I'll have to write a function (say $read_audio_data) and wrapper module to call it on each clock pulse ??

Hm, or may be I need to create the module and then get a handle for it and pass value/vect to the handle somehow ?

I am not quite concerned about how file names will be set, as I probably wouldn't do it from the verilog code anyway. And I will probably stick to 24-bit integer samples for the time being and libsndfile supposed to handle conversion quite nicely. Perhaps, I'll stick to serial for now (may be even do in the I2S-like fashion) and de-serialise it in Verilog if needed.

Also I have looked at Icarus plug-in which implements a video camera that reads PNG files, though there are many more aspects to image processing then there is to audio. Hence that code looks a bit overcomplicated to me at the moment - neither I managed to get it to run.


Solution

  • I suggest approaching it like this:

    1. figure out your C/Verilog interface
    2. implement the audio file access with that interface in mind, but not worrying about VPI
    3. implement the C/Verilog glue using VPI

    The interface can probably be pretty simple. One function to open the audio file and specify any necessary parameters (sample size, big/little endian, etc...), and another function returns the next sample. If you need to support reading from multiple files in the same simulation, you'll need to pass sort of handle to the PLI functions to identify which file you're reading from.

    The Verilog usage could be as simple as:

    initial $OpenAudioFile ("filename");
    
    always @(posedge clk)
        audio_data <= $ReadSample;
    

    The image-vpi sample looks like a reasonable example to start from. The basic idioms to use in the C code are:

    Argument access

    // Get a handle to the system task/function call that invoked your PLI routine
    vpiHandle tf_obj = vpi_handle (vpiSysTfCall, NULL)
    
    // Get an iterator for the arguments to your PLI routine
    vpiHandle arg_iter = vpi_iterate (vpiArgument, tf_obj)
    
    // Iterate through the arguments
    vpiHandle arg_obj;
    arg_obj = vpi_scan (arg_iter);
    // do something with the first argument
    arg_obj = vpi_scan (arg_iter);
    // do something with the second argument
    

    Retrieving values from Verilog

    s_vpi_value v;
    v.format = vpiIntVal;
    vpi_get_value (handle, &v);
    // value is in v.value.integer
    

    Writing values to Verilog

    s_vpi_value v;
    v.format = vpiIntVal;
    v.value.integer = 0x1234;
    vpi_put_value (handle, &v, NULL, vpiNoDelay);
    

    To read or write values larger than 32 bits, you will need to use vpiVectorVal instead of vpiIntVal, and de/encode a s_vpi_vector structure.