openfpga-litex icon indicating copy to clipboard operation
openfpga-litex copied to clipboard

How can I tell when a deferred file read is finished?

Open kcsmnt0 opened this issue 5 months ago • 14 comments

I'm all up and running with the core and having fun putting together a little Slint app, but I've hit a roadblock with the deferred file loading API. This might be a silly question, but I've been staring at the docs and experimenting on my Pocket for a couple days and I'm still stuck on it.

I'm trying to use deferred loading to read individual parts of a file that might be too big to fit in the core's RAM all at once. My slot in data.json looks like this:

{
  "name": "file",
  "id": 1,
  "required": true,
  "parameters": "0x89",
  "deferload": true
}

The parameters value sets flag 0 (user-reloadable), flag 3 (read-only), and flag 7 (restart of core before/after loading).

My Rust code to read a piece of data starts like this:

// bridge: APF_BRIDGE
// buffer: &mut [u8]
// offset: u32
bridge.ram_data_address.write(|w| w.ram_data_address().variant(buffer as *mut [u8] as *mut u8 as u32));
bridge.transfer_length.write(|w| w.transfer_length().variant(buffer.len() as u32));
bridge.data_offset.write(|w| w.data_offset().variant(offset);
bridge.request_read.write(|w| w.request_read().bit(true));

If I try println!("{:?}", buffer) immediately after setting request_read, I get the original unmodified buffer contents; if I have the program do some arbitrary pointless work for long enough before inspecting buffer, then it has the file contents that I expect. That seems like a race condition, which makes sense with my understanding of what's going on under the hood, but I can't figure out how to tell when the program has waited long enough.

None of these seem to work reliably as signals to block on:

  • status is cleared on read, so reading a 0 from it means that either no read is in progress or a read I've already observed is still in progress. I haven't figured out any way to distinguish between these two possibilities.
  • command_result_code is always 0 unless an invalid read happens, so if my code never does an invalid read, then command_result_code never changes at all. It also seems to update before a read is finished: I've tried deliberately doing an invalid read to set command_result_code to a nonzero value before I do the actual read, but waiting for command_result_code to return to 0 still didn't resolve my race condition.
  • current_address seems to update when the bridge starts to copy a chunk of the data, not when it finishes copying the chunk of data.

Right now I'm running into this problem in a larger project with some graphics and input code that are irrelevant to this particular issue, but I can boil it down to a minimal code example demonstrating the race condition if that's helpful. I've pored over the Analogue target command docs and I don't see anything relevant in there that isn't mirrored in the Rust API for this core, so I'm guessing I'm probably just missing something about how this is all supposed to fit together? Thanks in advance!

kcsmnt0 avatar Jan 22 '24 04:01 kcsmnt0