Reply 80 of 122, by superfury
GloriousCow wrote on 2023-08-07, 14:15:Bear in mind I model this as a state we enter; not a one time event. […]
superfury wrote on 2023-08-06, 11:52:Just implemented an extra timer on the BIU emulation of the 808x: - When T3 is ticked (proceeding onto T4), it will set a flag i […]
Just implemented an extra timer on the BIU emulation of the 808x:
- When T3 is ticked (proceeding onto T4), it will set a flag if the prefetch isn't empty.
- When T1 arrives to tick and either said flag is set, or no request is made, an additional check is made before checking the requests from the EU:
-- (in both cases below the above flag is cleared, preventing it from retriggering until after the EU request finishes after this)
-- PIQ not full? Perform a prefetch instead.
-- PIQ full? Perform 4 idle clock cycles instead (thus taking T1-T4 cycles with idle bus).Bear in mind I model this as a state we enter; not a one time event.
It's perhaps most noticeable in string instructions with REP prefixes, for example a REP MOVSB will incur the 3 cycle delay after the first R/W iteration as the queue fills up. Once full, we now delay 3 extra cycles per iteration (effectively 18% of iteration time) because we do not 'resume' the BIU until a byte is actually read out of the queue again, which it won't until the operation is complete. There are other possible ways to model this logic - perhaps you could assume that the prefetcher still schedules on a full queue, and so the delay is explained by a fetch attempt each time instead of specifically delaying EU operations - then you wouldn't need to track state. I don't yet know how to test which underlying theory is correct.
I don't know if you can just add these delays into your code easily, since you are likely accounting for them in some sort of static cycle count already. To properly emulate all the 8088 bus delays, i think one pretty much has to model the microcode execution time exactly and let the BIU delay logic fill in the rest.
Also, it won't set the flag if the current operation is a prefetch operation. Otherwise, any prefetch would ignore the EU requests until the PIQ is fully filled, which shouldn't happen.
Currently, on the 8088, the word accesses's byte accesses will be interrupted by the PIQ fetching (if any available) aren't interrupted, since it's considered atomic (so T1-T4 of byte +0, followed by T1-T4 of byte +1, followed by 1 guaranteed T1-T4 or 3 idle cycles(if buffer full) for a prefetch.
If T1 arrives without any request from the EU, a prefetch will always be attempted (T1-T4 if not full, 1 idle cycle otherwise).
If requests from the EU keep coming each cycle, it would flip-flop between prefetching a byte and any pending request byte, back and forth between the two.
Once the EU stops requestig before/at T1, the PIQ starts doing requests on T1 until filled, at which point the PIQ simply ticks 1 cycle waiting for it to empty or a request to be made from the EU(which gets priority, unless it was the last transfer made on T1-T4 and asking for another byte to transfer, which gets interrupted by either prefetching or 3-cycle stall once a byte is transferred).
Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io