News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_MaV

Frame flyback and interrupts

Started by MaV, 16:15, 09 June 11

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

MaV

So ... I've been reading (re-reading actually since I knew some of the stuff from a very long time ago) about the frame flyback and interrupts.

I've been reading somewhere that there are 6 interrupts occurring at exact positions on the screen.

Am I right in presuming that of 5 halt-commands after a frame flyback every "halt" will delay the Z80 so long as to resume operation exactly at one of those mentioned spots on the screen? And the sixth will be the frame flyback?


Black Mesa Transit Announcement System:
"Work safe, work smart. Your future depends on it."

arnoldemu

#1
Quote from: MaV on 16:15, 09 June 11
So ... I've been reading (re-reading actually since I knew some of the stuff from a very long time ago) about the frame flyback and interrupts.

I've been reading somewhere that there are 6 interrupts occurring at exact positions on the screen.
yes

Quote from: MaV on 16:15, 09 June 11
Am I right in presuming that of 5 halt-commands after a frame flyback every "halt" will delay the Z80 so long as to resume operation exactly at one of those mentioned spots on the screen? And the sixth will be the frame flyback?
yes

the position will not be exact, worse with the firmware.

with firmware interrupts the position is not perfectly exact because it depends on the interrupts (ticker, frame flyback etc) that have been set. Your HALT will come after all of them have been done.

If you need accurate position, then you have to use a "express asynchronous fast ticker event".
Example:
http://www.cpctech.org.uk/source/modesplt.asm

The firmware processes these first, but you have to be careful what you do inside them because some things will not work.

I did try to patch 0038 so that my code was called first and then firmware's was executed after, but it didn't work with basic. (Basic calls the EDIT function in the rom, and while it is reading input, firmware's rom is active, and firmware's interrupts are running ;) ).






My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

arnoldemu

firmware interrupt operation:

acknowledges hardware interrupt, and jumps to 0038.

(actually it should be possible to setup an im 2 interrupt to intercept the interrupt and then pass it to the firmware this way)

re-enables interrupts to check for external maskable interrupts and then calls 003b if it sees them and then continues to finish interrupt handler and quits. So external maskable interrupt should do normal ret.

next it updates "TIME" value.

checks VSYNC and executes FRAME FLYBACK interrupts

then it executes FAST TICKER

then it does sound

then it does keyboard scan (if needed), 6 interrupts apart not always in same place in frame ;)

then I think it does ticker list

for each of frame flyback, fast ticker, sound etc it then checks the priority

express asynchronous first
then asynchronous I think
then synchronous last


after all this your HALT will "return" back to you and you can do what you want ;)

So I setup a express asynchronous fast ticker event to do the mode change.
yes, the frame flyback ones come first, but that doesn't matter so much when it's not visible on the screen.

I had to write direct to hardware, and the alternative z80 registers were not what I expected.. it was hard work to make that code work ;)



My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

arnoldemu

Markus has set me the challenge. A split screen (demo type) using firmware fast ticker interrupts.
I think I may be able to modify some code to do that.
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

redbox

Quote from: MaV on 16:15, 09 June 11
And the sixth will be the frame flyback?

If you wait for the sixth, you still have time to do some stuff before the frame flyback (with a normal screen setup).

For example, you can do some fast sprite routines here which avoids screen flickering and without the need to double buffer.

MaV

Quote from: arnoldemu on 16:50, 09 June 11
after all this your HALT will "return" back to you and you can do what you want ;)

Thanks, arnoldemu.

I checked on the halt instruction. The Z80 is executing NOPs until an interrupt occurs. Then it resumes normal operation, which means execute the interrupt, before you are able to do anything. I read somewhere that the PC is also incremented before the jump to the interrupt routine. So the interrupt is executed exactly between the halt and the next instruction.

Hmm, so whatever I do, I have to take into account that I'll be missing a bunch of cycles. I can influence that by writing my own interrupt routine. I guess that's the way to go for games and demos. Since the Int occurs regularly it makes sense to do sound and keyboard scanning there.

