Interrupts: Difference between revisions
No edit summary |
|||
| (5 intermediate revisions by 3 users not shown) | |||
| Line 20: | Line 20: | ||
Using this register to "move" the standard interrupt to just after the final line of the visible screen can increase the time available for processing between frames. | Using this register to "move" the standard interrupt to just after the final line of the visible screen can increase the time available for processing between frames. | ||
= Hardware IM2 Mode = | |||
Different from the regular IM2 mode which, from the programmer's perspective, matches the behavior of the original ZX Spectrum, a new "Hardware IM2 mode" exists in the core version 3.02.00 and above. It allows configuring different interrupt handlers for different interrupt sources. | |||
Hardware IM2 mode is turned on with bit 0 of Next Register 0xC0 ({{NextRegNo|$C0}}) and has a full set of prioritized and chained interrupts, each with well-defined separate vectors. In this mode, when the IM2 occurs the lower 8 address bits are set as described in the reference documentation of the C0 next register: https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/-/blob/master/cores/zxnext/nextreg.txt?ref_type=heads | |||
Interrupt requests are cached and held while a higher priority interrupt is being serviced, then triggered (potentially late) as soon as the higher priority interrupt is returned. All returns in this mode have to be done with '''''reti''''' to allow the hardware to track the priorities. | |||
In standard mode and on regular Spectrums, if an interrupt is missed (the '''''/INT''''' line is released before the interrupt is accepted) then the interrupt is lost forever. | |||
= Extra titbits about timing from discord by AA = | |||
''The copper counts according to the pixel currently being generated with (0,0) corresponding to the (0,0) position of the ula's 256x192 screen. You can adjust where vertical 0 is for the copper via nextreg but not horizontal position (yet?). Line interrupt & raster line position also use the copper's vertical coordinate.'' | |||
''The ula actually reads pixel and attribute data 12 pixels before they are displayed. So if the copper registers x=0, indicating pixel 0 is being generated, then the ula fetched that pixel/attr data during the previous 12 cycles.'' | |||
''The line interrupt for line=y occurs at line=y-1, x=256 iirc. Ie, the interrupt occurs just after the 256-pixel area has been drawn in the PREVIOUS line. That's to give maximum time to do things BEFORE the indicated line is drawn.'' | |||
''The vbi interrupt from the ula occurs where it does on the spectrum which I can't remember offhand. It's in the vertical blank time, probably at x=0 or 1. The 128K video frame as it a little later at x=1 because the 128K machines have an RC capacitor on the pcb on the /int line from the ula.'' | |||
''If you need more precision with interrupt timing, you can get the copper to generate interrupts via a nextreg.'' | |||
= Another Summary, with Core Versions Specified (from discord, by SevenFFF) = | |||
(This summary contains more exact information about the core versions). | |||
There are three interrupt scenarios and they sometimes get mixed up and conflated: | |||
1) Classic Spectrum/Z80 behaviour: mode 0 (not usable on a Speccy), mode 1 and mode 2. VBI triggers interrupts and that's fixed in hardware. No other interrupt sources. Needs a 257 byte table as the floating bus or external hardware can put random vectors on the bus. | |||
2) Original Next behaviour. As classic spectrum, but VBL also triggers interrupts. Can turn VBI and VBL sources off separately, independently of whether interrupts are enabled or what mode they're in. Floating bus doesn't put random vectors on the bus, but hardware still can, so 257 byte table is recommended. | |||
3) Next hardware mode 2. Can opt into this via nextreg. Multiple sources you can opt into (VBI, VBL, ESP UART Tx received, ESP UART Rx ready, Pi UART Tx received, Pi UART Rx ready, CTC timers elapsed (channels 7 and 8). Each source has their own specific guaranteed vector, so you can use vector tables as Zilog originally intended (yay!). Interrupt sources have priorities and higher priorities can interrupt lower ones. Must return from handlers with RETI so that the hardware can track the chain state. All this is available in 3.01.08 and above. Can also trigger some interrupts programmatically (3.01.10 and above). Fixed some bugs with interrupt status bits (3.02.00 and above) | |||
(Here, VBI stands for vertical blank interval, one interrupt per frame. VBL is probably the line interrupt , once per line. It's not called VBL in the hardware docs. The docs call them UAT interrupt and line interrupt.) | |||
Latest revision as of 17:30, 29 August 2025
Default Interrupt Handler
The default interrupt handler is at address $0038 in ROM and is automatically called by the Z80 in Interrupt Mode 1.
It:
- updates the system variable frame counter;
- scans the keyboard and updates the keyboard state system variables.
The default interrupt handler preserves all registers and has no external requirements.
You can replace the interrupt handler by either:
- Setting the Z80 to interrupt mode 2 (IM 2) and configuring the address for a custom interrupt handler. Due to the restrictions on the Z80's interrupt specification, this requires placing the interrupt handler at an address where the high and low bytes are the same.
- Using Next Memory Management to page out the ROM at address $0038 and replace it with a RAM page with your own routine at offset $38.
Interrupt Timing
The standard Spectrum ULA raises an interrupt every video frame. This is very commonly used in games to synchronize graphics with the updates of the screen.
You can adjust the timing of video interrupts using {{#ask: TBRegisterNumber::$22 }} ($22). This will allow you to add an extra interrupt that occurs at a particular line address, or disable the standard ULA interrupt.
Using this register to "move" the standard interrupt to just after the final line of the visible screen can increase the time available for processing between frames.
Hardware IM2 Mode
Different from the regular IM2 mode which, from the programmer's perspective, matches the behavior of the original ZX Spectrum, a new "Hardware IM2 mode" exists in the core version 3.02.00 and above. It allows configuring different interrupt handlers for different interrupt sources.
Hardware IM2 mode is turned on with bit 0 of Next Register 0xC0 ({{#ask: TBRegisterNumber::$C0 }} ($C0)) and has a full set of prioritized and chained interrupts, each with well-defined separate vectors. In this mode, when the IM2 occurs the lower 8 address bits are set as described in the reference documentation of the C0 next register: https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/-/blob/master/cores/zxnext/nextreg.txt?ref_type=heads
Interrupt requests are cached and held while a higher priority interrupt is being serviced, then triggered (potentially late) as soon as the higher priority interrupt is returned. All returns in this mode have to be done with reti to allow the hardware to track the priorities.
In standard mode and on regular Spectrums, if an interrupt is missed (the /INT line is released before the interrupt is accepted) then the interrupt is lost forever.
Extra titbits about timing from discord by AA
The copper counts according to the pixel currently being generated with (0,0) corresponding to the (0,0) position of the ula's 256x192 screen. You can adjust where vertical 0 is for the copper via nextreg but not horizontal position (yet?). Line interrupt & raster line position also use the copper's vertical coordinate.
The ula actually reads pixel and attribute data 12 pixels before they are displayed. So if the copper registers x=0, indicating pixel 0 is being generated, then the ula fetched that pixel/attr data during the previous 12 cycles.
The line interrupt for line=y occurs at line=y-1, x=256 iirc. Ie, the interrupt occurs just after the 256-pixel area has been drawn in the PREVIOUS line. That's to give maximum time to do things BEFORE the indicated line is drawn.
The vbi interrupt from the ula occurs where it does on the spectrum which I can't remember offhand. It's in the vertical blank time, probably at x=0 or 1. The 128K video frame as it a little later at x=1 because the 128K machines have an RC capacitor on the pcb on the /int line from the ula.
If you need more precision with interrupt timing, you can get the copper to generate interrupts via a nextreg.
Another Summary, with Core Versions Specified (from discord, by SevenFFF)
(This summary contains more exact information about the core versions).
There are three interrupt scenarios and they sometimes get mixed up and conflated:
1) Classic Spectrum/Z80 behaviour: mode 0 (not usable on a Speccy), mode 1 and mode 2. VBI triggers interrupts and that's fixed in hardware. No other interrupt sources. Needs a 257 byte table as the floating bus or external hardware can put random vectors on the bus.
2) Original Next behaviour. As classic spectrum, but VBL also triggers interrupts. Can turn VBI and VBL sources off separately, independently of whether interrupts are enabled or what mode they're in. Floating bus doesn't put random vectors on the bus, but hardware still can, so 257 byte table is recommended.
3) Next hardware mode 2. Can opt into this via nextreg. Multiple sources you can opt into (VBI, VBL, ESP UART Tx received, ESP UART Rx ready, Pi UART Tx received, Pi UART Rx ready, CTC timers elapsed (channels 7 and 8). Each source has their own specific guaranteed vector, so you can use vector tables as Zilog originally intended (yay!). Interrupt sources have priorities and higher priorities can interrupt lower ones. Must return from handlers with RETI so that the hardware can track the chain state. All this is available in 3.01.08 and above. Can also trigger some interrupts programmatically (3.01.10 and above). Fixed some bugs with interrupt status bits (3.02.00 and above)
(Here, VBI stands for vertical blank interval, one interrupt per frame. VBL is probably the line interrupt , once per line. It's not called VBL in the hardware docs. The docs call them UAT interrupt and line interrupt.)