cool thanks for this tip i will study this.
Cool. I realise I forgot fully to explain the logic behind my suggestion though. In interrupt mode 2 the Z80 expects the peripheral causing the interrupt to supply a value identifying itself during the interrupt cycle. It uses the I register as the high byte and the value supplied by the peripheral to form the address from which to fetch the address of the interrupt handler. So the intention was to allow vectored interrupts.
I don't think the MSX bus is required to be in any particular state during the interrupt cycle, so you have no idea what will be picked as the low byte of the address. You don't even know whether it'll be even or odd.
So the 16-bit vector might be loaded from any of 256 addresses.
You therefore put your interrupt routine at an address where high byte = low byte, and put that byte into a table 257 times because then it doesn't matter which address the Z80 starts reading the vector from. It'll always end up with the address of your routine.
That all being said, it strikes me that: (i) you're going to have to assume your RAM is always paged in when the interrupt occurs for that to be safe; and (ii) if you can safely assume you've taken full control over paging, you could just put RAM in the lowest bank and place your routine at 0038h. I guess the only difference is whether you want to make 64kb RAM a requirement.
Thank you again for your response.
Because i am using SDCC for my little project, i am still troubling with doing this the easy way. IM2 is kinda tricky in my current "workflow".
Polled timing:
__ASM ei halt __ENDIF
Works fine for me to run the code on timed, but i wanted to disable the system interrupts temporary.
I took ROADFIGHTER rom and had a look how konami did it.
They basically hook the whole game on HKEYI. They use a trick for not allowing the system to continue with HTIMI and updating the rest of the system.
Just before they return from HKEYI hook they add:
call 013e
So i guess this is a trick to fool the bios that the vdp didnt generate the interrupt
bios part:
0C3C: push hl 0C3D: push de 0C3E: push bc 0C3F: push af 0C40: exx 0C41: ex af,af' 0C42: push hl 0C43: push de 0C44: push bc 0C45: push af 0C46: push iy 0C48: push ix 0C4A: call #fd9a 0C4D: in a,(#99) 0C4F: and a 0C50: jp p,#0d02 0C53: call #fd9f --- slowing down system stuff here ... 0D02: pop ix 0D04: pop iy 0D06: pop af 0D07: pop bc 0D08: pop de 0D09: pop hl 0D0A: ex af,af' 0D0B: exx 0D0C: pop af 0D0D: pop bc 0D0E: pop de 0D0F: pop hl 0D10: ei 0D11: ret
I still dont know how to refer to direct (dynamic) address in SDCC on an interrupt, this looks like a solution for now.
Hope to release my little project soon, working more then a year on this... Yes i suck.
Some time ago I caught exactly the same issue when developing something for GR8NET (video player or MP3 player, do not remember exactly). I do not recall how I got this info, most probably someone knowledgeable told me here on the forum.
Solution: it is completely BAD idea to poll status register of the VDP. There are circumstances when interrupt condition occurs, some internal flag is being set, but by reading S#0 you still read old value of 0, but that internal flag gets reset, thus it never appears set in S#0 bits. That's why you miss interrupt condition.
The ONLY reliable way to get 50/60 Hz (and I guess other types of interrupt) from the VDP is using ISR, this way you are 100% complete with correct interrupt flag processing and interrupt-related bits are being improperly handled.
If you are in BASIC and need performance, the only way to get Z80 jumping to your ISR is to use IM2 mode (as previously stated), having I register preset appropriately before you enable interrupts. It will require a jump table of 257 byte size with the same content so that reading from any (addr) LSB and (addr+1) MSB location within this table return the same 16-bit address (e.g. filling table with &h81 will cause jump to address &h8181), not depending on what would-be peripheral device supplies. By the way, looking through Z80 datasheet I do not see it properly and explicitly stating at which bus interrupting device must put vector to - to address A[7:0] or to data D[7:0]!
By the way, looking through Z80 datasheet I do not see it properly and explicitly stating at which bus interrupting device must put vector to - to address A[7:0] or to data D[7:0]!
Eugeny, the device vector always comes to D[7 : 0] on the interrupt vector request -> !M1 & !IORQ.
Z80 address bus is either output or tri-stated.
@Wlcracks
BEWARE of Z80 and its clones fetching the interrupt table content from ODD addresses when supplied with the ODD vector on the data bus. Z80 manual is mute about it and emulators often ZERO the address bit 0, which is wrong. The real Z80 and its clones take the ODD table entry (0xFF in the LSB) and continue to the next address for the MSB for the jump address fetch when provided with 0xFF on the data bus.
Regarding the ODD device vector address (forbidden combination for the normal CPU operation) here are a few considerations:
- MSX1/2/2+ has historically the pull-up resistors on the databus. I.e. any I/O read yields 0xFF. However, the device vector address must be EVEN, but since 0xFF is returned on an empty data bus it will be ODD. Therefore the ISR address will be fetched from :
LSB is fetched from (I_reg<<8) + 255
and MSB is fetched from (I_reg+1)<<8, where I_reg is the I register.
Bottom line: if the data bus state is unknown and/or it's necessary to get the code running on ANY MSX machine, the ISR vector table MUST have not only 257 entries, but also the SAME MSB and LSB for the interrupt vector routine (required to cover the odd/even case on the data bus). For example, the interrupt vectors like 0xFEFE, 0xFDFD, 0xC1C1 are completely valid since MSB=LSB.
By the way, looking through Z80 datasheet I do not see it properly and explicitly stating at which bus interrupting device must put vector to - to address A[7:0] or to data D[7:0]!
the Axx lines on z80 are address bus.. Address bus in uni-directional bus.
D0-D7 is of course bidiretional