Bregalad wrote:The problem is that you have to wait a dozen of IRQs for a dozen of scanline, so if this technique were to be used for a longer time between both split, this constant stream of useless IRQs would waste very significant CPU time for nothing
It's significant, but the 37 cycles out of 432 still fall within my 10% of CPU time budget.
Code: Select all
irq_handler:
bit $4015 ; acknowledge dpcm irq
inc irqs
; schedule another IRQ
pha
lda enable_timer
sta $4015
pla
rti
And it's not entirely useless to know how much time I have left before the IRQ fires.
Would this technique work as well if you play a 1-byte sample, count the # of cycles before the interrupt, then play a 17 or 33 byte sample to have only 2 IRQs in total ?
Playing a 17-byte sample would allow skipping the first IRQs if the splits are far enough apart ((17+1)*8*54 = 7776 CPU cycles or 69 scanlines). But the demo's splits are only about 10 bytes apart, and it would be two more instructions in the IRQ to handle switching to 1-byte samples after the initial 17- or 33-byte sample. I'll consider it in the second.
Altough of course this will waste 100% of CPU time between the 1st and 2nd split instead of between the top and the 1st split, so it all depends of what you'd want to achieve.
What motivated my development of this technique was trying to display a background picture that needs more than 4 KiB of CHR while decompressing a page of text to put into the next picture. Here, sprite 0 would be in a fixed place (doesn't matter where as long as it's present), and the code would wait for the end of vblank by waiting for sprite 0 flag to turn off.
EDIT : Yet another thing is that you could, in the first loop, wait for $4015.7 to rise, while having the I flag set.
The number of cycles in the loop that measures the IRQ jitter has to match the number of cycles in the loop that compensates, and it takes more time to read $4015 than the zero-page variable that the IRQ handler updates.