News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu

Catch vsync when interrupts been disabled

Started by martin464, 14:59, 23 November 22

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

martin464

Sometimes things are easy, hope this question is one of those haha

I got some code that uses the stack to write the screen out so have to disable interrupts
I was originally planning my interrupt handler to count in 6 cycles so it knew which one vsync was
But that was before it dawned on me about the disabling interrupts which i forgot about

Can the interrupt handler tell if the particular one it's in is the vsync one?
I don't want to loop round waiting for it

The basic idea is the screen generating code sets a memvar when it's finished so the interrupt can switch the double buffer. There's no way to know in advance how long it will take to render the screen, it won't be constant
There's no rasters or ruptures to worry about!

PS I will only disable interrupts during screen writing, the rest of the time they're enabled like 50% of the time I guess
CPC 464 - 212387 K31-4Z

"One essential object is to choose that arrangement which shall tend to reduce to a minimum the time necessary for completing the calculation." Ada Lovelace

Longshot

Why don't you test if the Vsync is active during your interruption handler?
somethink like that:
inter_handler:
push af
ld a,#f5
in a,(#ff)
rra
jr nc, novsync
>>>vsync
novsync:
pop af
ei
ret
Rhaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!!

martin464

i was worried that doing it this way, it would take a lot of interrupts until it happened to catch it

but if the vsync can be checked like this the problem goes away, hey that's great thanks Longshot
the docs say it's 16 scanlines long so guess that checking it first thing will always work

do you think i will have any problems implementing the double buffer, pretty sure i can copy S.E.C. (someone else's code) wasn't sure if i switch it right at the start as soon as possible, i guess that's the perfect time is when vsync active

the arrangement i'm planning is 2 16k screens at &8000 and &C000. it's 128k game
then i can switch in a 2nd 64k bank over the screen being displayed at the time and keep the lower 32k free for main program and stuff. 
i found one annoying thing, the screen address lookup table is 2 bytes per line so you double the y line index but that forces 16 bit register (unless game area is <=128 lines). i've ended up having 2 lookup tables one for H and another for L to avoid doubling the index. it would be so much easier to limit the game y lines to 128 but the game won't let me do it. it's just 20 pixels too short visually the extra height is better looking
but all this extra 16 bit code is not fun to see it when trying to optimize everything else - and only for 20 pixels!

CPC 464 - 212387 K31-4Z

"One essential object is to choose that arrangement which shall tend to reduce to a minimum the time necessary for completing the calculation." Ada Lovelace

Longshot

You are right, a VSYNC detection problem can occur depending on the moment you reactivate the interruptions.  :-X

A VSYNC lasts 16 lines on CRTC 1 and 2.
On CRTC 0, 3 and 4, the number of lines of the VSYNC is defined with R3 (CRTC).

Interruptions are linked to the VSYNC and HSYNC signals and a 52-line counter (R52).
In principle an interruption occurs 2 lines after the start of the VSYNC if the line counter (R52) exceeded 31.

With a standard formatted screen with 312 lines : 312/52 = 6 interruptions exactly.

However, if you deactivate the interruptions for more than 52 lines (via a DI), a pending interruption will occur immediately after the instruction following EI.
This can therefore complicate things if you don't know when EI is executed.

Indeed, if this interruption occurs while the counter had again exceeded 31, this will shift the interruptions of 32 lines (because the Bit 5 of R52 is zeroed).
In other words, depending on the moment when the interruptions are authorized (6 periods of 20 lines), this discrepancy will prevent the interruption from occurring when the VSYNC is active.

You can imagine that there are 6 zones of 52 lines during a frame (line 0 to 51).
In each zone of 52 lines, if you reactivate the interruptions between line 32 and 51, then the "vSync" interruption will not take place (and therefore you will not be able to see it).

I advise you to read chapter 25 of Compendium.
http://logonsystem.fr/down/ACCC1.3-EN.pdf
Rhaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!!

martin464

#4
hmm interesting i will read that doc
from your description it sounds like it could happen where none of the interrupts will synchronize with vsync any more, as the EI offsets it (from resetting the counter)
So the interrupts get out of sync with vsync? nooooooooo
For me I wouldn't mind which interrupt caught the vsync as long as one of them did, so this sounds like trouble

i probably haven't understood it fully yet but a thought occurs...
maybe one strategy is to do as you suggested first, check vsync on each interrupt
but not to EI when you feel like it
no, not that - instead throw in periodic checks in the main code when you want to enable interrupts, and only enable them if the vsync is active at that moment

maybe repurpose RST 0, and dot them around the code when you don't care about AF
something like:
normally RST 0 has a RET

when you want to enable interrupts you put a NOP in there
then it does

ld a,#f5
in a,(#ff)
rra
ret nc ;no vsync
ei
ld a, &C9
ld (0), a
ret


CPC 464 - 212387 K31-4Z

"One essential object is to choose that arrangement which shall tend to reduce to a minimum the time necessary for completing the calculation." Ada Lovelace

Axelay


Quote from: martin464 on 17:45, 23 November 22i found one annoying thing, the screen address lookup table is 2 bytes per line so you double the y line index but that forces 16 bit register (unless game area is <=128 lines). i've ended up having 2 lookup tables one for H and another for L to avoid doubling the index. it would be so much easier to limit the game y lines to 128 but the game won't let me do it. it's just 20 pixels too short visually the extra height is better looking
but all this extra 16 bit code is not fun to see it when trying to optimize everything else - and only for 20 pixels!


Are you aligning your look up tables for H & L to a page (base address of #??00), so you would only need to load L with the y coordinate and H with the high byte of the of the lookup table base address to reduce any manipulation?  And have the tables adjacent in memory so an 8 bit INC/DEC H gets you between them?

Alternatively, are you able to store in a single page the screen base address of only every other line?  The address for  the line beneath lines 0,2,4 & 6 is always only a "SET 3,H" (or whichever register is appropriate) below the line above it, so depending on your requirements, storing every line address may not be necessary.  This also means you wouldn't need to double y to get the correct address, as the address for line 2 would start at #??02 for example, but you would need to make allowance in the code if you want objects to start displaying from an odd y coordinate.

Longshot

You won't be able to test the first available VSYNC in the Handler if the interrupt is shifted 32 lines.
On a complete frame of 312 lines with an EI on a pending interrupt, 38% of the lines are affected by the delay of the interrupts.

If your display code isn't exactly in sync with the VSYNC, that adds a random factor to this problem.
And so here, chaos is your friend ;D , since it increases the possibility of executing the EI in the 62% of "good lines".

Otherwise, why not wait directly for the VSYNC in your main code, once you've finished handling the display.
And manage the switching of the screen as soon as the VSYNC occurs.

To avoid losing CPU between the time you finish building a screen and its display, you can indeed test the VSYNC periodically.
However, these tasks must test the VSYNC every 16 lines max so as not to miss it.
(by putting R3high=0 on CRTC 0, 3 and 4)

Another question is whether the program can "advance" on other tasks as long as the display is not done.
Rhaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!!

martin464

#7
Quote from: Axelay on 11:38, 24 November 22Are you aligning your look up tables for H & L to a page (base address of #??00), so you would only need to load L with the y coordinate and H with the high byte of the of the lookup table base address to reduce any manipulation?  And have the tables adjacent in memory so an 8 bit INC/DEC H gets you between them?

Yes that exactly it, its like you can see my code lol. I didn't know about the SET hack before maybe some for unrolled sprite drawing code that could be a very useful optimisation!


QuoteYou won't be able to test the first available VSYNC in the Handler if the interrupt is shifted 32 lines.
On a complete frame of 312 lines with an EI on a pending interrupt, 38% of the lines are affected by the delay of the interrupts.

This has got my head spinning a bit with all the different ways of doing it
I'm going to try leaving interrupts enabled and drawing the screen right to left so any garbage is always overwritten, cause it writes every pixel i think it would work. I didn't realise all this thankyou, i think there is a workaround just what one is most efficient.  I do not want to lose even 0,5% of CPU power on handling this stuff!
CPC 464 - 212387 K31-4Z

"One essential object is to choose that arrangement which shall tend to reduce to a minimum the time necessary for completing the calculation." Ada Lovelace

martin464

As an update to this, what Longshot says is true. 
I managed to get no interrupt to occur during a vsync by disabling interrupts randomly and enabling them
I wrote a crude piece of code to sync them back approximately, which I am guessing could occur if using firmware disk routines that disable them i thought, so it could happen
I don't know how the super precise rupture effects are able to handle this problem and use interrupts to position stuff!
all the code i see seems to use halts and then position but how when they can get misaligned. can we reset the counters ourselves? i bet that is what is happenning cause i feel like that would explain it if that was it 

Anyway, I got another question that's a bit different, 
Would it be possible to make the CRTC hide the left edge of the screen, like a wider left border, like this:
BORDER   HIDDEN    VISIBLE ....................... RIGHT BORDER
               C000         C002
and still have the visible part centralised, just hiding the first 2 bytes of every line?
if it uses a bit more screen ram is ok but not going to full 24k (or 20k) as in increasing crtc to 50 characters
i think it can't be done but maybe there is some way?!

Thanks guys, appreciated


CPC 464 - 212387 K31-4Z

"One essential object is to choose that arrangement which shall tend to reduce to a minimum the time necessary for completing the calculation." Ada Lovelace

andycadley

The Plus machines have hardware to do that (technically it's at the right hand side of the screen but that doesn't actually make a difference).

Don't think there is a practical way of doing it on an old school CPC though. Would probably involve doing a rupture on every scanline.

Powered by SMFPacks Menu Editor Mod