Display List Interrupts
Note: This is an advanced topic.
Display list interrupts (normally called DLI) are a way to modify display registers at certain vertical positions on the screen.
What Are DLIs?
DLIs allow you to change display hardware registers during screen rendering, enabling effects that would otherwise be impossible with a single set of register values.
Uses for DLIs
You can use DLIs to:
- Display more colors in the image - By changing color registers (registers from $D012 to $D01A)
- Split Player/Missile graphics - Move players/missiles to different horizontal positions (registers from $D000 to D007)
- Change scrolling position - Modify screen scrolling during display
- Change screen width - Adjust screen width mid-frame
- Modify P/M width - Change Player/Missile width settings
- Create color gradients - Change colors line-by-line for gradient effects
FORGE DLI Support
FORGE allows you to specify one or more DLI routines, activate one or deactivate all DLI by using the DLI statement.
Defining a DLI
DLI SET name = op1, op2, ... / DLIS.
Setups a new DLI with the given name and performing the op operations.
Each operation is of the form:
- data
INTOaddress - data
WSYNCINTOaddress
Where:
- data is one constant byte or the name of a
DATA BYTEarray - address is a memory location to modify
Array-Based DLIs
If data is a DATA array, the first element (at index 0) will be used at the first line with DLI active in the screen, the second element at the second active line, etc.
WSYNC
The WSYNC word advances one line in the display area (this is done by writing to the WSYNC ANTIC register), so the value is set in the next screen line. You can put the WSYNC word multiple times to advance more than one line. This allows one DLI to modify multiple lines at the screen.
Multiple INTO Operations
Multiple INTO words can be used to write more than one register with the same value.
Abbreviations
INTOcan be abbreviated toI.WSYNCcan be abbreviated toW.
Important Notes
- You can specify any number of operations, but as each one takes some time you could see display artifacts if you use too many.
- By defining a DLI you are simply giving it a name, you need to activate the DLI afterwards.
- You can split a DLI definition over multiple lines, just like
DATAby ending a line with a comma and starting the next line withDLI =
Enabling a DLI
DLI name / DL.
This statement enables the DLI with the given name, the DLI must be defined before in the program.
This setups the OS DLI pointer to the named DLI and activates the interrupt bit in the display processor (the ANTIC chip), but does not activate on which lines the DLI must be called.
To define on which lines the DLI is active you must modify the Display List, see the examples below.
Custom Machine Code DLIs
You can also pass the name of a DATA BYTE array with a custom machine language routine to the DLI statement, the routine must begin with a PHA and end with PLA and RTI.
Disabling a DLI
DLI / DL.
This statement simply disables the DLI, returning the display to the original state.
Display List Modification
To activate DLIs on specific screen lines, you must modify the Display List. The Display List address is stored at memory location 560 (DPEEK(560)).
To enable a DLI on a specific line, you need to set bit 7 (add 128) to the display list instruction byte for that line.
Example:
' Enable DLI on line 11 (offset 16 in display list) POKE DPEEK(560) + 16, 130 ' 2 + 128 = 130
Examples
Example 1: Simple Background Color Change
This is the most basic example of a DLI that simply changes the background color at the middle of the screen:
' Define the DLI: set background color to $24 = dark red. DLI SET d1 = $24 INTO $D01A ' Setups screen GRAPHICS 0 ' Alter the Display List, adds a DLI at line 11 on the screen POKE DPEEK(560) + 16, 130 ' Activate DLI DLI d1 ' Wait for any key ? "Press a Key" : GET K ' Disable the DLI DLI
Example 2: Multiple Color Changes
The next example shows how you can use a DLI to change multiple values in the screen:
' An array with color values DATA Colors() BYTE = $24,$46,$68 ' Define the DLI: set background color from the Color() array ' and text back color with value $8A in the same line and then ' the black in to the next line. DLI SET d2 = Colors INTO $D01A, DLI = $8A INTO $D018, DLI = $00 WSYNC INTO $D018 ' Setups screen GRAPHICS 0 ' Adds DLI at three lines: POKE DPEEK(560) + 13, 130 POKE DPEEK(560) + 16, 130 POKE DPEEK(560) + 19, 130 ' Activate DLI DLI d2 ' Wait for any key ? "Press a Key" : GET K ' Disable the DLI DLI
Example 3: Player/Missile Movement
The final example shows how you can move multiple P/M using one DLI:
' Player shapes, positions and colors DATA p1() BYTE = $E7,$81,$81,$E7 DATA p2() BYTE = $18,$3C,$3C,$18 DATA pos() BYTE = $40,$60,$80,$A0 DATA c1() BYTE = $28,$88,$C8,$08 DATA c2() BYTE = $2E,$80,$CE,$06 ' Our DLI writes the position and colors to Player 1 and Player 2 DLI SET d3 = pos INTO $D000 INTO $D001, DLI = c1 INTO $D012, c2 INTO $D013 GRAPHICS 0 : PMGRAPHICS 2 ' Setup our 4 DLI and Players FOR I = 8 TO 20 STEP 4 POKE DPEEK(560) + I, 130 MOVE ADR(p1), PMADR(0)+I*4+5,4 MOVE ADR(p2), PMADR(1)+I*4+5,4 NEXT ' Activate DLI DLI d3 ? "Press a Key" REPEAT PAUSE pos(0) = pos(0) + 2 pos(1) = pos(1) + 1 pos(2) = pos(2) - 1 pos(3) = pos(3) - 2 UNTIL KEY() DLI
Useful Registers
This is a table of some useful registers to change during a DLI:
| Address | Register |
|---|---|
| $D000 | Player 0 horizontal pos. |
| $D001 | Player 1 horizontal pos. |
| $D002 | Player 2 horizontal pos. |
| $D003 | Player 3 horizontal pos. |
| $D004 | Missile 0 horizontal pos. |
| $D005 | Missile 1 horizontal pos. |
| $D006 | Missile 2 horizontal pos. |
| $D007 | Missile 3 horizontal pos. |
| $D012 | Color of player/missile 0 |
| $D013 | Color of player/missile 1 |
| $D014 | Color of player/missile 2 |
| $D015 | Color of player/missile 3 |
| $D016 | Color register 0 |
| $D017 | Color register 1 |
| $D018 | Color register 2 |
| $D019 | Color register 3 |
| $D01A | Color of background |
Best Practices
- Keep DLI routines short - Long DLI routines can cause display artifacts
- Test thoroughly - DLIs can be timing-sensitive
- Disable when done - Always disable DLIs when your program exits
- Use arrays for multiple lines - Arrays make it easy to change multiple lines
- Document your DLIs - Note which lines they affect and what they do
Troubleshooting
DLI not activating:
- Check that you've modified the Display List correctly
- Verify the DLI is enabled with
DLI name - Ensure the DLI is defined before it's enabled
Display artifacts:
- Reduce the number of operations in the DLI
- Check timing - some operations may be too slow
- Verify register addresses are correct
Colors not changing:
- Check that you're writing to the correct color register
- Verify the graphics mode supports the color changes
- Ensure the DLI is actually being called (check Display List)
Related Topics
- Hardware Registers - Complete hardware register reference
- Statements - DLI statement syntax
- Low-Level Programming - Memory operations for DLI setup