An interrupt is a signal to the processor emitted by hardware or software indicating an event that needs immediate attention. An interrupt alerts the processor to a high-priority condition requiring the interruption of the current code the processor is executing. The processor responds by suspending its current activities, saving its state, and executing a function called an interrupt handler (or an interrupt service routine, ISR) to deal with the event. This interruption is temporary, and, after the interrupt handler finishes, the processor resumes normal activities. (Interrupt)

The Bally Arcade provides several interrelated registers that help the user acknowledge and respond to both hardware and software interrupts.

Vertical Blank

A CRT television image is drawn by a process known as raster scanning, whereby an electron beam sweeps across the screen horizontally, from left to right and top to bottom, creating stacked rows known as scanlines. At the end of each scanline, the beam must temporarily reset to the following scanline during an interval known as horizontal blank. When the full field of scanlines is drawn and the beam must travel from the bottom of the screen to the top, it does so during a period known as vertical blank. To draw a convincing television image without visible flicker, the electron beam performs its scan incredibly quickly—sixty times per second (NTSC).

The Bally Arcade provides a Vertical Blank Register (VERBL: output port $A) that allows the user to set the specific scanline where vertical blanking will begin. The Arcade outputs 102 vertical lines before blanking, so setting a value lower than 101 frees up RAM for scratchpad that would normally be used to display pixel data If the vertical blank register is set to 0, the entirety of RAM can be used for scratchpad.

The Vertical Blank register is set as follows:

VERBL Bit Function
1–7 Line number where vertical blanking begins
0 None (always 0)

Note that VERBL expects the value BLINE*2, where BLINE is the Bottom LINE of the vertical blank. For example, Astro Battle sets its vertical blank as follows:

        LD      A,$B4           ; 180 dec. (90 pixel lines times 2) for
        OUT     (VERBL),A       ; Port 10 - Vertical Blank [at scan]line

The value $B4 (or 180) is two times the desired vertical blanking target of line 90. The remaining 12 lines below vertical blank are reserved for scratchpad use throughout the game. (Astro Battle source code)

The screen area below the vertical blank line will display the frame color defined in bits 6 and 7 of the Horizontal Color Boundary (HORCB: output port $9).

Example: VERBL and HORCB

The screen above depicts three stacked rectangles set to three different palette entries. The horizontal color boundary is set to byte 30 (120 pixels), and VERBL is set to 102. Setting VERBL to the Bally Arcade's lowest line reveals the contents of scratchpad RAM (the multi-colored pixels) in the lower two lines of the screen. The frame color is also set to 2, but the lack of any blanking area leaves the frame 'hidden.'

User-Defined Interrupts

The Bally Arcade also allows the user to enable and respond to two software-controlled interrupts: screen interrupts at designated scanlines and interrupts for tracking light pen input.

Screen Interrupts

The screen interrupt synchronizes the software with the video system. If the screen interrupt enable bit is set, the Z80 will be interrupted when the video system completes scanning the line in the interrupt register. As a result, screen interrupts are especially useful for timing-dependent tasks, such as altering the color registers mid-screen, allowing a program to display more than eight colors onscreen simultaneously.

To enable and execute screen interrupts, several steps are necessary:

  • Enable screen interrupts and set its mode in INMOD ($E)
  • Designate the target interrupt scanline in INLIN ($F)+++
  • Set the interrupt handler address…
    • low byte in INFBK ($D)
    • high byte in register I
  • Set the interrupt mode with the IM opcode
  • Enable interrupts with the EI opcode

+++necessary only with multiple interrupts? screen interrupts seem to function fine when INLIN isn't set

Interrupt Enable and Mode (INMOD)

In order for the Z80 to accept an interrupt, one or two of the external interrupt enable bits must be set (output port $E). If bit 1 is set, light pen interrupts can occur. If bit 3 is set, screen interrupts can occur. If both bits are set, both interrupts can occur, and the screen interrupt has higher priority.

The interrupt mode bits determine what happens if an interrupt occurs when the Z80's interrupt enable flip-flop (EI) is not set. Each of the two interrupts may have a different mode.

  • In mode 0, the Z80 will continue to be interrupted until it finally enables interrupts and acknowledges the interrupt.
  • In mode 1, the interrupt will be discarded if it is not acknowledged by the next instruction after it occurred. In this mode, the software must be designed such that the system will not be executing certain Z80 instructions when the interrupt occurs. The opcodes of these instructions begin with CBH, DDH, EDH, and FDH.

The INMOD register contains the following interrupt control bits:

INMOD bit Function
3 Screen interrupt enable
2 Interrupt mode for screen interrupts
1 Light pen interrupt enable
0 Interrupt mode for light pen interrupts

Interrupt Line Register (INLIN)

If the screen interrupt is enabled in INMOD, the CPU will be interrupted when the display completes scanning the line which is contained in INLIN, the interrupt line register (output port $F). The INLIN register is defined as follows:

INLIN bit Function
1–7 Line number for screen interrupt
0 None (always 0)

