Turbo R - interrupt line issues

Página 1/2
| 2

Por shram86

Expert (117)

imagem de shram86

29-03-2023, 22:19

Hello,

I've been working with good success on a MSX2 w/OPN game. It loads and runs well on both emulator and hardware configured for my machine (F1XDJ + FMPAC).

Someone tried to run it on their Turbo R, and it failed to load. It didn't reproduce in emulator, but when I tried a Turbo model (or anything with 9958, possibly), I was getting various confusing behaviors regarding the memory page map.

1. I use a custom interrupt handler that is stored low in ram (around 200h). This pushes and pulls the 8 main registers (I don't use shadow), acknowledges any vdp interrupts, calls vblank (which calls the music hook) and returns. This all runs fine on MSX2.
2. I am using "call 0005h" to load files from disk. This also works just fine on MSX2. On Turbo, this works fine *as long as I don't touch any interrupt hooks*. (I was also getting repeated behavior of this code in z88dk simply failing to return to the RAM page after executing, but in pure assembly this does not occur, much to my confusion).
3. A step through of my code on Turbo shows that the VBL signal is never cleared - it always returns to rst38 after EI / RETI. I was seeing this before on MSX2 when I forgot to ack the vblank interrupt, but I definitely am doing it here. Perhaps there is something else pulling the signal?

I realize this is confusing, but the long and short of it is this:
1. Does the Turbo R require acknowledgement of another interrupt line I am unaware of? Or, is there a different method of clearing the VDP interrupt? If so, how does one ack and clear it?
2. Is there any reason why "call 5" wouldn't work on Turbo R in MSX-DOS 1 mode? Possibly due to an aforementioned interrupt line I am unaware of?
3. Here is my interrupt:

_irq:
        di 
        push af 
        push bc 
        push de 
        push hl 

        ; vdp ack
        ld c,$99 
        ld a,0      ; status reg 0
        out (c),a 
        ld a,15+$80 ; r15=statregsel
        out (c),a
        in a,(c)    
        and $80
        call nz,vblank ; if it was from the vdp, call vblank code 
       ; vdp ack 2 - just in case hblank is set... 
        ld a,1 
        ld c,$99
        out (c),a 
        ld a,15+$80
        out (c),a 
        in a,(c)

        ; return 
        pop hl 
        pop de 
        pop bc 
        pop af 

        ei 
        reti
        vblank:
            call $fd9f  ; htimi, used by musica 
            ret 

Am I missing anything huge here? Why would a game that runs perfectly on an MSX2 simply fail so hard on a Turbo with such a multitude of symptoms? What could I be missing?
Program disk

Well... thanks for reading.

Entrar ou registrar-se para comentar

Por Grauw

Ascended (10818)

imagem de Grauw

29-03-2023, 22:44

What happens when page 0 is switched to e.g. the BIOS and an interrupt occurs? The normal ISR assumes status register 0 is selected and just does an IN (99H), so the interrupt won't get acknowledged, so it will get into an infinite interrupt loop.

Also, a hook on FD9FH assumes all registers are preserved since this is what the BIOS ISR does, but you call it without doing so, leading to possible register corruption by the ISR. This hook often contains calls to the DiskROM, for example.

p.s. No need to di at the start of the interrupt, and on MSX you do not need to use reti to return from interrupts, a normal ret suffices.

Por shram86

Expert (117)

imagem de shram86

29-03-2023, 22:51

Grauw wrote:

What happens when page 0 is switched to e.g. the BIOS and an interrupt occurs? The normal ISR assumes status register 0 is selected and just does an IN (99H), so the interrupt won't get acknowledged, so it will get into an infinite interrupt loop.

Is this avoidable by forcing off vdp interrupts during this period?

Quote:

Also, a hook on FD9FH assumes all registers are preserved since this is what the BIOS ISR does, but you call it without doing so, leading to possible register corruption by the ISR. This hook often contains calls to the DiskROM, for example.

Can you explain a bit more? Does this mean an additional push/pop sequence before and after "call $fd9f" is expected? If so, that isn't a concern here because there isn't any further code happening here, and the pre-interrupt registers are restored right after.

Quote:

p.s. No need to di at the start of the interrupt, and on MSX you do not need to use reti to return from interrupts, a normal ret suffices.

ah thx Wink

Por Grauw

Ascended (10818)

imagem de Grauw

30-03-2023, 00:38

shram86 wrote:
Grauw wrote:

What happens when page 0 is switched to e.g. the BIOS and an interrupt occurs? The normal ISR assumes status register 0 is selected and just does an IN (99H), so the interrupt won't get acknowledged, so it will get into an infinite interrupt loop.

Is this avoidable by forcing off vdp interrupts during this period?

No, the BIOS or BDOS routines that you call may enable interrupts themselves. It is best to uninstall your custom ISR and restore the standard one while you call the BIOS or BDOS.

Or instead of fully removing it, make your ISR robust if sometimes the BIOS ISR is called instead, so change ld a,1 to ld a,(RG15SA), and set system variable RG15SA to 0 while you call BIOS and BDOS routines. And disable any other interrupts (like line interrupts) as well, or handle them in H.KEYI, otherwise those might go unhandled.

shram86 wrote:
Grauw wrote:

Also, a hook on FD9FH assumes all registers are preserved since this is what the BIOS ISR does, but you call it without doing so, leading to possible register corruption by the ISR. This hook often contains calls to the DiskROM, for example.

Can you explain a bit more? Does this mean an additional push/pop sequence before and after "call $fd9f" is expected? If so, that isn't a concern here because there isn't any further code happening here, and the pre-interrupt registers are restored right after.

Yes. Including pushing / popping ix/iy and the alternate registers. The BIOS ISR starts like this. If you call hooks, allowing arbitrary code to execute, then you should do the same.

It is not the registers within the ISR code itself that may be corrupted, but those of the code that was interrupted, which can be anything.

Por shram86

Expert (117)

imagem de shram86

30-03-2023, 00:33

Thanks for the tips! I'll do some research and see if I can't get it working.

Por Grauw

Ascended (10818)

imagem de Grauw

30-03-2023, 00:39

Grauw wrote:

No, the BIOS or BDOS routines that you call may enable interrupts themselves. It is best to uninstall your custom ISR and restore the standard one while you call the BIOS or BDOS.

Or instead of fully removing it, make your ISR robust if sometimes the BIOS ISR is called instead, so change ld a,1 to ld a,(RG15SA), and set system variable RG15SA to 0 while you call BIOS and BDOS routines. And disable any other interrupts (like line interrupts) as well, or handle them in H.KEYI, otherwise those might go unhandled.

Alternatively, put your custom ISR in high memory (above C000H) using IM 2, and make sure it does not access any code or variables below that. Then your ISR will remain in use even when the BIOS is paged in, since page 3 is never switched out.

Por shram86

Expert (117)

imagem de shram86

30-03-2023, 06:46

Thanks for the replies so far. I haven't figured it out, but I haven't given up yet either. Im properly saving all registers now as I should.

Grauw wrote:

No, the BIOS or BDOS routines that you call may enable interrupts themselves. It is best to uninstall your custom ISR and restore the standard one while you call the BIOS or BDOS.

Or instead of fully removing it, make your ISR robust if sometimes the BIOS ISR is called instead, so change ld a,1 to ld a,(RG15SA), and set system variable RG15SA to 0 while you call BIOS and BDOS routines. And disable any other interrupts (like line interrupts) as well, or handle them in H.KEYI, otherwise those might go unhandled.

This I think is the path I should take, but I'm having trouble figuring out where/ at what time the status register needs to be saved. I took a look at the RST38h handler on F1XD, and it looks like this:

DDB4  ld     hl,(#ddd1)   2A D1 DD ; scratch location of current RAM stack pointer 
DDB7  ld     a,l          7D
DDB8  or     h            B4 ; A = SP low OR sp hi...?
DDB9  pop    hl           E1 ; 
DDBA  ld     ix,#0038     DD 21 38 00 ; RST38 location
DDBE  ld     iy,(#fcc0)   FD 2A C0 FC  ; FCC1-1 (mnrom)
DDC2  jr     nz,#dde7     20 23
DDC4  pop    af           F1
DDC5  ld     (#ddd1),sp   ED 73 D1 DD ; save sp 
DDC9  ld     sp,#dda8     31 A8 DD ; temporary sp 
DDCC  call   #001c        CD 1C 00  ; inter-slot call 
DDCF  di                  F3

Interestingly, it jumps to a location where it then performs another inter-slot RST38 (the mnrom handler). Well, know I know. Lots more work to be done...

I tried to find an example where RG15 was saved and restored for use in this situation - I know I saw it once before but now I am at a loss. Let me know if you have one off hand.

Por gdx

Enlighted (6422)

imagem de gdx

30-03-2023, 09:18

You don't have to save all registers, only the ones you use in your ISR. I think the best is to switch your custom ISR with that of the system depending on what you want to do as Grauw suggests. When using DOS and Bios routines, switch to the DOS ISR. It's not necessary to use IM2. And remove the call $fd9f from your custom ISR.

Por ro

Scribe (5056)

imagem de ro

30-03-2023, 11:39

Hai,

I'm doing the same thing; custom ISR on #38 on turbo R. Works fine, nothing special needed for that machine.
The FD9F call, like GDX mentioned, is better to ignore unless you want diskdrives to stop spinning. But there's other methods for that.

on Vblank you call musica, make sure you save the right registers used by that replayer (unless its saving the regs on its own)

The only thing I could think of, is some slot switching going on (musica?) - if you have DOS enabled and page 0 is RAM this would just work.

Por shram86

Expert (117)

imagem de shram86

30-03-2023, 15:12

ro wrote:

Hai,

I'm doing the same thing; custom ISR on #38 on turbo R. Works fine, nothing special needed for that machine.
The FD9F call, like GDX mentioned, is better to ignore unless you want diskdrives to stop spinning. But there's other methods for that.

on Vblank you call musica, make sure you save the right registers used by that replayer (unless its saving the regs on its own)

The only thing I could think of, is some slot switching going on (musica?) - if you have DOS enabled and page 0 is RAM this would just work.

Interesting... Well, Musica prefers to hook itself into fd9f and backup / call what was there previously. I didn't really see an issue with that, but instead I've taken to calling it directly each vblank just in case. It does indeed flip pages (this is the problem on Turbo) to find the MSX-MUSIC rom and access it there before restoring it (it is located at page 1 on the FS-A1ST).

Grau I believe is correct on what is happening - during a disk access or playback routine that uses a ROM page, IRQ is pulled low to 38h. I've managed to keep a new test rom stable, but the audio isnt playing, so I am still doing something wrong. Mind that it isn't that ISR isn't working, but by coincidence and the paging and timing of vblank made my particular project break. This is why I believe that restoring the previous ISR during this time is the correct method but I am having trouble getting it to cooperate (no clear reason yet, but trying to use fd9f is probably part of it).

My next test is going to be installing my own ISR at the location found at $0038, take out the interslot rst 38 and see what happens.

Por shram86

Expert (117)

imagem de shram86

30-03-2023, 19:18

Thanks all, I was closer than I thought - late-night error I fixed this morning. FS-A1ST confirmed working.

Some interesting notes, because I'm still not sure this method will work on *all* machines:
1. Install my own ISR at $0038 (<- what are some machines that might have strange behavior in their ISR...?)
2. My ISR does: Push/pop all, call $fd9a (possibly to reset a line?), ack vdp, call $fd9f (musica hooks itself, then runs previous fd9f code)

This removes the built-in interslot RST38, but as far as I can tell minus sprite collision, timer increment, and SOUND call my routine is now identical to MNROMs. Since this might be helpful for someone in the future to see in entirety:

org 0x100
    di 
    ; install ISR first thing 
    ld a,$c3 
    ld ($0038),a 
    ld hl,_irq 
    ld ($0039),hl 

    :load files using call 5, 
    :vdp writes, install music driver, etc

    ei 
    loop: jr loop 

_irq:
    ;di               ; exchange everything just in case
    push    hl
    push    de
    push    bc
    push    af
    exx
    ex      af,af'
    push    hl
    push    de
    push    bc
    push    af
    push    iy
    push    ix

    call $fd9a      ; possibly needed to reset an irq line on some machines? 
    
    ; vdp ack
    ld c,$99 
    ld a,0              ; status reg 0
    out (c),a 
    ld a,15+$80
    out (c),a
    in a,(c)   
    rlca                ; bit7 = vbl
    call nz,vblank ; if it was from the vdp, call vblank code 

    pop     ix
    pop     iy
    pop     af
    pop     bc
    pop     de
    pop     hl
    ex      af,af'
    exx
    pop     af
    pop     bc
    pop     de
    pop     hl
    ei
    ret            
    
    vblank:
        call $fd9f         ; mnrom calls this here as well btw 
    
        ld a,(0xc001)
        inc a 
        ld (0xc001),a   ; increment as a test once per frame 
    
        ret 

Página 1/2
| 2