The ULA is the Spectrum video and input chip. The enhanced ULA adds extra video modes and features to the standard Spectrum.
ULA stands for "Uncommitted Logic Array" and refers to the manufacturing process involved. The chip itself is a custom chip.
Spectrum Video Mode
The standard Spectrum has only one video mode, with a resolution of 256x192 (not including the border) and 15 colours. This screen is further divided into 8x8 "attribute cells", so the attribute cell resolution is 32x24.
The ULA reads memory from Bank 5 or Bank 7 based on the setting at Memory Paging Control ($7FFD / 32765). If you haven't done any fancy messing about with the memory map, or you're using Spectrum 48k mode, then the screen memory will start at $4000.
There is one bit per pixel, so each byte represents 8 pixels (ie, one line of an attribute cell). Each screen line is stored in straightforward left-to-right order, so the 32 bytes from $4000 onwards represent all the pixels on the first line of the screen.
Unfortunately, while the columns of the screen are in straightforward order, the lines are not.
The 192 line screen is vertically divided into thirds, with each third containing 64 lines (or 8 attribute cells). These three thirds are stored sequentially in memory, but within each third, the order is not what you'd expect. You'd expect it'd store the first line of the first cell, the second line of the first cell.. up to the eighth line of the first cell, then the first line of the second cell. Instead, the sorting is inverted. So it stores the first line of the first cell, then the first line of the second cell, then the first line of the third cell, and so on.. up to the first line of the eighth cell, which is then followed by the second line of the first cell!
This means that getting the address of the start of a given line can be a tricky business. Fortunately, since the numbers involved are all powers of 2, it can be done by breaking the line number (0-191) into its bits.
Each 3rd is 64 lines, so the top two bits of the line number indicate which 3rd we're in, with the highest being %10 for 128 (%11 would be 192, off the bottom of the screen). Then, each cell is 8 lines, so bits 3-5 of the line number give the cell address, and the remaining bits give the line within that cell.
The thirds are stored in sequential order; each third contains 64 lines; and storing a line takes 32 bytes, meaning that the 3rd number is multiplied by 2048. Add $4000 for the start of the screen and that'll give the address of the start of the target third. Now, to get to the block for the correct line number. To store the top line of a single row of cells takes 32 bytes; but since all the top lines for 8 cells are stored together, there's actually 256 bytes (32*8) between lines. So the offset must be multiplied by 256 and added to the address. Then, to select the correct cell within that block, the cell number needs to be multiplied by 32. So the final 16-bit address is:
The five lowest bits of this value are then used to select between the 32 horizontal cells on that line, which is simply done by dividing the pixel address by 8.
As you can see from the above, pixel data is stored with 1-bit color in the pixel data memory. However, it is possible for the color to vary across the screen. The snag is that you can set only two colours within a single attribute cell - that is, an 8x8 area.
Color data is stored at $5800 onwards. Unlike the pixel data, it's stored in straightforward reading order, with one byte per attribute cell, for a total of 768 bytes. The byte represents:
|0-2||"Ink" color (color of 1 bits). From 0-7: black, blue, red, magenta, green, cyan, yellow, white. Note that ULAPlus (see below) allows these colors to be redefined.|
|3-5||"Paper" color (color of 0 bits).|
|6||Bright flag (toggles brighter version of both colors). If ULAPlus is enabled, bits 6-7 instead select between the 4 available palettes.|
|7||Flash flag (toggles regular alternation of ink and paper colors)|
Because you can have only one color value per 8x8 cell, some older games exhibited "color clash" in which an object or part of an object would appear the wrong color because it needed to be drawn inside an 8x8 cell with another object of a different color.
Enhanced video modes
The Next adds a number of additional video modes to the standard ULA.
Timex Sinclar Double Buffering
Writing %001 to the lower 3 bits of Timex Sinclair Video Mode Control ($xxFF / 255) will change the accessed base screen address to $6000 instead of $4000. Writing %000 restores the normal base screen address. This allows this area of memory to be used for a "double buffer" for smooth frame transitions. Note however that the Spectrum 128k's bank switching also allows double buffering (see Memory Map) which can be combined with this.
Timex Sinclair Hi-Res Mode
Writing %110 to the lower 3 bits of Timex Sinclair Video Mode Control ($xxFF / 255) will change the screen resolution to 512x192, doubling the X resolution. This still uses the Double Buffer structure of one set of screen data at $4000 and another at $6000, but now columns are alternately read from the two buffers to account for the higher resolution. In addition, attributes are disabled: this mode supports only two colors. Which they are can be set by writing bits 3-5 of Timex Sinclair Video Mode Control ($xxFF / 255).
Timex Sinclair Hi-Color Mode
Writing %010 to the lower 3 bits of Timex Sinclair Video Mode Control ($xxFF / 255) will disable the standard attribute area. Instead, the attribute area is set to begin at $6000 and to have the same interleaved structure as the pixel data. Each attribute byte is now applied to only one line of each cell, rather than the whole cell. The storage structure matches that of the pixel data (including the weird interleaving). This means that the areas of color clash are now limited to 8x1 blocks instead of 8x8 blocks.
Radastanian Mode, named after its implementor's username, is from the ZXUno system. It is enabled as on the ZXUno by writing $40 to ($FC3B) and then %00000011 to ($FD3B). It allows 16 colors anywhere on the screen at the cost of halving the horizontal resolution to 128x192.
Documentation on Radastanian mode is not clear but it appears as follows: the screen is structured in a similar way to timex hi-res mode, with alternating columns read from the two areas of the screen bank. However, each pixel is assigned 4 bits instead of 1. Thus a single byte that would normally cover 8 1-bit pixels is replaced with 2 bytes with 4 bits per "pixel". Because of the reduced resolution, each "pixel" is actually drawn as two pixels in the standard resolution.
Radastanian mode must be used together with ULAplus and the values are 4-bit ULAplus palette indices.
ULAPlus allows 64 colors on screen at once via re-purposing the FLASH and BRIGHT bits as extra color bits. It also allows these colors to be selected from a palette of 256. It is controlled via ($BF3B) and ($FF3B). Note that ULAPlus allows 64 colors to exist screen but does not, on its own, remove the restrictions on attribute cells.
ULAPlus is enabled by writing %0100000 to ($BF3B), then %00000001 to ($FF3B). Writing %00000011 to $FF3B will set the screen to 256 shades of grey instead.
Once this is done, colors are configured by writing the color number to configure, 0-63, to ($BF3B), then the color setting %GGGRRRBB to ($FF3B).
When ULAPlus is enabled color numbers taken from the other ULA modes are mapped to the palette. The 64-color ULAPlus palette is divided as follows:
|ULAplus palette range||ULA palette setting|
|0-7||INK colors 0-7|
|8-15||PAPER colors 0-7|
|16-23||INK colors 0-7 with BRIGHT set|
|24-31||PAPER colors 0-7 with BRIGHT set|
|32-39||INK colors 0-7 with FLASH set|
|40-47||PAPER colors 0-7 with FLASH set|
|48-55||INK colors 0-7 with BRIGHT and FLASH set|
|56-63||PAPER colors 0-7 with BRIGHT and FLASH set|