Sprite Status/Slot Select
|ShortDesc||Sets active sprite-attribute index and pattern-slot index, reads sprite status.|
|Bit Mask||%0011 0000 0011 1011 ??|
Used to select the sprite index/slot (0..63 for pattern slots and 0..127 for sprite attribute slots) used by Sprite Attribute Upload ($xx57) and Sprite Pattern Upload ($xx5B). Once written, these ports may auto-increment the sprite index they are addressing. This auto-increment happens independently and so the two ports may end up addressing different sprites as a result. A write to this port will resynchronise them to the same sprite. There is also Sprite port-mirror Index Register ($34), which can be set to operate either independently or in link (bit 4 in Peripheral 4 Register ($09)) with values set on this port (details in NextReg $34 description).
Write to this port with bit 7 set adds an offset of 128 to the pattern upload index (aiming at the second half of 256 byte pattern slot 0..63).
When read, returns sprite status information as follows:
|1||Maximum sprites per line flag.
Set to 1 when sprite renderer ran out of time when preparing next scanline. Reading the port will reset it to 0.
Set to 1 when non transparent pixels of any 2 sprites overlap during rendering scanline. Reading the port will reset it to 0.
Sprite Engine internals information
Sprite renderer is able to draw roughly about 1600..1800 pixels per line (exact amount depends on the video mode timing, slower modes like 50Hz will give renderer more time per line, HDMI 60Hz mode is the most demanding one, allowing only about 100,6 sprites visible per line). In practice at least 100 non-scaled 16x16 sprites should be always rendered without any issue. When up-scaled sprites are used, the rendering time may get exhausted sooner (then bit 1 "maximum sprites" will get set, and rendering is aborted unfinished with some sprite graphics (of sprites defined later in the list) missing in final result). Sprites partially crossing left-boundary (screen border or clip window) will use the pixel bandwidth in the same way as if the invisible part of sprite was actually drawn. Sprites partially crossing right boundary terminate drawing as soon as boundary is reached, saving the pixel bandwidth for later sprites.
The rendering does proceed through list of sprites from sprite 0 to sprite 127, preparing sprite graphics for *next* scanline, i.e. when ULA pixel area is drawing line Y=14 (raster line register reads 14), the sprite graphics for line 14 was prepared during line 13. Thus "maximum" and "collision" flags read at the end of scanline 13 (start of scanline 14) contains already results of what is visible as line 14 on screen.
The attributes of particular sprite are read in single 28MHz cycle when the sprite rendering starts, i.e. attributes of sprite 0 are read somewhere around end of previous scanline (after pixel at sprite coordinate 319 is outputted), and as rendering progresses, attributes of sprite 127 are read somewhere toward end of scanline (or completely skipped in case the sprite renderer runs out of time due to large-scale sprites encountered early - the skipped sprites are also missing in the "collision" test, the "collision" flag is set only when particular colliding sprite pixels are rendered successfully and collision was "visible" on screen).
In case you are "multiplexing" sprites (changing sprite attributes during single frame to make particular sprite appear multiple times at screen at different lines), the sprite attributes for line Y must be updated when line Y-1 video output starts (for sprite 0 obviously slightly ahead of Y-1 scanline start, but not at start of Y-2 scanline, as that would modify sprite position already for scanline Y-1 result.
It is not possible to obtain from the sprite hardware the numbers or IDs of the sprites which overlapped in the "collision". The collision flag should thus be seen as initial broad phase collision detection (you can slightly narrow the detection by reading the flag at different scanlines, for example reading it at player's "top" line first to reset it, and at player's "bottom" line to ignore all sprite collisions happening above/below player).