imagedev/floppy: batch sequential flux writes - #15425
Conversation
|
I think buffering in the floppy_device instead of the individual fdcs is a good idea. But if we do that, we need to commit to it. That means changing the interface in floppy_device from the existing one to something along the lines of write_start(time), write_end(time), write_flux_change(time) and write_flush(time). Would you be ready to try for that? |
|
Honestly, I really sweated this one being sure I couldn't actually break anything... I'm not sure how good the CI is in this project, but honestly, the idea of being able to break everything with a floppy gives the the willies. I can maybe dig in a bit this weekend, I only really looked at the one drive implementation so maybe taking a wider look will help settle my stomach. |
|
Ah, took a quick look, yeah, I see what you mean now... it looks like there's a few different solutions to the problem. I'll poke at it during the week and see what I come up with. |
|
The HP and VTech ones were the biggest brain twisters in there. Only about 97% sure I've retained the VTech time travelling behaviour. 😄 |
|
Updated the top comment since it looks like you do squash merges here. |
|
I assume this is still something we want - please do a rebase to resolve the conflicts @RealDeuce. |
Some floppy controllers commit generated write flux in very small spans. This is especially visible while formatting, where a controller can emit a full track byte-by-byte and each byte-level commit previously edited the persistent track vector immediately. That turns one logical sequential track write into thousands of repeated track scans and insertions, making format operations orders of magnitude slower than the emulated disk timing. Keep the existing write path semantics by delaying only contiguous writes to the same cylinder, side and subcylinder. The accumulated span is flushed before any operation that can observe or depend on committed media state, including cache fills, write-splice updates and image commit. Non-contiguous writes or writes to another track also flush first, so existing callers that issue isolated writes continue to take the same path with no behavioral change beyond avoiding redundant intermediate vector edits. The pending span stores the original start/end positions and concatenated flux-change positions, then reuses the existing wspan_remove_damaged and wspan_write helpers when flushed. This preserves the existing damaged-region handling and track modification logic while making sequential write streams behave like the single larger write they represent.
fc84bbc to
f9d78ad
Compare
Replace the batched write_flux(start, end, count, transitions) interface with an event-driven streaming interface: write_start, write_flux_change, write_end and write_flush. This makes the floppy device own the write-gate lifecycle and the transition buffer rather than requiring every controller to maintain its own. write_start activates the write gate and snapshots the current track identity. write_flux_change appends a single transition timestamp to an internal buffer. write_end deactivates the write gate and flushes buffered transitions to the track. write_flush commits transitions earlier than a given time without ending the write, retaining later transitions for a subsequent flush or end. All controllers now call write_flux_change directly as transitions are generated rather than maintaining local buffers. Controllers that use speculative execution with checkpoint/rollback (wd_fdc, 64h156, c2040fdc, paulafdc) previously needed local 32-entry write buffers to avoid duplicating transitions after rollback. The floppy device now handles this transparently: write_flux_change detects out-of-sequence timestamps and discards stale entries, so replayed transitions replace their predecessors cleanly. The hp9895 controller supports simultaneous read and write for write-with- verify loopback. It previously read back transitions from the fdc_pll write buffer. Since that buffer no longer exists, hp9895 now maintains its own loopback buffer that captures transition times as they are generated and serves them back through get_next_transition when the write gate is active. Add a floppy parameter to fdc_pll_t::start_writing so that write_start is called on the floppy device at the correct point in the PLL lifecycle. All controllers that use fdc_pll_t (wd_fdc, swim3, mc6843, upd765, i8271, hdc92x4, hp9885, isbc202, c8050fdc, victor9k_fdc, hp9895) now pass their floppy pointer through start_writing. The same change applies to the wd_fdc digital PLL and the paulafdc PLL. The old fdc_pll_t::write_next_bit had a lazy-init path that implicitly started writing on the first bit if start_writing had not been called. Three controllers (upd765, i8271, hdc92x4) relied on this for sector writes -- only their format-track paths called start_writing explicitly. That lazy init is removed; the sector-write paths now call start_writing at the point where they transition from reading gap data to writing sector data. The batching performance benefit from the earlier write_flux optimization is preserved: transitions accumulate in the floppy device and are written to the track representation only at flush points, avoiding repeated track vector edits during sequential writes such as formatting.
f9d78ad to
b547d57
Compare
|
I've redone it, did |
|
I agree with @galibert that this is structurally a win, and once CI passes I'll merge it if he doesn't first. We have roughly 6 weeks until the release freeze for people to test things and a relatively small number of controllers involved. So it's certainly scary, but it's not unsurmountable. The existence of software lists makes it relatively easy to test a lot of systems, for instance. |

Replace the batched write_flux(start, end, count, transitions) interface
with an event-driven streaming interface: write_start, write_flux_change,
write_end and write_flush. This makes the floppy device own the write-gate
lifecycle and the transition buffer rather than requiring every controller
to maintain its own.
Some floppy controllers commit generated write flux in very small spans.
This is especially visible while formatting, where a controller can emit a
full track byte-by-byte. With the old interface each commit edited the
persistent track vector immediately, making format operations orders of
magnitude slower than the emulated disk timing. The new interface solves
this naturally: transitions accumulate in the floppy device and are written
to the track representation only at flush points.
write_start activates the write gate and snapshots the current track
identity. write_flux_change appends a single transition timestamp to an
internal buffer. write_end deactivates the write gate and flushes buffered
transitions to the track. write_flush commits transitions earlier than a
given time without ending the write, retaining later transitions for a
subsequent flush or end.
All controllers now call write_flux_change directly as transitions are
generated rather than maintaining local buffers. Controllers that use
speculative execution with checkpoint/rollback (wd_fdc, 64h156, c2040fdc,
paulafdc) previously needed local 32-entry write buffers to avoid
duplicating transitions after rollback. The floppy device now handles this
transparently: write_flux_change detects out-of-sequence timestamps and
discards stale entries, so replayed transitions replace their predecessors
cleanly.
The hp9895 controller supports simultaneous read and write for write-with-
verify loopback. It previously read back transitions from the fdc_pll
write buffer. Since that buffer no longer exists, hp9895 now maintains its
own loopback buffer that captures transition times as they are generated
and serves them back through get_next_transition when the write gate is
active.
Add a floppy parameter to fdc_pll_t::start_writing so that write_start is
called on the floppy device at the correct point in the PLL lifecycle.
All controllers that use fdc_pll_t (wd_fdc, swim3, mc6843, upd765, i8271,
hdc92x4, hp9885, isbc202, c8050fdc, victor9k_fdc, hp9895) now pass their
floppy pointer through start_writing. The same change applies to the
wd_fdc digital PLL and the paulafdc PLL.
The old fdc_pll_t::write_next_bit had a lazy-init path that implicitly
started writing on the first bit if start_writing had not been called.
Three controllers (upd765, i8271, hdc92x4) relied on this for sector
writes -- only their format-track paths called start_writing explicitly.
That lazy init is removed; the sector-write paths now call start_writing
at the point where they transition from reading gap data to writing sector
data.