Interrupt Feedback (INFBK)

When the CPU acknowledges an interrupt, it reads 8 bits of data from the data bus. It then uses this data as an instruction or an address. In the Bally Arcade, this data is determined by the contents of the interrupt feedback register (output port $D). In response to a screen interrupt, the contents of the interrupt feedback register are placed directly on the data bus. In response to a light pen interrupt, the lower four bits of the data bus are set to 0 and the upper four bits are the same as the corresponding bits of the feedback register.

The value set in INFBK defines the low byte of the 16-bit interrupt handler vector, i.e., the address where program control will begin executing when the screen interrupt triggers.

Interrupt Vector Register (I)

The interrupt vector register (I) provides the high byte of the 16-bit interrupt handler vector in interrupt mode 2. (See Zilog Z80)

Interrupt Mode (opcode IM)

The Z80's interrupt mode 2 is enabled using the instruction:

IM      2

This instructs the Z80 to use the indirect vector method, as explained below:

“Interrupt processing commences according to the interrupt method stipulated by the IM i instruction, where i=0, 1, or 2. If i=1, for direct method, the PC is loaded with 0038H. If i=0, for vectored method, the interrupting device has the opportunity to place the op-code for one byte . If i=2, for indirect vector method, the interrupting device must then place a byte. The Z80 then uses this byte where one of 128 interrupt vectors can be selected by the byte.”

Source: Wai-Kai Chen (2002). The Circuits and Filters Handbook, p. 1943.

Enable Interrupts (opcode EI)

Finally, for screen interrupts to occur, the Z80's internal interrupt flip-flop must be enabled by opcode EI.

Light Pen Interrupt

The light pen interrupt occurs when the light pen trigger is pressed and the video scan crosses the point on the screen where the light pen registers. The interrupt routine can read two registers to determine the position of the light pen. The line number is read from the vertical feedback register (input port $E). Bit 0 is ignored and bits 1–7 indicates the line number. The horizontal position of the light pen can be determined by reading input port $F and subtracting 8. The resultant value is the pixel number, 0–159.

Automatic Interrupts (ACTINT)

Test and clarify

The Bally Arcade system ROM provides an “automatic” interrupt service via the ACTINT system routine.

In the system ROM source, ACTINT is listed as follows:

        DI                      ; MAKE SURE INTERRUPT IS DISABLED
        PUSH    AF
        PUSH    BC
        PUSH    DE
        PUSH    HL
        IM      2
        LD      A,ITAB SHR 8
        LD      I,A
        LD      A,$C8
        OUT     (INLIN),A
        LD      A,ITAB & 0FFH
        OUT     (INFBK),A
        LD      C,$0F           ; USE CT0-3
        CALL    TIMEY           ; DEC CT0-3
        POP     HL
        POP     DE
        POP     BC
        POP     AF

ACTIN does the following:

  • Sets Z80 interrupt mode 2 (IM2)
  • Sets I register and INFBK to vector to ITAB on interrupt (which calls MACTIN)
  • Sets INLIN to $C8 (i.e., line 100)
  • Calls TIMEZ (updates game timer, blackout timer, and music processor)
  • Calls TIMEY (decrements counter-timers CT0–CT3)

Screen Interrupt Examples

Football sets up interrupts as follows (for clarity, only relevant code snippets are included):

         DW     L24D9     ; INTERRUPT ROUTINE
          LD     A,H
          LD     I,A       ; SET INTERRUPT RFG
          LD     A,L
          IM     2
          EI               ; START THE ACTION
         LD     A,70*2    ; NEW LINE INTERRUPT VALUE
         OUT    (INLIN),A

The interrupt table vector (INTTAB) is stored in HL (which can be indexed to access both routines). The high byte from INTTAB is transferred to A, then stored in the interrupt vector register (I). The low byte from INTTAB is then transferred to A, then stored in the Interrupt Feedback register (INFBK). Finally, the program sets interrupt mode to 2 (indirect vector method) and enables interrupts (EI). Consequently, on the screen interrupt triggered at line 70 (INLIN), the PC will jump to address <I><INFBK>.

Astro Battle uses a similar technique to load new color register values at four points down the screen:

; Setup for Interrupts
; --------------------
;   Initialize first of four screen interrupts to run once EI encountered
        LD      A,IRVEC1 >> 8   ; High Order Byte Address of Interrupt Vector
        LD      I,A             ; Load Interrupt Vector Register
        LD      A,IRVEC1 & $FF  ; Get Low Order Byte Address
        OUT     (INFBK),A       ; Port $0D, INterrupt FeedBacK Register
        LD      A,10*2          ; Screen Line 10 times 2 [below Score]
        OUT     (INLIN),A       ; Port $0E, INterrupt LINe Register
        LD      A,$08
        OUT     (INMOD),A       ; Port $0F, INterrupt MODe Register [Screen Ints. only]
; Finish Setup for Interrupts
; ---------------------------
        IM      2               ; Set Interrupt Mode 2 Condition
        EI                      ; Enable Interrupts