Anyway that code seems fairly sane, it's hard to tell what the routine it calls does though obviously.
Maybe it uses IY or AF' or the shadow registers and doesn't then restore them? And so does the rest of the game or whatever else you are doing?
To be 100% safe you have to push and pop everything on entering/leaving the ISR
Code: Select all
push af
push bc
push de
push hl
push ix
push iy
ex af, af'
push af
exx
push bc
push de
push hl
Code: Select all
pop hl
pop de
pop bc
exx
pop af
ex af, af'
pop iy
pop ix
pop hl
pop de
pop bc
pop af
should do that. (Not tested)
You definitely can't do a JP 56 if IY is not the magic value it usually has when Basic is running (since when it updates the frame counter and the currently pressed keyboard key it assumes IY points to the sysvars). Otherwise you will trash memory.
If you know that the routine you call only trashes IX, AF, BC, DE and HL what it is doing now (code you posted) is ok.
I had a look at some code for one version of vortex (I think) and it definitely uses AF'. It also modifies IY but there is a compile option Basic = 1 which looks like it restores it to the correct value (but if you turned that flag off, or it seems there may be an older version which did not do that, that would be bad).
You probably want to look in the debugger what the register values are on entry to the ISR (all registers and shadow registers, and the SP. Also check the top of the stack value because that is where it will return to once the ISR is finished). Then once you hit the JP 56 check they are all the same. Otherwise bad things (TM) will likely happen.
If the ISR does not save and restore everything random hard to debug weirdness is bound to happen depending on what the program was doing when the interrupt went off (usually could be doing absolutely anything).
Obviously all the addresses must be correct as well (i.e. the ISR must be at the address it expects, as must those variables which control the playing and reading the keyboard). You can debug that by putting a breakpoint on 46336 (should be the JP ISR it poked into memory) and seeing where that ends up.
Also verify that when you call the entry point it takes you to the expected place in the player. Otherwise you have assembled it to the wrong address.
Sometimes ISR bugs can stay hidden for a while if the code you run usually enters the ISR only while the CPU is doing a HALT instruction - everything looks fine then if you run at 50FPS but as soon as you drop a frame - BAM! - everything will break. As an added bonus, it will usually not break and crash immediately but quietly corrupt memory, end up looking at the wrong flag values, etc. which can take a while to become apparent, long after the problem actually started happening. Randomly occurring hard to reproduce bugs are usually a good sign there is something wrong with the ISR.
The reason the Z80 shadow register set was added in the first place was apparently to avoid pushing and popping things in the ISR as an option (say you are running on hardware with hardly any stack space available). If you never use AF' or EXX in your entire code you can just do an EX AF, AF' and EXX on entry to the ISR and the reverse (or the same, order does not matter) before you exit. Then you don't use any stack space apart from the ISR return address and it's also faster than all those pushes and pops - important for devices which must service interrupts as fast as possible when they go off (e.g. running a nuclear power station using a ZX81 as the reactor control system)
Then of course Spectrum programmers realised how fast and amazingly handy the EXX and EX AF, AF' instructions are so you can't do your ISR like that if you use them outside of the ISR
EDIT: It also goes without saying that if your code has modified IY at any point when the ISR goes off, and then you jump to the ROM ISR, it would be bad
I usually just define my own frame counter variable which I update in the ISR and you don't need to update the currently pressed key flag unless you use it in the rest of the code, since you are reading the keyboard port directly in that routine. Then I don't bother with any of the stuff it does in the ROM ISR since I don't need it.
If you never use ROM calls and never intend to return to basic except via CALL 0 you can even use the sysvars area for your own data if you want.