Oli's old stuff

Tinkering with retro and electronics

Feb 5, 2021 - 9 minute read - sinclair electronics retro hardware zx spectrum zxsprite

ZX-Sprite Introduction

The series

ZX-Sprite: An Introduction

Towards the backend of 2020 I started working on a Spectrum Next game; the game uses a couple of the cool features of Next - tilemaps and sprites. As a bit of fun, I started to adapt my emulator to support both of these; mostly because I’ve got into a bit of a nice workflow with this emulator; one that I can’t quite get from CSpect.

Whilst adding these early Next features, I also decided to add ULAplus support to the emulator to give me 64 colours.

ULAplus is implemented extremely sympathetically to the original hardware:

  • requires additional hardware support
  • it’s completely optional
  • works entirely using I/O requests

As such, it’s a peripheral device - but one that you need to drive a screen with in order to actually use it.

Whilst adding the ULAplus support the idea struck me - wouldn’t it be cool to be able to support the Spectrum Next’s sprites in the way that ULAplus does?

And thus, ZX-Sprite was born.

What is ZX-Sprite?

ZX-Sprite is a fantasy hardware add-on that ports a modified the Spectrum Next Sprite system to the original ZX Spectrum.

As we’re targeting the 48K and 128K ZX Spectrum hardware we have to make some minor adjustments to the Spectrum Next Sprite spec, notably around the colour depth used in the sprites.

DISCLAIMER

This is not endorsed by or associated with the Spectrum Next or any of its creators in any way at all.

Concepts

Like the Spectrum Next, the system revolves around the use of patterns, sprites and in the case of ULAplus - palettes.

A pattern is the image data for a sprite. It can be used by multiple sprites on the screen. A sprite pattern is a 16x16 pixel image that has a 4-bit colour depth. The colour data always refers to a palette entry, meaning all 16 original Spectrum colours are available, or any 16 colours from one of the 4 ULAplus palettes. ZX-Sprite provides support for 64 sprite patterns (although this may increase to 128 as the concept evolves).

A sprite is a collection of attributes laid out sequentially in the hardware’s RAM. Attributes are used to define the sprite; providing its position information and which pattern it is using. The current specification allows for 64 sprites, but this may also change to 128 as the concept evolves.

Sprites are rendered onto the sprite layer. This is currently an overlay to the standard ULA screen that includes the border regions. This means that the sprite layer is theoretically a 320x256 screen, although 320x240 is more common for HDMI displays.

Interface

The interface to ZX-Sprite is very similar to that of the Spectrum Next; we use 3 IO ports to upload data to the internal memory of the hardware.

The first port $303B is the SELECT or ‘slot’ port, writing to this port sets the internal SLOT register which is used by either the pattern or attribute ports.

The second port, $xx5B is the PATT port that is used to upload pattern data from the Spectrum to the internal hardware memory. The PATT port will use the currently selected SLOT; it then expects 128 bytes of data to be written to complete the full pattern. See the section on Sprite Patterns for more information.

The third port is $xx57 - the ATTR port. This is used to define the sprites and change their values at runtime.

Slot/Select

This is used in combination with the pattern/attribute interfaces to select the pattern or attribute to work on.

Bits Name Description
7 Control Enable to select control mode
6-0 S6-S0 Pattern / Sprite number to select

Control mode is new to ZX-Sprite and aims to provide some of the control functionality that is provided through the use of nextreg on the Spectrum Next.

When selecting a new slot, the internal data indexes used by sprite patterns or sprite attributes are reset to zero.

Sprite Patterns

Sprite patterns are a 16x16 pixel image with a 4-bit colour depth. The data is arranged top-to-bottom, left-to-right as 16 rows of 8 bytes; each byte contains data for two pixels. This makes the size of each sprite 128 bytes.

The value of each nibble is an index into the palette used by the sprite; thus 16 colours per sprite are possible. For the standard ULA palette, the normal colours are mapped as 0-7 and the bright colours are mapped 8-15.

An example of a pattern:

    .db $01,$19,$2A,$3B,$4C,$5D,$6E,$7F
    .db $01,$19,$2A,$3B,$4C,$5D,$6E,$7F
    .db $01,$19,$2A,$3B,$4C,$5D,$6E,$7F
    .db $01,$19,$2A,$3B,$4C,$5D,$6E,$7F
    .db $01,$19,$2A,$3B,$4C,$5D,$6E,$7F
    .db $01,$19,$2A,$3B,$4C,$5D,$6E,$7F
    .db $01,$19,$2A,$3B,$4C,$5D,$6E,$7F
    .db $01,$19,$2A,$3B,$4C,$5D,$6E,$7F
    .db $01,$19,$2A,$3B,$4C,$5D,$6E,$7F
    .db $01,$19,$2A,$3B,$4C,$5D,$6E,$7F
    .db $01,$19,$2A,$3B,$4C,$5D,$6E,$7F
    .db $01,$19,$2A,$3B,$4C,$5D,$6E,$7F
    .db $01,$19,$2A,$3B,$4C,$5D,$6E,$7F
    .db $01,$19,$2A,$3B,$4C,$5D,$6E,$7F
    .db $01,$19,$2A,$3B,$4C,$5D,$6E,$7F
    .db $01,$19,$2A,$3B,$4C,$5D,$6E,$7F
    .db $01,$19,$2A,$3B,$4C,$5D,$6E,$7F

