How to debug vdp interruption

By jepmsx

Master (253)

jepmsx's picture

21-12-2022, 11:38

Hi!

I'm trying to debug why my vdp interruption isn't working. I've set a breakpoint at the beginning of the loop and kept pressing F9 in openmsx-debugger without success. It always stops at the same position, it doesn't seem to generate the vdp interruption.

Is there a way to set a breakpoint to the vdp interruption?

Login or register to post comments

By Grauw

Ascended (10768)

Grauw's picture

21-12-2022, 11:44

It seems easiest to just set a breakpoint on address 38H?

You can also use a probe breakpoint on the interruption signal I believe.

By jepmsx

Master (253)

jepmsx's picture

21-12-2022, 12:32

Thanks Grauw for your answer.

Reading the artticle about interrupts I understand that 38H is a set of instructions to prepare for the interruption and then jumps to address FD9FH where there is a jump to my routine. Am I right?

By Grauw

Ascended (10768)

Grauw's picture

21-12-2022, 13:21

Yeah, when the interrupt occurs the Z80 CPU automatically calls the ISR (Interrupt Service Routine) at address 38H in the BIOS.

The ISR stores all registers on the stack, and calls the FD9AH hook (H.KEYI).

Then the ISR checks with the VDP if the interrupt was the VDP vertical blanking interrupt signal. If that is the case, it calls the FD9FH hook (H.TIMI), and then does a couple of other things like increasing the JIFFY timer counter, reading keyboard inputs, etc.

Lastly when the ISR ends, it restores all registers from the stack and returns to the original program.

By jepmsx

Master (253)

jepmsx's picture

21-12-2022, 17:27

Thanks a lot Grauw!

Following your explanation, I've been able to see why it doesn't work. After some steps after the breakpoint in FD9FH I've seen that there is an out (#a8),#FF that restores page $0 to slot 3-0 segment 3. But in the program that doesn't work, the out is out (#a8),#FC which does not restore page $0.

I'm using the same function of Fusion-C (InitVDPinterruptHandler) in two different programs, one does it well (page $0 is restored) and the other no. The main difference is that in the one that works InitVDPinterruptHandler is in an address below $4000 and the one that doesn't work the address of the function is in an address above $4000.

I still don't know why in the version that doesn't work page $0 is not restored

By ducasp

Paladin (680)

ducasp's picture

21-12-2022, 18:12

jepmsx wrote:

Thanks a lot Grauw!

Following your explanation, I've been able to see why it doesn't work. After some steps after the breakpoint in FD9FH I've seen that there is an out (#a8),#FF that restores page $0 to slot 3-0 segment 3. But in the program that doesn't work, the out is out (#a8),#FC which does not restore page $0.

I'm using the same function of Fusion-C (InitVDPinterruptHandler) in two different programs, one does it well (page $0 is restored) and the other no. The main difference is that in the one that works InitVDPinterruptHandler is in an address below $4000 and the one that doesn't work the address of the function is in an address above $4000.

I still don't know why in the version that doesn't work page $0 is not restored

Fusion-c 1.2 interrupt routines are buggy, they should work if you don't have anything that change slot pages and your routine is on any page that is not 0 or any page that is not switched. The hook doesn't use interslot call... And that's bound to cause issues Tongue I've worked on an example from Darkschneider and generated a better handler that should be in 1.3 or something similar, you can either ask Eric for a beta of it or use my version of Fusion.lib and headers:

https://drive.google.com/drive/folders/1inY5kp2QYKCJtnjxVaNr...

That, should work for code in any page and you can choose general interrupts or vdp interrupts only ;)

By jepmsx

Master (253)

jepmsx's picture

21-12-2022, 18:21

Thanks a lot ducasp!

I've already done that. This problem is with Fusion-c 2beta

By ducasp

Paladin (680)

ducasp's picture

21-12-2022, 20:47

jepmsx wrote:

Thanks a lot ducasp!

I've already done that. This problem is with Fusion-c 2beta

So, the code should not restore the slot in page 0, but, the slot in the page where the interrupt code resides currently (and hopefully, that is the slot selected when Init... is called). The interrupt initialization routine is simplified and it looks for the slot where page 1 is located when the function Init is called... For all purposes, unless you did use some mapper routine to re-allocate page 1, that should be the same RAM slot for all pages.

On the other hand, being that the code only restore the slot where the interrupt function resides, you must make sure that:

  1. Function does not span over pages (i.e.: start at 0x3FF0 and finishes at 0x4100)
  2. Interrupt function will not update or call or depend on anything that is not on the same page it resides

As an example, if you are setting some variable at page 0 when your interrupt code is running on page 1, there is no guarantee that page 0 won't have BIOS paged in, if you call something there, even worse...

Also, notice that you should try to make your interrupt function as simple and lean as possible, avoiding to execute stuff or calling functions there unless absolutely necessary. z80 is not a powerhouse and if you take too much time executing stuff during your interrupt (and remember, it is not just you that is executing code at that time, BIOS too has some stuff and some other device/code could be hooked to it as well). One example is: if you have a game engine and wants to check input every screen update, do not make the joystick checks and all stuff in the interrupt, use the interrupt to set a memory flag and have your loop code check that memory flag and if it is 1 (example) you know interrupt occurred and it is time to read inputs and update everything, just make sure to set that to 0 (example) as soon as you check it to be 1 so the loop won't run all the time.

I'm guessing that your program that has some issues is either having the interrupt routine calling something in other page than its own page (most likely page 0, as 1, 2 and 3 won't change usually in a C / DOS Program) and something else is paged there at interrupt time (i.e.: bios)...

By jepmsx

Master (253)

jepmsx's picture

21-12-2022, 21:59

Thanks ducasp for your answer, it is very clarifying.

My interrupt function updates PSG and FM and some global variables that I use as a flag. But maybe some of these functions call functions in another page. I'll try to simplify it more as you suggest, removing all the functions, and check if it works.

By ducasp

Paladin (680)

ducasp's picture

23-12-2022, 23:07

After looking carefully, there is a corner case scenario that the routines proposed for sdcc and part of sdcc 1.3 beta and probably sdcc 2.0 whenever it is ready do not cover... If the interrupt handler function registered is at page 0 and the library code is on any other page, it won't work, because the interslot call is made internally to a function that is part of the library code (so the interslot call will set the slot for that page, not page 0, that will be paged to bios)... The internal function will then make a simple call to the registered function, at page 0, and that will be paged to bios and crash.... Crying

I've quickly made a solution for that (the internal function is used to force push af and pop af before returning to the old hook, as this is needed for H_TIMI) but unfortunately my sdcc/fusion-c install doesn't like the library built by me, probably will need to reinstall it from the scratch and use the recommended old fusion-c version and that will be a pain, so it will take some time before I can test the solution and send it back to Eric to incorporate into fusion-c... In the mean-time there are two possible work-arounds:

  1. Make sure that either the library code for interrupt is mapped on page 0 (which might be quite difficult depending on your code size) or that your interrupt routine is on any page other than 0 and doesn't access anything at page 0
  2. Use the functions InterruptHandlerHelper / InitializeMyInterruptHandler / EndMyInterruptHandler from https://github.com/ducasp/MSX-Development/blob/master/SDCC/A... in your own code and make sure those are the very first functions in your C file so they sit at page 0, they are basically the library current interrupt code adapted to be compiled in C files (a little bit different due to some limitations on inline assembly), this will make it work nicely no matter what page your interrupt handler is

By jepmsx

Master (253)

jepmsx's picture

24-12-2022, 08:06

I've used the second approach and works like a charm.
Thanks a lot ducasp for your answer and time.