This is the specification for the screen device of the Bedrock computer system.
This document is aimed at people who are implementing the Bedrock system from scratch. For people who are learning about or writing program for the Bedrock system, the screen device manual will generally be more useful.
Concepts
Screen palette
The screen has a 16 colour palette, with each colour in the palette indexed as colour zero through fifteen. Each colour in the palette is selected from a 12-bit RGB colour space. Every pixel on the screen is rendered using a palette index. Changing a colour in the palette will change the colour of all pixels that use that index.
The initial colour palette is determined by the implementation.
Screen layer
The screen contains two overlapping layers, called the foreground layer and the background layer. Each pixel on a layer is coloured using a palette index. When rendering the screen contents, each pixel of the screen is rendered as the foreground colour of that pixel if it is not colour zero, otherwise it is rendered as the background colour.
The initial colour of each pixel on the foregroud and background layer is colour zero.
Screen cursor
The screen cursor is a pair of signed 16 bit coordinates representing the position of a pixel on the screen. The horizontal coordinate increases rightwards, and the vertical coordinate increases downwards. The intial value of each coordinate is zero. The origin is the top-left pixel of the screen.
Sprite buffer
The sprite buffer is a 16 byte block of writeable memory with an associated pointer. The initial value of each byte is zero. The initial value of the pointer is zero.
Pushing a byte into the sprite buffer will write that byte to the address referenced by the pointer, and then will increment the pointer by 1, wrapping to zero after 15.
The sprite buffer is treated as a circular buffer that is split into two 8 byte planes by the pointer. The high plane is made up of the eight bytes starting from the address referenced by the pointer, and the low plane is made up of the remaining eight bytes.
Sprite data
A sprite is an 8x8 pixel square image. A 1-bit sprite is stored as eight bytes, and a 2-bit sprite is stored as sixteen bytes.
Sprites are read from the sprite buffer. Each plane of the sprite buffer contains 1 bit of data per sprite pixel. Each byte of a plane maps to a row of the sprite, ordered top to bottom, and each bit of a byte maps to a pixel in the row, ordered left to right, from highest bit to lowest.
A 1-bit sprite is drawn using the low plane of the sprite buffer, with each pixel corresponding with a 1-bit colour value.
A 2-bit sprite is drawn using both planes of the sprite buffer, with each pixel corresponding with a 2-bit colour value. The high plane determines the high bit of each colour value and the low plane defines the low bit.
Each pixel of a sprite is drawn using the selected colour that corresponds with the colour value of that pixel:
High | Low | Description |
---|---|---|
0 |
0 |
Drawn as selected colour 0 |
0 |
1 |
Drawn as selected colour 1 |
1 |
0 |
Drawn as selected colour 2 |
1 |
1 |
Drawn as selected colour 3 |
Selected colours
The selected colours are a set of four palette colours that are used to draw sprites to the screen. Each selected colour is a palette index. The initial value of each selected colour is zero.
Ports
Port | Name | Description | Read | Write |
---|---|---|---|---|
0x50 |
Horizontal coordinate | Horizontal cursor coordinate. | ✓ | ✓ |
0x51 |
grouped | grouped | ✓ | ✓ |
0x52 |
Vertical coordinate | Vertical cursor coordinate. | ✓ | ✓ |
0x53 |
grouped | grouped | ✓ | ✓ |
0x54 |
Screen width | Horizontal screen dimension. | ✓ | ✓ |
0x55 |
grouped | grouped | ✓ | ✓ |
0x56 |
Screen height | Vertical screen dimension. | ✓ | ✓ |
0x57 |
grouped | grouped | ✓ | ✓ |
0x58 |
Palette | Change the colour palette. | ✗ | ✓ |
0x59 |
grouped | grouped | ✗ | ✓ |
0x5A |
Selection | Select the sprite colours. | ✗ | ✓ |
0x5B |
grouped | grouped | ✗ | ✓ |
0x5C |
Sprite | Write to the sprite buffer. | ✗ | ✓ |
0x5D |
aliased | aliased | ✗ | ✓ |
0x5E |
Draw | Draw to the screen. | ✗ | ✓ |
0x5F |
Move | Move the screen cursor. | ✗ | ✓ |
Horizontal coordinate
Reading from this port group will return the horizontal coordinate of the screen cursor. Writing to this port group will set the coordinate to the value written.
Vertical coordinate
Reading from this port group will return the vertical coordinate of the screen cursor. Writing to this port group will set the coordinate to the value written.
Screen width
Reading from this port group will perform an atomic read, returning the width of the screen in pixels. Reading while no screen is available will return zero.
Writing to this port group will perform an atomic write, requesting on commit that the width of the screen be locked and changed to the value written.
Screen height
Reading from this port group will perform an atomic read, returning the height of the screen in pixels. Reading while no screen is available will return zero.
Writing to this port group will perform an atomic write, requesting on commit that the height of the screen be locked and changed to the value written.
Palette
Writing to this port group will perform an atomic write, changing a colour in the screen palette on commit.
The upper four bits of the value written represent the palette index that will be overwritten, and the remaining 4-bit groups represent the red, green, and blue values of the colour.
Bits | Description |
---|---|
0xF000 |
Palette index |
0x0F00 |
Red channel |
0x00F0 |
Green channel |
0x000F |
Blue channel |
Selection
Reading from this port will return a 16 bit value containing the four selected colours. Writing to this port will set the selected colours to the value written. Each group of four bits in the value read or written represents one of the selected colours:
Bits | Description |
---|---|
0xF000 |
Selected colour 0 |
0x0F00 |
Selected colour 1 |
0x00F0 |
Selected colour 2 |
0x000F |
Selected colour 3 |
Sprite
Writing to this port will push the byte written to the sprite buffer.
Draw
Writing to this port will perform a draw operation according to the byte written. The upper four bits determine the operation to be performed, as follows:
Value | Operation |
---|---|
0x0_ |
Set the colour of a pixel in the background layer. |
0x1_ |
Draw a 1-bit sprite to the background layer. |
0x2_ |
Fill the background layer with a solid colour. |
0x3_ |
Draw a 2-bit sprite to the background layer. |
0x4_ |
Draw a solid line to the background layer. |
0x5_ |
Draw a 1-bit textured line to the background layer. |
0x6_ |
Draw a solid rectangle to the background layer. |
0x7_ |
Draw a 1-bit textured rectangle to the background layer. |
0x8_ |
Set the colour of a pixel in the foreground layer. |
0x9_ |
Draw a 1-bit sprite to the foreground layer. |
0xA_ |
Fill the foreground layer with a solid colour. |
0xB_ |
Draw a 2-bit sprite to the foreground layer. |
0xC_ |
Draw a solid line to the foreground layer. |
0xD_ |
Draw a 1-bit textured line to the foreground layer. |
0xE_ |
Draw a solid rectangle to the foreground layer. |
0xF_ |
Draw a 1-bit textured rectangle to the foreground layer. |
If bit 0x10
of the byte written is unset, the lower four bits of the byte will represent the palette colour to use. Otherwise, the lower four bits will represent the transformations to apply to the sprite used by the operation, in the following order:
Bit | Name | Description |
---|---|---|
0x_1 |
Flip X | Flip sprite across vertical center-line. |
0x_2 |
Flip Y | Flip sprite across horizontal center-line. |
0x_4 |
Flip diagonal | Flip sprite across top-left bottom-right diagonal. |
0x_8 |
Transparent | Don’t draw sprite pixels that use sprite colour 0. |
The current cursor position is the current position of the screen cursor. The previous cursor position is the position of the screen cursor during the previous draw operation, or the origin if no draw operation has been performed.
When setting the colour of a pixel on a layer, the pixel on that layer at the current cursor position is changed to the given colour.
When filling a layer with a solid colour, each pixel on that layer is changed to the given colour.
When drawing a sprite to a layer, the sprite is read from the sprite buffer, then the given transformations are applied, and then each pixel of the sprite is drawn to that layer, with the top-left pixel of the sprite placed at the current cursor position.
When drawing a line to a layer, each pixel on the layer belonging to the shortest line that connects the previous and current cursor positions will be affected. Line pixels can connect diagonally or orthogonally. The algorithm chosen must be stable.
When drawing a rectangle to a layer, each pixel on the layer belonging to the smallest axis-aligned rectangle that contains both the previous and current cursor positions will be affected.
When drawing a solid line or rectangle, each pixel belonging to the line or rectangle will be changed to the given colour.
When drawing a textured line or rectangle, a 1-bit sprite is read from the sprite buffer, then the given transformations are applied, and then each pixel belonging to the line or rectangle will be drawn as the corresponding sprite pixel, as if the sprite were tiled outwards from the top-left corner of the screen.
Move
Writing to this port will move the screen cursor a number of pixels in a given direction according to the byte written. The upper two bits determine the direction to move, and the lower six bits determine the distance:
Bit | Name |
---|---|
0x80 |
Negative |
0x40 |
Vertical |
0x3F |
Distance |
If bit 0x40
is set, the vertical coordinate of the screen cursor will be modified, else the horizontal coordinate will be modified. If bit 0x80
is set, the distance will be subtracted from the coordinate, else the distance will be added.
Implementation notes
Double buffering
Double-buffering should be used to reduce flickering. Buffers should be flipped every time the system enters sleep mode. Palette changes should also be double-buffered in order to prevent the screen colours from updating separately from the image.
Fixed palette screens
For a two-colour screen with a fixed palette, every second palette index maps to the on colour and every other index maps to the off colour. For a three-colour screen, every fourth index maps instead to the grey colour. For a four-colour screen, the third and fourth index of every four map instead to the dim grey and bright grey colours.
Index | 2 colour | 3 colour | 4 colour |
---|---|---|---|
0,4,8,C |
Off | Off | Off |
1,5,9,D |
On | On | On |
2,6,A,E |
Off | Off | Dim |
3,7,B,F |
On | Grey | Bright |
Wake behaviour
This device will send a wake request to the system device when the width or height of the screen changes.