To sum it up: You're not able to determine exactly how many cycles are left to do manipulate objects on the screen between interrupts. And you may have to resort to trial and error  to get the most out of it (e.g. insert an assembly routine, then check, then insert some more, then check, ... ).


PS: Emulator debuggers should mark the spot where the next interrupt occurs. That would make exact timing a bit easier. (Yeah, I know it's a bit difficult to determine sometimes. Different execution paths etc.)
Black Mesa Transit Announcement System:
"Work safe, work smart. Your future depends on it."

MaV

Quote from: redbox on 20:32, 09 June 11
If you wait for the sixth, you still have time to do some stuff before the frame flyback (with a normal screen setup).

For example, you can do some fast sprite routines here which avoids screen flickering and without the need to double buffer.

Ah, ok. So it's 6 interrupts plus the frame flyback.

Thanks!
Black Mesa Transit Announcement System:
"Work safe, work smart. Your future depends on it."

arnoldemu

Quote from: MaV on 08:54, 10 June 11
Ah, ok. So it's 6 interrupts plus the frame flyback.

Thanks!
no, 6 total. 1 inside frame flyback. so you wait until the 5th *after* the vsync.
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

arnoldemu

Quote from: MaV on 08:53, 10 June 11
Thanks, arnoldemu.

I checked on the halt instruction. The Z80 is executing NOPs until an interrupt occurs. Then it resumes normal operation, which means execute the interrupt, before you are able to do anything. I read somewhere that the PC is also incremented before the jump to the interrupt routine. So the interrupt is executed exactly between the halt and the next instruction.
Yes.


Quote from: MaV on 08:53, 10 June 11
Hmm, so whatever I do, I have to take into account that I'll be missing a bunch of cycles. I can influence that by writing my own interrupt routine. I guess that's the way to go for games and demos. Since the Int occurs regularly it makes sense to do sound and keyboard scanning there.
Yes the best is to write your own routine because then you can predict the number of cycles, because you control it.

Generally, the maskable interrupt is signalled by the gate-array. The z80 finishes executing the current instruction, acknowledges the interrupt (which takes some cycles - depending on interrupt mode), then starts to execute the interrupt handler. If it's yours, you can do as you want.

If it's the firmware, it does a load of other stuff as well as executing tickers and flyback functions that have been added/registered. With firmware you have less control over the accuracy, just because it does things.


Quote from: MaV on 08:53, 10 June 11
To sum it up: You're not able to determine exactly how many cycles are left to do manipulate objects on the screen between interrupts. And you may have to resort to trial and error  to get the most out of it (e.g. insert an assembly routine, then check, then insert some more, then check, ... ).
If you are in control, yes you can determine it exactly. if you use firmware interrupts, then it varies, but you could work out a maximum.


Quote from: MaV on 08:53, 10 June 11
PS: Emulator debuggers should mark the spot where the next interrupt occurs. That would make exact timing a bit easier. (Yeah, I know it's a bit difficult to determine sometimes. Different execution paths etc.)
Yes we could do that, but that would be the absolute perfect position not taking into account the timing of the interrupt handler.

I think Winape does this already, Arnold will do it soon.

My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

MaV

Hm, call me stupid for discovering information by myself that most likely is known by just about everyone here, but I'm learning best by experimenting with bits of infos and doing the rest.

I've been throwing some code pieces together to get (some facts are quite obvious):
org #8000

di
im  1

ld hl,#c9fb
ld (#0038), hl
ei

;ld b,#f5
;vsync:
;in a,(c)
;rra
;jp nc, vsync

ld bc,#7f00

     ; #46 cyan
ld d,#55 ; bright blue
ld e,#4d ; bright magenta
ld h,#4e ; orange
ld l,#56 ; green
     ; #4c red

out (c),c

loop:
halt
ld a,#46
out (c),a
halt
out (c),d
halt
out (c),e
halt
out (c),h
halt
out (c),l
halt
ld a,#4c
out (c),a
jp loop


Then I inserted a bunch of nops to see where the ray goes and done some calculations.

The result for the standard crtc screen is:

- one line including left and right border and the horizontal flyback equals 256 cycles (= 64 nops)
- the borders (left and right) are 16 cycles each (4 nops x 2)
- the line itself takes 160 cycles (40 nops)
- the horizontal flyback equals 64 cycles (16 nops)

The time the ray takes to completely go through the 200 lines of the screen:
- 256 cycles times 200 lines = 51200 (12800 nops)

The CPC executes at 4MHz, the screen is updated 50 times/second. That's 80000 cycles per screen (20000 nops).

Consequently the upper and lower border plus the frame flyback take 80000-51200 = 28800 cycles (7200 nops); I've yet to figure out the relation of frame flyback to upper and lower border.

Further rambling:
Execution of the interrupt routine after the halt takes place exactly at the beginning of the left side border. The processor starts with the jump to the interrupt routine (IM 1 mode) which takes 16 cycles, then executes the interrupt routine (16 cycles in the code example, ei + ret). If you then like to change the color with out (c), n the first position that will be affected is the 14th byte of this line.

Black Mesa Transit Announcement System:
"Work safe, work smart. Your future depends on it."

Executioner

Quote from: MaV on 00:41, 13 June 11
The CPC executes at 4MHz, the screen is updated 50 times/second. That's 80000 cycles per screen (20000 nops).

Not quite. It's 312 scan lines at 64 nops = 19968 nops. The screen actually updates at 50.08012820512821 (ish) times/second.

Executioner

Quote from: MaV on 00:41, 13 June 11
Execution of the interrupt routine after the halt takes place exactly at the beginning of the left side border.

The interrupt is triggered by the falling edge of the HSYNC signal from the Gate Array, so the position at which it occurs is directly affected by the HSYNC width (altered by CRTC Reg 3), the HSYNC Position (CRTC Reg 2) and the characters (NOPS) per scan line (CRTC Reg 0 + 1).

MaV

Quote from: Executioner on 02:26, 13 June 11
Not quite. It's 312 scan lines at 64 nops = 19968 nops. The screen actually updates at 50.08012820512821 (ish) times/second.

OK. Thanks. The 20000 nops are based on the assumption that it's exactly 50Hz.


Quote from: Executioner on 02:26, 13 June 11
The interrupt is triggered by the falling edge of the HSYNC signal from the Gate Array, so the position at which it occurs is directly affected by the HSYNC width (altered by CRTC Reg 3), the HSYNC Position (CRTC Reg 2) and the characters (NOPS) per scan line (CRTC Reg 0 + 1).

And thank you for that. :)

It was a bit late when I posted, so I haven't had time yet to compare my findings to the standard values of the crtc. This will be the next step to better understand the CRTC and Gate Array.

That the interrupt occurs at the left side border is still true for the standard programmed values of the crtc then, isn't it?

Black Mesa Transit Announcement System:
"Work safe, work smart. Your future depends on it."

Executioner

The interrupt occurs at HSYNC Pos + HSYNC Width (ie. Reg 2 + (Reg 3 and #0F)) nops. That's normally 42 + 14 = 56. There's a 2 nop delay for the interrupt, so that makes it 58. The actual RST instruction in IM 1 delays it by a further 1 nop, and it is dependent on the instruction which was executing at the time the interrupt occurred.

MaV

Quote from: Executioner on 00:26, 14 June 11
The interrupt occurs at HSYNC Pos + HSYNC Width (ie. Reg 2 + (Reg 3 and #0F)) nops. That's normally 42 + 14 = 56. There's a 2 nop delay for the interrupt, so that makes it 58. The actual RST instruction in IM 1 delays it by a further 1 nop, and it is dependent on the instruction which was executing at the time the interrupt occurred.

Thanks, executioner. Is there any info about sensible values to the CRTC-registers. Maybe that sounds naive, but my guess is that a lot of values just don't make sense.
Black Mesa Transit Announcement System:
"Work safe, work smart. Your future depends on it."

arnoldemu

Quote from: MaV on 09:20, 21 June 11
Thanks, executioner. Is there any info about sensible values to the CRTC-registers. Maybe that sounds naive, but my guess is that a lot of values just don't make sense.

If you want your display to work correctly on modulators, then the horizontal timing must be a total of 64us. And there must be a hsync of 6us each line. You also need to have 312 lines per screen total, and a vertical sync of 8 lines.

If you do all that, then the image will be stable.
How you choose to create the image is up to you as long as the timing follows this.
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

MaV

Quote from: arnoldemu on 09:35, 21 June 11
You also need to have 312 lines per screen total, and a vertical sync of 8 lines.

Funny. I dabbled with the values of the R4 and R9 registers in WinAPE. My guess was if the product of both registers ( +1; so 39 * 8 ) is 312 then the screen should be stable, except it isn't for R9 values above 7.
So do I need to write to R7 for the VSync in these cases to stabilize the screen?

Interesting side note: I've been reading some old magazines on these subjects. Most of these infos were available around 88 (interlacing, more colours, ...), and I remembered how I did some interlacing pictures back then. Of course some of that still needed proper reflection to get higher resolution screens and all that. Now the differences between the various CRTCs ... that was completely new to me a year ago. Yeah, I've got a lot to catch up on ...
Black Mesa Transit Announcement System:
"Work safe, work smart. Your future depends on it."

arnoldemu

Quote from: MaV on 09:58, 21 June 11
Funny. I dabbled with the values of the R4 and R9 registers in WinAPE. My guess was if the product of both registers ( +1; so 39 * 8 ) is 312 then the screen should be stable, except it isn't for R9 values above 7.
So do I need to write to R7 for the VSync in these cases to stabilize the screen?

Interesting side note: I've been reading some old magazines on these subjects. Most of these infos were available around 88 (interlacing, more colours, ...), and I remembered how I did some interlacing pictures back then. Of course some of that still needed proper reflection to get higher resolution screens and all that. Now the differences between the various CRTCs ... that was completely new to me a year ago. Yeah, I've got a lot to catch up on ...
if you are changing r9, then you need to adjust r4 and also r7 to compensate for this.
So if r9 was changed to 15, then r4 needs to be half as much as it was before.
R7 is not half (but it's value will be smaller), but you can adjust it until it is correct how you want.

EDIT: My advice is *ALWAYS* test on a real cpc. Emulators are not 100% accurate.
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

MaV

Quote from: arnoldemu on 10:19, 21 June 11
EDIT: My advice is *ALWAYS* test on a real cpc. Emulators are not 100% accurate.

I do, but I'm lacking a real CPC in some places. And it's a bit easier to debug in an emulator.

Thanks, arnoldemu. Much appreciated!

Now on to some more dabbling. :)
Black Mesa Transit Announcement System:
"Work safe, work smart. Your future depends on it."

Executioner

btw, I mentioned something about 1 NOP for RST earlier. It's actually 3 NOPS.

cpcitor

Quote from: MaV on 00:41, 13 June 11
The result for the standard crtc screen is:

These seem really interesting.

Once a forum discussion brings interesting facts or conclusions, everyone wins if those are included in the wiki.
Trying to find a good place in the wiki to put it, the best I could find was in CRTC - CPCWiki

Feel free to review/criticize/correct.
Had a CPC since 1985, currently software dev professional, including embedded systems.

I made in 2013 the first CPC cross-dev environment that auto-installs C compiler and tools: cpc-dev-tool-chain: a portable toolchain for C/ASM development targetting CPC, later forked into CPCTelera.

Powered by SMFPacks Menu Editor Mod