Plus Vectored Interrupts
On the Amstrad Plus and GX4000 it is possible to use Z80 Interrupt mode 2 (IM 2). When maskable interrupts are enabled (EI) and the interrupt is acknowledged by the Z80, the ASIC will provide a vector which is put onto the bus.
This vector and Z80 register I are used to form an address:
(I*256)+vector
The Z80 will then read a 2-byte address which is the location of the interrupt handler.
Bit 0 of the vector will be 0. Bits 3..1 are generated by the ASIC based on the interrupt source (one of the DMA channels or raster interrupt). Bits 7..4 are defined by writing a value to the ASIC IVR register (at &6805 in the ASIC registers).
The raster interrupt interrupt comes from the CPC compatible 52-line interrupt OR the Plus programmable line interrupt (PRI at &6800 in the ASIC registers).
Bit 0 of IVR is set to 1 at power-on but the other bits are undefined, so you should either:
- Set the IVR value by writing to 6805 after unlocking the asic and making the registers visible
e.g.
... di call asic_unlock ld bc,&7fb8 out (c),c ld a,1 ld (&6805),a ld a,&40 ld i,a ld hl,dma0_handler ld (&4000),hl ld hl,dma1_handler ld (&4002),hl ld hl,dma2_handler ld (&4006),hl ld hl,raster_handler ld (&4008),hl im 2 ei ...
- OR, you can repeat the same interrupt function handlers through the entire 256 byte vector range.
e.g.
... di ld a,&40 ld i,a ld hl,dma0_handler ld (&4000),hl ld hl,dma1_handler ld (&4002),hl ld hl,dma2_handler ld (&4006),hl ld hl,raster_handler ld (&4008),hl ld hl,&4000 ld de,&400a ld bc,256-&a ldir im 2 ei ...
See Arnold_V_Specs_Revised for more information.
The Vectored Interrupt Bug
NOTE: Vectored interrupts are bugged.
Following discussions on cpcwiki involving roudoudou, Longshot, gerald, arnoldemu and dragon, it has been found that if the instruction which is being interrupted is located in a memory region where A13=1 (i.e. &2000-&3fff, &6000-&7fff, &a000-&cfff, &e000-&ffff) then the bug will not occur.
When the instruction is in a memory region where A13=0 then the vector will be seen to change between 6 and 4. This is related to if the CPU is performing a memory read/write.
The bug is independent of the value of I register, the location of the interrupt service routine, the location of the vector table which has the interrupt service routine addresses.
The exact triggers are being investigated.
Advice, either point all interrupt vectors to the same interrupt handler and manually acknowledge the dma interrupts OR locate your code where A13=1.