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开发者_Python百科 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.
I suggest approaching it like this:
- figure out your C/Verilog interface
- implement the audio file access with that interface in mind, but not worrying about VPI
- 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.
I have spent a few days now implementing the PLI testbench, if anyone reads this and they may find it useful - here is my source code. There is a readme file and below is the screenshot of some basic results ;)
Use git clone git://github.com/errordeveloper/sftb
to obtain
the code repo or download it from the github.com.
I have also wrote about this in my new blog, so hopefully if anyone searches for this sort of thing they will find it. I couldn't find anything similar, hence started this project!
This sounds like a good fit for Cocotb an open-source project which abstracts VPI to provide a Pythonic interface to your DUT. You wouldn't have to write any additional Verilog testbench or wrapper RTL or call VPI tasks or functions from Verilog as the testbenches are pure Python.
Your testbench as described would look something like this:
import cocotb
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge
# Whatever audio-file IO library you happen to like best...
from scikits.audiolab import wavread
@cocotb.test()
def stream_file(dut, fname="testfile.wav")
# Start a clock generator
cocotb.fork(Clock(dut.clk, 5000))
data, sample_frequency, encoding = wavread(fname)
result = []
while data:
yield RisingEdge(dut.clk)
dut.data_in <= data.pop(0)
result.append(dut.data_out.value.integer)
# Write result to output file
Disclaimer: I'm one of the Cocotb developers and thus potentially biased, however I'd also challenge anybody to produce functionality similar to the above testbench as quickly and with fewer lines of (maintainable) code.
精彩评论