What is going on over at 0x0038/VDP when NOT using EXX?

ページ 1/2
| 2

By Bengalack

Paladin (717)

Bengalack さんの画像

29-04-2020, 20:46

I thought that, as long as I preserve the registers I use in my interrupt code, I should be good. With this is mind I find the case below strange.

My interrupt-routine ("myLeanInterruptRoutine") uses only A(F) and HL-register, and is doing IN and OUT from port 0x99.

And here is the deal: Stub A works fine / system runs fine ("EXX-code"). Stub B makes the line interrupts trigger only in random frames ("POP-CODE").

Stub A

0x0038:
	exx
	push af
	push hl

	call	myLeanInterruptRoutine

	pop hl
	pop af
	exx
	ei
	reti

Stub B

0x0038:
	push af
	push hl

	call	myLeanInterruptRoutine

	pop hl
	pop af

	ei
	reti

From the image below you can see that the only things changed during the stub's entry and exit is the PC-reg, R-reg and EI is set as the last instruction.

(In case you wonder why i care to optimize this hard - it's part of screensplits, and I generally want to keep interrupt time to a minimum. Also, with split-effects, I want the time from the incurred line-interrupt happens to pc reaches my "custom" code, to be kept to an absolute minimum as well)

Why? Why do I need those exx's? Somehow the line-interrupts/VDP is affected by this. Known thing?

ログイン/登録して投稿

By norakomi

Paragon (1136)

norakomi さんの画像

29-04-2020, 21:46

afaik you need to check and 'acknowledge' your interrupts.

you do this with an in a,($99)

for lineint you need status register 1 set.
for vblank you need status register 0 set.

An interrupthandler without lineint:

InterruptHandler:
  push  af
  xor   a                 ;set s#0
  out   ($99),a
  ld    a,15+128
  out   ($99),a
  in    a,($99)           ;check and acknowledge vblank interrupt
  rlca
  call    c,vblank

  pop   af
  ei
  ret

an interrupthandler that also uses a lineint:

InterruptHandler:
  push  af
  ld    a,1               ;set s#1
  out   ($99),a
  ld    a,15+128
  out   ($99),a
  in    a,($99)           ;check and acknowledge line interrupt
  rrca
  call	c,LineInterruptHandlerDemos
  xor   a                 ;set s#0
  out   ($99),a
  ld    a,15+128
  out   ($99),a
  in    a,($99)           ;check and acknowledge vblank interrupt
  rlca
  call    c,vblank

  pop   af
  ei
  ret

About pushing and popping...
you only need to push and pop registers that you use in your interrupt routine.
So in your case you only need to push and pop af and hl
no need to use exx.

By Dolphin101546015

Champion (335)

Dolphin101546015 さんの画像

29-04-2020, 22:12

Also for speedup, you might always keep status reg, as indirrect Wink

By pgimeno

Champion (328)

pgimeno さんの画像

29-04-2020, 22:26

In fact exx does not save anything in the first place; relying solely on exx for saving registers in an interrupt routine can only be done if you're sure that no other part of the code uses exx. The ROM uses it, for one. Probably MSXDOS too.

@Bengalack if you replace the EXX with NOP, it should work the same. Does it?

By Grauw

Ascended (10699)

Grauw さんの画像

29-04-2020, 22:49

1. There’s no need to use exx. Some systems reserve the alternate register set for the ISR (one example is SymbOS and I think perhaps the CPC?). However IMO given the relative infrequency of interrupts, the benefit of having double the amount of registers available to your program far outweighs the cost of pushing / popping in your ISR. The BIOS ISR pushes and pops all registers before it does its thing.

I have no explanation of why the presence of exx makes things work, other than that the routine that you call touches alternate registers, or somehow has some kind of alignment requirement or some such. Unfortunately you don’t provide the contents of myLeanInterruptRoutine Smile.

2. Use ei, ret to return, not reti. reti is meant for a nested priority interrupt architecture that MSX does not use, so for MSX reti is just a slower version of ret and indeed the BIOS itself also uses just ret.

3. You want to check if the interrupt is a line interrupt, and if not, instead of returning, call the old ISR entry location to let the normal BIOS ISR process.

By Bengalack

Paladin (717)

Bengalack さんの画像

30-04-2020, 00:05

First of all, thanks for input guys!

norakomi wrote:

afaik you need to check and 'acknowledge' your interrupts.

Yes, I do this, that is why it works perfectly with in one of the cases.

norakomi wrote:

About pushing and popping...
you only need to push and pop registers that you use in your interrupt routine.
So in your case you only need to push and pop af and hl
no need to use exx.

Exactly. My thought as well.

pgimeno wrote:

@Bengalack if you replace the EXX with NOP, it should work the same. Does it?

Tried that. Tried other thing to slow slow down. No change.

Grauw wrote:

1. There’s no need to use exx.

I thought so too. That said, even when I do that, I need to preserve the registers (HL) it seems.

Grauw wrote:

2. Use ei, ret to return, not reti.

Ok, nice to know. Will do from here on (But I have tried it earlier though, does not help on my "case")

Grauw wrote:

3. You want to check if the interrupt is a line interrupt, and if not, instead of returning, call the old ISR entry location to let the normal BIOS ISR process.

Maybe, but that will probably not explain why my line-interrupts trigger only when EXX is used oO

It's all strange. I have tested it on openMSX as well as on real msx2 (SVI-738 / 9938).

The main-loop is in C, a loop which barely do anything (checking keyboard + joystick and waits for JIFFY to change). The keyboard and joystick check is my own code, going directly on the ports. All coded running is my own code, except for some generated from C.

The whole case is from a test-application I wrote... before moving it into a bigger engine. But the test-app is still a bit big. Too big to post here Smile I should probably isolate it to a super simple case which proves the problem. Easier to demonstrate and discuss then. Just wanted to check if people had seen anything like it.

By Grauw

Ascended (10699)

Grauw さんの画像

30-04-2020, 00:48

Try pushing and popping bc and de as well.

Your interrupt handler routine modifying one of those registers is the most likely explanation. The reason why it works when you use exx is because the ISR then corrupts the alternate bc' and de' registers, which you probably don’t use (much) in your program yet.

By Bengalack

Paladin (717)

Bengalack さんの画像

30-04-2020, 07:25

Grauw wrote:

Try pushing and popping bc and de as well.

Tried that too. Doesn't change anything. Only EXX works. Very strange.

By Daemos

Paragon (2044)

Daemos さんの画像

30-04-2020, 09:51

You do exx first and then push the registers. You specifically want to use the exx registers ? If you have the bios active the bios may write and corrupt your alternate registers.

Try:

Push hl
Push bc
Exx

Call inthandler

Exx
Pop bc
Pop hl

Ei
Ret

By gdx

Enlighted (6069)

gdx さんの画像

30-04-2020, 10:09

No need also to use RETI because it has the same effect than RET on MSX.

By Bengalack

Paladin (717)

Bengalack さんの画像

30-04-2020, 13:34

Daemos wrote:

You specifically want to use the exx registers ?

No, I really don't want to use EXX Smile My routine uses AF and HL, so all I want is to push and pop AF+HL. But it does not work.

I'll try to isolate this, and bake up a small sample demonstration.

ページ 1/2
| 2