RP6502-VGA¶
Rumbledethumps Picocomputer 6502 Video Graphics Array.
Table of Contents
1. Introduction¶
The RP6502 Video Graphics Array is a Raspberry Pi Pico with RP6502-VGA firmware. Its primary data connection is to a RP6502-RIA over a 5-wire PIX bus. More than one VGA module can be put on a PIX bus. Note that all VGA modules share the same 64K of XRAM and only one module can generate frame numbers and vsync interrupts.
2. Video Programming¶
The design philosophy for the VGA system is to enable the full power of the Pi Pico while maintaining some 8-bit purity. To that end, two paths must be created. The VGA system must help you get the most value from 64K of extended memory (XRAM) and the VGA modes must inflict nostaligia. You may follow either or both paths.
The VGA system is built around the scanvideo library from Pi Pico Extras. All three planes are enabled with RGB555 color plus transparency. The mode 4 sprite system is from Pi Pico Playground. The programming system and all other modes are original work for the RP6502.
The RP6502 VGA system exposes per-scanline configuration of the video system to your 6502 application. At the broadest scope we have three planes. Each plane has two layers, a fill layer and a sprite layer. Your application can assign different fill and sprite modes to specific planes and scanlines. There’s plenty of fill rate to exceed the capabilities of any classic 8-bit system, but if you like to push the limits then you may see a half-blue screen indicating you went too far.
The built-in 8x8 and 8x16 fonts are available by using the special XRAM pointer $FFFF. Glyphs 0-127 are ASCII, glyphs 128-255 vary depending on the code page selected.
The built-in color palettes are accessed by using the special XRAM pointer $FFFF. 1-bit is black and white. 4 and 8-bits point to an ANSI color palette of 16 colors, followed by 216 colors (6x6x6), followed by 24 greys.
16-bit colors are built with the following bit logic. Setting the alpha bit will make the color opaque. The built-in ANSI color palette has the alpha bit set on all colors except color 0 black.
#define COLOR_FROM_RGB8(r,g,b) (((b>>3)<<11)|((g>>3)<<6)|(r>>3))
#define COLOR_FROM_RGB5(r,g,b) ((b<<11)|(g<<6)|(r))
#define COLOR_ALPHA_MASK (1u<<5)
Palette information is an array. 8bpp, 4bpp, and 1bpp modes use a palette. 16 bit per pixel modes don’t use indexed color and will ignore the palette. Palettes must be 16-bit aligned.
struct {
uint16_t color;
} palette[2^bits_per_pixel];
Programming the VGA device is done with PIX extended registers - XREGS. VGA is PIX device ID 1. Registers are 16 bit values addressed by $device:$channel:register. e.g. $1:0:0F
// Select a 320x240 canvas
result = xreg(1, 0, 0, 1); // or
result = xreg_vga_canvas(1);
// Program mode 3 for 4 bit color with
// its config registers at XRAM $FF00.
result = xreg(1, 0, 1, 3, 2, 0xFF00); // or
result = xreg_vga_mode(3, 2, 0xFF00);
Key Registers¶
Setting key registers may return a failure (-1) with errno EINVAL.
Address |
Name |
Description |
---|---|---|
$1:0:00 |
CANVAS |
|
$1:0:01 |
MODE |
|
Mode 0: Console¶
The console may be rendered on any canvas plane. ANSI color 0-black is transparent, which makes it easy to show text over a background image using planes. The console may be a partial screen, but the scanlines must be a multiple of the font height. 640 pixel wide canvases use an 8x16 font for 80 columns. 320 pixel wide canvases use an 8x8 font for 40 columns. Only one console may be visible, programming again will remove the previous console.
Address |
Name |
Description |
---|---|---|
$1:0:01 |
MODE |
0 - Console |
$1:0:02 |
PLANE |
0-2 to select which fill plane of scanlines to program. |
$1:0:03 |
BEGIN |
First scanline to program. BEGIN <= n < END |
$1:0:04 |
END |
End of scanlines to program. 0 means use canvas height (180-480). |
Mode 1: Character¶
Character modes have color information for each position on the screen. This is the mode you want for showing text in different colors.
Address |
Name |
Description |
---|---|---|
$1:0:01 |
MODE |
1 - Character |
$1:0:02 |
OPTIONS |
bit 3 - font size 0=8x8, 1=8x16
bit 2:0 - 0=1, 1=4r, 2=4, 3=8, or 4=16 bit color
|
$1:0:03 |
CONFIG |
Address of config structure in XRAM. |
$1:0:04 |
PLANE |
0-2 to select which fill plane of scanlines to program. |
$1:0:05 |
BEGIN |
First scanline to program. BEGIN <= n < END |
$1:0:06 |
END |
End of scanlines to program. 0 means use canvas height (180-480). |
Config structure may be updated without reprogramming scanlines.
struct {
bool x_wrap;
bool y_wrap;
int16_t x_px;
int16_t y_px;
int16_t width_chars;
int16_t height_chars;
uint16_t data_ptr;
uint16_t palette_ptr;
uint16_t font_ptr;
} config;
Data is encoded based on the color bit depth selected.
// 2-color, 1-bit
struct {
uint8_t glyph_code;
} data[width_chars * height_chars];
// 16-color reversed index, 4-bit
struct {
uint8_t glyph_code;
uint8_t fg_bg_index;
} data[width_chars * height_chars];
// 16-color, 4-bit
struct {
uint8_t glyph_code;
uint8_t bg_fg_index;
} data[width_chars * height_chars];
// 256-color, 8-bit
struct {
uint8_t glyph_code;
uint8_t fg_index;
uint8_t bg_index;
} data[width_chars * height_chars];
// 32768-color, 16-bit (no palette)
struct {
uint8_t glyph_code;
uint8_t attributes; // user defined, ignored by VGA
uint16_t fg_color;
uint16_t bg_color;
} data[width_chars * height_chars];
Fonts are encoded in wide format. The first 256 bytes are the first row of each of the 256 glyphs.
struct {
struct {
uint8_t col[256];
} row[height];
} font;
Mode 2: Tile¶
Tile modes have color information encoded in the tile bitmap. This is the mode you want for showing a video game playfield. Hi-res canvases (640x480 and 640x360) support one plane of 1-bit color. Standard canvases (320x240 and 328x180) support two planes of any option.
Address |
Name |
Description |
---|---|---|
$1:0:01 |
MODE |
2 - Tile |
$1:0:02 |
OPTIONS |
bit 3 - 0=8x8, 1=16x16
bit 2:0 - 0=1, 1=2, 2=4, or 3=8 bit color
|
$1:0:03 |
CONFIG |
Address of config structure in XRAM. |
$1:0:04 |
PLANE |
0-2 to select which fill plane of scanlines to program. |
$1:0:05 |
BEGIN |
First scanline to program. BEGIN <= n < END |
$1:0:06 |
END |
End of scanlines to program. 0 means use canvas height (180-480). |
Config structure may be updated without reprogramming scanlines.
struct {
bool x_wrap;
bool y_wrap;
int16_t x_px;
int16_t y_px;
int16_t width_tiles;
int16_t height_tiles;
uint16_t data_ptr;
uint16_t palette_ptr;
uint16_t tile_ptr;
} config;
Data is a matrix of tile ids with 0,0 at the top left.
struct {
uint8_t tile_id;
} data[width_tiles * height_tiles];
Tiles are encoded in “tall” bitmap format.
// 8x8 tiles
struct {
struct {
uint8_t cols[bpp];
} rows[8];
} tile[up_to_256];
// 16x16 tiles
struct {
struct {
uint8_t cols[2*bpp];
} rows[16];
} tile[up_to_256];
Mode 3: Bitmap¶
Every pixel can be its own color. 64K XRAM limits the full screen color depth. Monochrome at 640x480, 16 colors at 320x240, 256 colors for 320x180 (16:9).
Address |
Name |
Description |
---|---|---|
$1:0:01 |
MODE |
3 - Bitmap |
$1:0:02 |
OPTIONS |
bit 3 - reverse bit order
bit 2:0 - 0=1, 1=2, 2=4, 3=8, or 4=16 bit color
|
$1:0:03 |
CONFIG |
Address of config structure in XRAM. |
$1:0:04 |
PLANE |
0-2 to select which fill plane of scanlines to program. |
$1:0:05 |
BEGIN |
First scanline to program. BEGIN <= n < END |
$1:0:06 |
END |
End of scanlines to program. 0 means use canvas height (180-480). |
Config structure may be updated without reprogramming scanlines.
struct {
bool x_wrap;
bool y_wrap;
int16_t x_px;
int16_t y_px;
int16_t width_px;
int16_t height_px;
uint16_t data_ptr;
uint16_t palette_ptr;
} config;
Data is the color information packed down to the bit level. 16-bit color encodes the color directly as data. 1, 4, and 8 bit color encodes a palette index as data.
Bit order is traditionally done so that left and right bit shift operations match pixel movement on screen. The reverse bits option change the bit order of 1 and 4 bit modes so bit-level manipulation code is slightly faster and smaller.
Data for 16 bit color must be 16 bit aligned.
struct {
struct {
uint8_t cols[(width_px * bit_depth + 7) / 8];
} rows[height_px];
} data;
Mode 4: Sprite¶
Sprites may be drawn over each fill plane. This is the 16-bit sprite system from the Pi Pico Playground. Lower bit depths are planned for a different mode.
WARNING! Slightly experimental! It is unknown how well the structure data is validated. Please submit a reproducable test program if you encounter a VGA system lockup.
Address |
Name |
Description |
---|---|---|
$1:0:01 |
MODE |
4 - Sprite |
$1:0:02 |
OPTIONS |
bit 1 - affine
|
$1:0:03 |
CONFIG |
Address of config array in XRAM.
|
$1:0:04 |
LENGTH |
Length of config array array in XRAM. |
$1:0:05 |
PLANE |
0-2 to select which sprite plane of scanlines to program. |
$1:0:06 |
BEGIN |
First scanline to program. BEGIN <= n < END |
$1:0:07 |
END |
End of scanlines to program. 0 means use canvas height (180-480). |
Unused sprites should be moved off screen. Non-affine sprites use this config structure.
struct {
int16_t x_pos_px;
int16_t y_pos_px;
uint16_t xram_sprite_ptr;
uint8_t log_size;
bool has_opacity_metadata;
} config[LENGTH];
Affine sprites apply a 3x3 matrix transform. These are slower than plain sprites. Only the first two rows of the matrix is useful, which is why there’s only six transform values. These are in signed 8.8 fixed point format.
struct {
int16_t transform[6];
int16_t x_pos_px;
int16_t y_pos_px;
uint16_t xram_sprite_ptr;
uint8_t log_size;
bool has_opacity_metadata;
} config[LENGTH];
Sprite image data is an array of 16 bit colors.
struct {
struct {
uint16_t color[2^log_size];
} rows[2^log_size];
} sprite;
Control Channel $F¶
These registers are managed by the RIA. Do not distribute applications that set these.
Address |
Name |
Description |
---|---|---|
$1:F:00 |
DISPLAY |
|
$1:F:01 |
CODEPAGE |
Set code page for built-in font. |
$1:F:02 |
UART |
Set baud rate. Reserved, not implemented. |
$1:F:03 |
UART_TX |
Alternate path for UART Tx when using backchannel. |
$1:F:04 |
BACKCHAN |
|
3. Backchannel¶
Because the PIX bus is unidirectional, it can’t be used for sending data from the VGA system back to the RIA. Using the UART Rx path is undesirable since there would be framing overhead or unusable control characters. Since there is a lot of unused bandwidth on the PIX bus, which is only used when the 6502 is writing to XRAM, it can be used for the UART Tx path allowing the UART Tx pin to switch directions.
This is not interesting to the 6502 programmer as it happens automatically. RIA Kernel developers can extend its usefulness. The backchannel is simply a UART implemented in PIO so it sends 8-bit values.
Values 0x00 to 0x7F are used to send a version string as ASCII terminated with a 0x0D or 0x0A. This must be sent immediately after the backchannel enable message is received for it to be displayed as part of the boot message. It may be updated any time after that and inspected with the STATUS CLI command, but currently there is no reason to do so.
When bit 0x80 is set, the 0x70 bits indicate the command type, and the 0x0F bits are a scalar for the command.
0x80 VSYNC - The scalar will increment and be used for the LSB of the RIA_VSYNC register.
0x90 OP_ACK - Some XREG locations are triggers for remote calls which may fail or take time to complete. This acknowledges a successful completion.
0xA0 OP_NAK - This acknowledges a failure.
4. Terminal¶
The RP6502 VGA system includes a color ANSI terminal attached as the console.
C0 control codes¶
^ |
C0 |
Abbr |
Name |
Effect |
---|---|---|---|---|
^H |
0x08 |
BS |
Backspace |
Move cursor left. |
^I |
0x09 |
HT |
Tab |
Move cursor right to multiple of 8 column. |
^J |
0x0A |
LF |
Line Feed |
Move to next line. |
^L |
0x0C |
FF |
Form Feed |
Clear screen and move cursor to top left. |
^M |
0x0D |
CR |
Carriage Return |
Move cursor to first column. |
^[ |
0x1B |
ESC |
Escape |
Start an escape sequence. |
Fe Escape Sequences¶
Code |
C1 |
Abbr |
Name |
Effect |
---|---|---|---|---|
ESC [ |
0x9B |
CSI |
Control Sequence Inducer |
Begins most of the interesting sequences. |
CSI Sequences¶
Missing numbers are treated as 0. Some functions, like cursor movement, treat 0 as 1 to be useful without parameters.
Code |
Abbr |
Name |
Effect |
---|---|---|---|
CSI n C |
CUF |
Cursor Forward |
Move the cursor n cells right. |
CSI n D |
CUB |
Cursor Back |
Move the cursor n cells left. |
CSI n P |
DCH |
Delete Character |
Delete n cells, move line left. |
CSI n m |
SGR |
Select Graphic Rendition |
Selects colors and styles. |
SGR Parameters¶
Multiple parameters may be sent separated by semicolons. Reset is performed if no codes (CSI m).
n |
Name |
Effect |
---|---|---|
0 |
Reset or normal |
White (7) foreground, black (0) background. |
1 |
Bold intensity |
Brighter foreground colors. Colors 0-7 brightened. |
22 |
Normal intensity |
Normal foreground colors. Colors 8-15 dimmed. |
30-37 |
Set foreground color |
Colors 0-7 |
38 |
Set foreground color |
Followed by 1 or 5;n or 2;r;g;b or 2::r:g:b |
39 |
Default foreground color |
Color 7 white. |
40-47 |
Set background color |
Colors 0-7 |
48 |
Set background color |
Followed by 1 or 5;n or 2;r;g;b or 2::r:g:b |
49 |
Default background color |
Color 0 transparent black. |
90-97 |
Set bright foreground color |
Colors 8-15 |
100-107 |
Set bright background color |
Colors 8-15 |