Using the standard ULA colour palette this will produce a sprite with a colour gradient through each of the colours (including bright).

ULA colours rainbow

ZX-Sprite has an internal data index register that is incremented for each byte uploaded for a pattern. This register has the following rules:

  • reset to 0 when a new slot is selected
  • reset to 0 when the 128th byte of a pattern is written

When the data register rolls over to zero, it also increments the slot register, allowing for multiple sprite patterns to be uploaded with successive port writes.

The ULA colours are kinda ugly and won’t make for attractive sprites; so ZX-Sprite supports ULAplus palettes through use of the palette select bits in the attributes.

Sprites on the Spectrum Next can be defined with an 8-bit colour index, thus giving 256 possible colours. This makes little sense on the original Spectrum, so ZX-Sprite has no plans to include this.

Sprite Attributes

Sprites are defined as a set of attributes. At the time of writing, ZX-Sprite supports 4 attributes, but there are plans to extend this to include the optional 5th attribute similarly to the Spectrum Next. Each attribute is a single byte, but depending on its position it may contain bitpacked data.

The current attributes are as follows:

Position Pattern Description
0 X7 X6 X5 X4 X3 X2 X1 X0 The lower 8 bits of the X position
1 Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 The Y position
2 -- -- P1 P0 HF VF RR X8 The palette and flipping attributes.
3 VV -- N5 N4 N3 N2 N1 N0 The visibility and pattern attribute

ZX-Sprite has an internal data index register that is incremented for each attribute uploaded. This register has the following rules:

  • reset to 0 when a new slot is selected
  • reset to 0 when the 4th byte of an attribute is written

When the data register rolls over to zero, it also increments the slot register, allowing for multiple sprites to be modified with successive port writes.

It is likely that the 5th attribute that the Spectrum Next supports will be added to the system, allowing for relative sprites to be used.

Attribute 2

Sprite attribute #2 contains information about the palette index and flip/rotation behaviour of the sprite.

Bits Name Description
7-6 Reserved, set to 0
5-4 P1-P0 Palette index for the ULAplus CLUT. Set to 0 if not using ULAplus.
3 HF Flip the sprite horizontally
2 VF Flip the sprite vertically
1 RR Rotate the sprite clockwise 90 degrees
0 X8 The high bit of the 9-bit X value.

There are differences from the Spectrum Next attribute 2 here; notably bits 7 and 6 aren’t used. This is because only 4 palettes are possible when using ULAplus.

Attribute 3

Sprite attribute #3 controls the visibility of the sprite as well as the pattern it is using.

Bits Name Description
7 VV Visible - set to 1 to show the sprite
6 Reserved, set to 0
5-0 N5-N0 6 bit sprite pattern to use

The main difference between this attribute and the Spectrum Next is that we are currently limiting the attribute count to 4. If this changes then bit 6 will be used to enable the extended attribute.

Control Mode

The Spectrum Next has a host of nextreg registers to control its sprite system. ZX-Sprite achieves this by allowing the SELECT port to be put into control mode.

When enabled, Control Mode allows the use of the ATTR port interface to upload control attributes.

Control Slot ATTR value Description
$80 E-----TB Global feature control
$81 ----PPPP Transparency index; the next 4-bit value written to the ATTR port will be the palette index of the transparent colour of all sprites.

To exit control mode, a second SELECT command must be issued without the control bit set.

Note; there are plans to add clipping and offset windows to the global control register in the future.

Global Features

The value $80 written to the SELECT port is used to control the global features of ZX-Sprite.

The next ATTR written after this is selected will control the features enabled.

Bits Name Description
7 E Enable ZX-Sprite
6-2 Reserved, set to 0
1 T Enable global transparency
0 B Enable draw in border mode; this changes the co-ordinate system origin to begin at 0,0 of the full screen and plots sprites into the borders. When disabled, the co-ordinate system used is 0,0 of the ULA screen and the borders are not drawn in.

The default values after reset are that all features are disabled.

Transparency Index

ZX-Sprite supports a global transparency index; meaning the palette entry matching the index will be rendered as transparent (when the global transparency feature is enabled).

This is controlled by writing the value $81 to the SELECT port. The next attribute written controls the palette index to use. This is index 11 by default, meaning the ULA colour of BRIGHT MAGENTA is rendered transparent.

Status

Many of the features listed above are working in my own personal ZX Spectrum emulator neccy. This hasn’t been released to the public.

ZX-Sprite neccy demo

As I said at the start of this post, ZX-Sprite is fantasy hardware. It doesn’t exist for real - well, kinda.

In order for ZX-Sprite to exist for real, it needs two prerequisite hardware features - the ability to show the normal ULA screen with the sprites overlayed and ULAplus palette support.

I’ve been experimenting with Raspberry Pis, CPLDs and breadboards attached to the Spectrum edge connector to achieve a partially working real-world hardware system (albeit slow).

It lives!

I’ll talk about that in my next post.