Is fuller information available about FH and IE1?

By TomH

Champion (375)

TomH's picture

08-05-2023, 17:21

As documented, FH is:

Quote:

Horizontal scan interrupt flag. Is set if VDP scans line specified in register R#19. If IE1 is set, interrupt is generated. FH is reset when S#1 is read

That would appear to establish that FH is completely independent of IE1 — it will be set if the VDP scans the R#19 line, it will be reset when S#1 is read. Oh, and by the way, if IE1 is set, the current status of FH will also be used to trigger interrupts.

However, I notice that many programs assume that they can read S#1 and use bit 0 to determine the current source of an interrupt. E.g. in Space Manbow the interrupt response code looks essentially like:

    interrupt:
        if (S#1 & 1) {
            wait for end of horizontal blank
            OTIR list of relevant VDP updates
        } else {
            ... other things ...
        }

But the title screen does not enable IE1 and does not prepare a list of VDP updates — not even an empty list. So if FH is left to behave exactly as per the documentation then, through an uninitialised pointer, Space Manbow ends up blasting the start of the BIOS at the VDP upon every end-of-frame interrupt, which it mistakes for a line interrupt.

Empirically and based on the inherently-limited scope of my disassemblies, maintaining an internal FH as described but exposing it in S#1 only when IE1 is enabled seems to give correct execution. But that puts me into the sphere of guesswork so: is there any detailed third-party documentation of the Yamaha VDPs? Or a thread here somewhere that I've just failed to uncover? Or anybody who is willing to say a few words?

Login or register to post comments

By Grauw

Ascended (10821)

Grauw's picture

08-05-2023, 21:37

I believe if IE1 is off then FH behaviour changes to automatically reset at the end of horizontal blank.

Yep, found the following comment in openMSX source (“detailed third-party documentation”):

Quote:

} else { // line int disabled
// FH goes up at the start of the right border of IL and
// goes down at the start of the next left border.

When IE1 is off, FH also does not get reset by reading if openMSX source is to be believed.

So my model of VDP internals is, without IE1 there’s an FH pulse during the blank of the specified line, and with IE1 enabled this pulse is latched into a separate flag (let’s call it FH*) which is connected to /IRQ, and then reading s#1 instead reads and clears this latch. When IE1 is disabled FH* is kept forced cleared (not sure if this last bit is proven, but it’s what openMSX emulates).

p.s. Check out this related research topic on the latch timing of BL, SPD and M1-M5.

By TomH

Champion (375)

TomH's picture

09-05-2023, 16:30

Fantastic! So to repeat what I think I've learnt, summarising your work into a single place for the purposes of search results:

  • FH will always go high on the line indicated in R#19 upon the start of the right border — 1282 cycles after the start of the sync signal;
  • if IE1 is disabled, it will go low again at the start of the next left border — 202 cycles after the start of the sync signal, so 288 cycles after it went high;
  • if IE1 is enabled then somewhere around halfway through the left border — you've marked cycle 144 after sync as a most-accurate known estimate, i.e. 230 cycles after FH went high — the value of FH will be latched, alongside the other flags you mention (and, presumably, that's when interrupt line output will change?)

Thanks!

By Grauw

Ascended (10821)

Grauw's picture

10-05-2023, 02:15

TomH wrote:
  • FH will always go high on the line indicated in R#19 upon the start of the right border — 1282 cycles after the start of the sync signal;

Correct for the graphics modes. In the text modes it is 1254 cycles after the start of the sync signal.

TomH wrote:
  • if IE1 is disabled, it will go low again at the start of the next left border — 202 cycles after the start of the sync signal, so 288 cycles after it went high;

Correct, though in the text modes this means it is 316 cycles after it went high.

TomH wrote:
  • if IE1 is enabled then somewhere around halfway through the left border — you've marked cycle 144 after sync as a most-accurate known estimate, i.e. 230 cycles after FH went high — the value of FH will be latched, alongside the other flags you mention (and, presumably, that's when interrupt line output will change?)

Mmmh not quite, afaik with IE1 enabled FH itself and the IRQ are latched immediately at the start of the right border as FH goes high.

The cycle 144 thing is not directly related to the FH flag, it may have been a bit confusing to mention it in the same reply, but since I understand you’re adding V9938 support to your Clock Signal emulator I figured you would find it interesting.

Most registers (like table offsets or vertical display offset) act immediately, but some flags like BL, SPD and M1-M5 do not take immediate effect. E.g. if you set BL during active display, the screen does not immediately disable but rather waits until somewhere in the next horizontal blanking period. The question was when exactly in the horizontal blanking period does it disable, and the most precise answer I can give is at cycle 144. By emulating this correctly you will get a tight screensplit in those games.

By TomH

Champion (375)

TomH's picture

15-05-2023, 19:39

Grauw wrote:

The cycle 144 thing is not directly related to the FH flag, it may have been a bit confusing to mention it in the same reply, but since I understand you’re adding V9938 support to your Clock Signal emulator I figured you would find it interesting.

Fantastic, yes, thanks! I'm trying to short up my little implementation, but further propagating the information you've worked hard to figure out is obviously more valuable.

Grauw wrote:

Most registers (like table offsets or vertical display offset) act immediately, but some flags like BL, SPD and M1-M5 do not take immediate effect. E.g. if you set BL during active display, the screen does not immediately disable but rather waits until somewhere in the next horizontal blanking period. The question was when exactly in the horizontal blanking period does it disable, and the most precise answer I can give is at cycle 144. By emulating this correctly you will get a tight screensplit in those games.

Yeah, I'd taken a guess on that — within my particular implementation line data is buffered in its native form for a while, and all of those flags are captured once per line whereas other parameters, e.g. background colour, vary as and when they vary. It felt like a safe guess given the way that fetch activity is tied to future output and the relatively cheap cost of ensuring that bad programming definitely can't lead to display blemishes, but I'm extremely happy to find out that it's an appropriate guess. Even though I'm currently latching at the wrong time.

Thanks again!