#105680 - masscat - Tue Oct 10, 2006 9:46 pm
The fifo does indeed become full (I cannot tap the X button quickly enough).
But if that was the problem then by pressing X you would see the number of handler calls increase. The fifo read allows a write to happen which, if an interrupt is generated per fifo write, would cause the handler call.
But no increase in handler calls means interrupt does not occur per write.
#105682 - masscat - Tue Oct 10, 2006 10:08 pm
Fortunately I did the fix on both ARMs so the problem was solved, but from those timings, as you say, it would have been the ARM7 to ARM9 FIFO.
#105700 - DekuTree64 - Wed Oct 11, 2006 7:47 am
Ok, this got me curious about the exact behavior of the FIFO, so I ran a few tests of my own. Here is what I found out:
1. FIFO Not Empty interrupt is generated ONLY when transitioning from empty to not empty. If your handler doesn't loop until the FIFO is empty again, then the rest of the data will just sit there and the interrupt will never be generated again. In other words, masscat's original post is correct.
2. Using my interrupt code, it takes about 160 cycles (33MHz) from the time of ARM9 writing a word to the FIFO, until ARM7 has executed its interrupt handler and read that value (ARM9 just does a while(!fifoempty) loop after sending the word). A bit slower than I would expect actually, but not too bad.
3. Depending on how the FIFO is used, there may be an extremely rare potential for missed not-empty interrupts using the libnds interrupt dispatcher.
If you always write a word and then spin until the other processor replies, it should be fine. But if you just write and move on, potentially writing more before the other processor has finished with the first, it could be bad.
The problem is that the dispatcher calls the user handler function (which in this case will empty the FIFO), and then clears the bit for that interrupt in REG_IF after that user handler returns. But there are a few sneaky cycles between the FIFO being for sure empty, and the IF bit being cleared. Consider this sequence of events:
ARM9 writes word to FIFO.
ARM7 fires interrupt, reads FIFO, sees that it is empty, breaks from its loop, and...
ARM9 writes another word to the FIFO.
ARM7 (still in interrupt code, with interrupts blocked) clears the bit in IF.
Bam, data in ARM7's receive buffer, but the IF bit has been cleared before it was processed.
Sooo, the solution is to clear the IF bit BEFORE calling the user handler. That way when ARM9 sends the second word, the IF bit will be left on in the end and trigger another not-empty interrupt as soon as the first one returns. But that will involve fiddling with assembly code in the libnds source.
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku
#105710 - masscat - Wed Oct 11, 2006 12:04 pm
After further investigation:
The ARM9 to ARM7 fifo alone can go full which leads to ~16ms inter packet timings. In this case the ARM9 to ARM7 packet transfer is being performed by the call to Wifi_Update() in the Vblank handler.
Both the ARM9 to ARM7 and ARM7 to ARM9 fifo can go full which leads to ~50ms inter packet timings. The ARM9 to ARM7 packet transfer is being performed by the call to Wifi_Update() in the Vblank handler. The ARM7 to ARM9 packet transfer is being performed by the call to Wifi_Timer() from the 50ms timer handler.
Since the ARM sync mechanism is external to dswifi, without the drain the FIFOs never recover and the latency remains.