GfxVGA programming guide
Outline #
The GfxVGA video display processor was developed as general purpose display system for use with the Y Ddraig computer. Designed to be capable of being used in many situations from text based OS, graphics user interfaces or as a games system.
The video card supports both 640x480 60hz 65536 colour display or 320x240 by doubling the pixel output. There is 2MB of Video RAM that is used for the bitmap mode as a framebuffer or used by the tile and sprite modes for storing data.
Display Modes #
There are 3 display modes supported. Text, bitmap and tile based modes.
Text Mode #
The following display modes are supported
- 80x30 character mode (8x16 font)
- 80x60 character mode (8x8 font)
- Hardware cursor
- hardware controlled text blinking
- 16 total colours from a user defined palette
- 16/8 background colours, only 8 colours available if blink mode is enabled, otherwise uses the full 16
- Custom 8x16 or 8x8 fonts
Palette support #
There is a 1024 item palette that is used by the bitmap, tiles, sprite and text modes that can each select between several palette banks within the full palette range.
Bitmap mode #
- 640x480 and 320x240 resolutions supported
- RGB-565 mode
- 8-bpp 256 palette mode
- Sprites can be used along with bitmap modes
- Framebuffer pointer to allow for double buffering
Tile Mode #
There are 4 tile layers that support either 16x16 or 8x8 tiles. Each tile uses 16 colours from a palette with index 0 always transparent. Tiles can use 8 different palettes for 128 colours (120 unique with transparent colours).
- Two 16x16 layers
- Two 8x8 layers
- Independent enable per layer
- 2048 tiles per layer
- Tile map are is 512x512 pixels
- 32x32 tiles for 16 pixel tiles
- 64x64 tiles for 8 pixel tiles
- Each tile layer supports independent X/Y per pixel scrolling
- Palette selected from 8 16-colour palettes
- Selectable palette bank per tile layer from 8 palette banks
- Flipping on both X and Y axis
- Layer priority is linear, layers 1-4 will draw in order
Sprites #
- 256 sprites available
- 48 visible sprites per line
- Flipping on X and Y axis
- Sprite priority handling between sprites and tile layers
- 16 colours per sprite, index 0 always transparent
- 16 palette banks for 256 sprite colours
- Sprites can be displayed on bitmap modes, limited to 320x240 resolution and screen space
Hardware accelerated drawing #
There are hardware accelerated drawing functions that work in 640x480 and 320x240 bitmap modes but only in RGB-565 format for now, not in palette mode.
- Filled rectangle
- Line drawing
- Fast horizontal
- Fast vertical
- Filled triangle
An extension to the drawing functions to allow some fast memory operations.
- Memory fill
- Linear memory copy
- 2D memory copy
Registers #
The register interface uses 16-bit accesses on even addresses. The CPU register address bus is split into a register group in bits 6:3 and a register index in bits 2:0, so each group contains up to 8 registers.
Unless otherwise noted:
- Registers are 16-bit
- Address values below are byte addresses
- Multi-word pointers are 20-bit values split into low and high registers
- Memory data/index registers commonly auto-increment after access
Register map #
| Range | Group | Purpose |
|---|---|---|
0x00-0x0E |
Control | Global control, status, interrupts, SRAM page |
0x10-0x1E |
Bitmap | Framebuffer base and line-scroll data pointer |
0x20-0x2E |
Text/Palette | Text RAM, cursor, palette RAM, palette bank control |
0x30-0x3E |
Drawing | Drawing engine command, colours, mode, base pointer |
0x40-0x4E |
Draw Params | Drawing engine parameter registers |
0x50-0x5E |
Tile Layer 1 | Tile layer 1 control, pointers, scrolling |
0x60-0x6E |
Tile Layer 2 | Tile layer 2 control, pointers, scrolling |
0x70-0x7E |
Tile Layer 3 | Tile layer 3 control, pointers, scrolling |
0x80-0x8E |
Tile Layer 4 | Tile layer 4 control, pointers, scrolling |
0x90-0x9E |
Sprites | Sprite data pointer and indexed sprite attribute access |
0xA0-0xAE |
Misc | Font RAM, pattern RAM, line interrupt |
0xB0-0xBE |
Cursor | Hardware cursor sprite control, position, data, colours |
0xF0-0xFE |
ID | Board version and board ID |
Control registers #
| Addr | Name | R/W | Description |
|---|---|---|---|
0x00 |
Status | R/W | Device status on read, interrupt clear bits on write |
0x02 |
Control | R/W | Global display mode and presentation control |
0x04 |
Interrupt control/status | R/W | Interrupt enable register |
0x06 |
SRAM page control | R/W | CPU-visible SRAM page select |
0x00 Status register #
Read returns current device status. Writing to this register clears interrupt flags through bits 4:2.
| b15 | b14 | b13 | b12 | b11 | b10 | b9 | b8 | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 |
| VBLANK | HBLANK | UNUSED | LINEINT | VBLANKINT | DRAWRDY | ||||||||||
DRAWRDY:1when the drawing engine is idle and can accept a commandVBLANKINT: vertical blank interrupt pendingLINEINT: line interrupt pendingHBLANK: currently in horizontal blankVBLANK: currently in vertical blank- Write
b4:b2to clear pending interrupt sources
0x02 Control register #
The control register selects the active display mode and several global presentation features.
| b15 | b14 | b13 | b12 | b11 | b10 | b9 | b8 | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 |
| UNUSED | TEXTOVL | SCANLINE | SPRITEEN | TEXT60 | BLINK | CURSOR | DEPTH | MODE | |||||||
Scanline mode only applies to 320x240 style output modes and can be used to simulate a CRT-like scanline effect.
| MODE | `000` Text mode `001` 320x240 bitmap mode `010` 640x480 bitmap mode `011` 320x240 tilemap mode Other values reserved |
|---|---|
| DEPTH | `000` RGB 5:6:5 `001` 8-bpp paletted Other values reserved |
| CURSOR | `1` enables the text cursor |
| BLINK | `1` enables text blink attributes |
| TEXT60 | `0` = 80x30 text mode, `1` = 80x60 text mode |
| SPRITEEN | `1` enables sprite display |
| TEXTOVL | `1` overlays the text layer on top of bitmap or tile output |
| SCANLINE | `00` no scanlines `01` black scanlines `10` grey scanlines `11` colour scanlines |
0x04 Interrupt control/status #
Controls which interrupt sources are enabled.
| b15 | b14 | b13 | b12 | b11 | b10 | b9 | b8 | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 |
| UNUSED | UNUSED | LINEEN | VBLEN | ||||||||||||
VBLEN: vertical blank interrupt enableLINEEN: line interrupt enableb2: currently unused in the interrupt generation path- Other bits are unused on write and read back as zero
0x06 SRAM page control #
Selects the CPU-visible SRAM page.
| b15 | b14 | b13 | b12 | b11 | b10 | b9 | b8 | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 |
| UNUSED | PAGE | ||||||||||||||
PAGE: SRAM page select
Bitmap registers #
These registers control the framebuffer base address and the line-scroll table base address.
| Addr | Name | R/W | Description |
|---|---|---|---|
0x10 |
Framebuffer base low | R/W | Low 16 bits of framebuffer pointer |
0x12 |
Framebuffer base high | R/W | High 4 bits of framebuffer pointer in b3:b0 |
0x18 |
Line-scroll base low | R/W | Low 16 bits of line-scroll pointer |
0x1A |
Line-scroll base high | R/W | High 4 bits of line-scroll pointer in b3:b0 |
Notes:
- Both pointers are 20-bit SRAM addresses
0x14,0x16,0x1C, and0x1Eare currently unused in this block
Text and palette registers #
These registers give indexed access to text RAM and palette RAM, plus cursor and palette bank configuration.
| Addr | Name | R/W | Description |
|---|---|---|---|
0x20 |
Text address | R/W | 13-bit text RAM index |
0x22 |
Text data | R/W | Text RAM data at current index, auto-increments index |
0x24 |
Cursor position | R/W | Cursor position in text memory |
0x26 |
Cursor size | R/W | Cursor start/end scanline control |
0x28 |
Palette address | R/W | 10-bit palette index |
0x2A |
Palette data | R/W | Palette entry at current index, write auto-increments index |
0x2C |
Palette control 0 | R/W | Text/bitmap palette bank control |
0x2E |
Palette control 1 | R/W | Tile/sprite palette bank control |
Text address and data #
0x20usesb12:b0for the text RAM index0x22accesses the current text RAM word- Writing
0x22increments the text index - Reading
0x22also increments the text index
Cursor registers #
The register block exposes:
0x24cursor position0x26cursor size
The reset value for cursor size is 0x0E0D.
0x24 cursor position:
| b15 | b14 | b13 | b12 | b11 | b10 | b9 | b8 | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 |
| CURSOR Y | CURSOR X | ||||||||||||||
0x26 cursor size:
| b15 | b14 | b13 | b12 | b11 | b10 | b9 | b8 | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 |
| UNUSED | END | UNUSED | START | ||||||||||||
Current implementation in the text generator decodes:
cursor_pos[7:0]: cursor X character positioncursor_pos[15:8]: cursor Y character positioncursor_size[3:0]: cursor start scanlinecursor_size[11:8]: cursor end scanline
With the reset value 0x0E0D, the default cursor spans scanlines 13 through 14.
Palette address and data #
0x28usesb9:b0for the palette index0x2Aaccesses one 16-bit palette entry- Writing
0x2Aincrements the palette index - Reads from
0x2Ause the current palette index without incrementing it
Palette control registers #
These registers are consumed by the display pipeline as follows:
0x2C palette control 0:
| b15 | b14 | b13 | b12 | b11 | b10 | b9 | b8 | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 |
| UNUSED | TEXT PAL BANK | BITMAP PAL BANK | |||||||||||||
0x2E palette control 1:
| b15 | b14 | b13 | b12 | b11 | b10 | b9 | b8 | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 |
| UNUSED | SPR | TILE4 | TILE3 | TILE2 | TILE1 | ||||||||||
TEXT PAL BANK: text palette bank selectBITMAP PAL BANK: bitmap palette bank selectTILE1..TILE4: tile layer palette bank selectsSPR: sprite palette bank select
Drawing registers #
The drawing engine is split into command/control registers and parameter registers.
Command/control block #
| Addr | Name | R/W | Description |
|---|---|---|---|
0x30 |
Draw command | R/W | Command code in b6:b0; write starts command processing |
0x32 |
Draw base low | R/W | Low 16 bits of drawing target base address |
0x34 |
Draw base high | R/W | High 4 bits of drawing target base address |
0x36 |
Draw colour 0 | R/W | Primary colour/pattern input |
0x38 |
Draw colour 1 | R/W | Secondary colour input |
0x3A |
Draw mode | R/W | Draw operation mode in b2:b0 |
0x3C |
Draw pattern | R/W | 16-bit pattern register |
Implemented command values:
0x00: none0x01: filled rectangle0x02: line0x03: vertical line0x04: horizontal line0x05: filled triangle0x06: linear memory copy0x07: 2D memory copy0x08: linear memory fill
Implemented draw modes:
0: solid1: XOR2: transparent3: reverse transparent
The current parameter usage is implementation-defined but stable enough to document.
Parameter block #
| Addr | Name | R/W | Description |
|---|---|---|---|
0x40 |
Draw param 0 | R/W | Command parameter 0 |
0x42 |
Draw param 1 | R/W | Command parameter 1 |
0x44 |
Draw param 2 | R/W | Command parameter 2 |
0x46 |
Draw param 3 | R/W | Command parameter 3 |
0x48 |
Draw param 4 | R/W | Command parameter 4 |
0x4A |
Draw param 5 | R/W | Command parameter 5 |
0x4C |
Draw param 6 | R/W | Command parameter 6 |
Current parameter usage by command #
| Command | Param 0 | Param 1 | Param 2 | Param 3 | Param 4 | Param 5 | Param 6 |
|---|---|---|---|---|---|---|---|
| Filled rectangle | X0 | Y0 | X1 | Y1 | unused | unused | unused |
| Line | X0 | Y0 | X1 | Y1 | unused | unused | unused |
| Horizontal line | X0 | Y0 | X1 | unused | unused | unused | unused |
| Vertical line | X0 | Y0 | unused | Y1 | unused | unused | unused |
| Filled triangle | X0 | Y0 | X1 | Y1 | X2 | Y2 | unused |
| Linear memory copy | source low | source high | dest low | dest high | word count | unused | unused |
| 2D memory copy | source low | source high | dest low | dest high | width in words | height in lines | stride in words, 0 = tightly packed |
| Linear memory fill | dest low | dest high | word count | fill value | unused | unused | unused |
Notes:
- Coordinates are clamped internally to the active display area before drawing starts
- Pointer pairs use a 20-bit address split as low 16 bits plus high 4 bits
- Rectangle coordinates are normalized internally so X0/X1 and Y0/Y1 may be supplied in either order
draw_patternis used by rectangle and line operations
Tile layer registers #
There are four identical tile layer register banks:
- Layer 1:
0x50-0x5E - Layer 2:
0x60-0x6E - Layer 3:
0x70-0x7E - Layer 4:
0x80-0x8E
Each bank contains the following registers:
| Offset | Name | R/W | Description |
|---|---|---|---|
+0x0 |
Tile control | R/W | Layer control bits in b2:b0 |
+0x2 |
Tile data low | R/W | Low 16 bits of tile graphics base pointer |
+0x4 |
Tile data high | R/W | High 4 bits of tile graphics base pointer |
+0x6 |
Tile map low | R/W | Low 16 bits of tile map base pointer |
+0x8 |
Tile map high | R/W | High 4 bits of tile map base pointer |
+0xA |
Scroll X | R/W | Horizontal scroll |
+0xC |
Scroll Y | R/W | Vertical scroll |
For each layer:
- Tile data and tile map pointers are 20-bit SRAM addresses
- Scroll registers are 16-bit values
- Control uses only
b2:b0
Tile control register:
| b15 | b14 | b13 | b12 | b11 | b10 | b9 | b8 | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 |
| UNUSED | LINE SCR | ENABLE | |||||||||||||
ENABLE: layer enableLINE SCR:00: disabled01: shared line-scroll table10: per-layer line-scroll table11: reserved
Sprite registers #
This block contains a sprite graphics base pointer plus indexed access to one sprite descriptor at a time.
| Addr | Name | R/W | Description |
|---|---|---|---|
0x90 |
Sprite data low | R/W | Low 16 bits of sprite graphics base pointer |
0x92 |
Sprite data high | R/W | High 4 bits of sprite graphics base pointer |
0x94 |
Sprite index | R/W | Selects sprite descriptor entry |
0x96 |
Sprite X position | R/W | 10-bit X position |
0x98 |
Sprite Y position | R/W | 10-bit Y position |
0x9A |
Sprite tile | R/W | 11-bit tile index |
0x9C |
Sprite attributes | R/W | Enable, priority, flip, palette |
Sprite index #
0x94usesb7:b0for the sprite number- Selecting a sprite triggers an internal descriptor fetch into a latch
Sprite attribute layout #
On write to 0x9C:
| b15 | b14 | b13 | b12 | b11 | b10 | b9 | b8 | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 |
| EN | UNUSED | PRIORITY | FLIPY | FLIPX | PALETTE | ||||||||||
EN: sprite enablePRIORITY: sprite priority fieldFLIPY: vertical flipFLIPX: horizontal flipPALETTE: palette select
Current sprite format and priority behaviour #
The current sprite pipeline uses:
- 16x16 pixels per sprite
- 4-bpp tile data format
- 16-colour per-sprite palettes with index
0transparent - up to 48 visible sprites per line
Within the sprite renderer:
- lower numeric sprite priority wins over higher numeric sprite priority
- if two sprites overlap, the lower priority value overwrites the higher one in the sprite line buffer
At final composition against tile layers:
- sprite priorities
0and1are above all tile layers - priorities
2and3are between tile layer 4 and tile layer 3 - priorities
4and5are between tile layer 3 and tile layer 2 - priorities
6and7are between tile layer 2 and tile layer 1 - priority
8is behind all tile layers - priorities
9to15are also treated as furthest back by the compositor
Hardware cursor registers #
This block controls the hardware cursor sprite overlay and its pattern RAM.
| Addr | Name | R/W | Description |
|---|---|---|---|
0xB0 |
Cursor control | R/W | b0 enables the hardware cursor |
0xB2 |
Cursor X | R/W | 10-bit cursor X position |
0xB4 |
Cursor Y | R/W | 10-bit cursor Y position |
0xB6 |
Cursor data address | R/W | 7-bit cursor pattern word address |
0xB8 |
Cursor data | W | Writes one 16-bit cursor pattern word and auto-increments address |
0xBA |
Cursor colour 1 | R/W | RGB565 cursor colour 1 |
0xBC |
Cursor colour 2 | R/W | RGB565 cursor colour 2 |
0xBE |
Cursor colour 3 | R/W | RGB565 cursor colour 3 |
Notes:
- Cursor X and Y use
b9:b0 - Cursor pattern address uses
b6:b0 - Writing
0xB8increments the cursor pattern address - The current register block does not provide readback for cursor pattern data, only for the address and colour/control registers
0xB0 cursor control:
| b15 | b14 | b13 | b12 | b11 | b10 | b9 | b8 | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 |
| UNUSED | ENABLE | ||||||||||||||
0xB2 cursor X and 0xB4 cursor Y:
| b15 | b14 | b13 | b12 | b11 | b10 | b9 | b8 | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 |
| UNUSED | POSITION | ||||||||||||||
0xB6 cursor data address:
| b15 | b14 | b13 | b12 | b11 | b10 | b9 | b8 | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 |
| UNUSED | ADDR | ||||||||||||||
Miscellaneous registers #
| Addr | Name | R/W | Description |
|---|---|---|---|
0xA0 |
Font address | R/W | 13-bit font RAM index |
0xA2 |
Font data | R/W | 8-bit font RAM data, auto-increments index |
0xA4 |
Pattern address | R/W | 10-bit pattern RAM index |
0xA6 |
Pattern data | R/W | 16-bit pattern RAM data, auto-increments index |
0xA8 |
Line interrupt Y | R/W | Scanline for line interrupt |
Details:
- Font data uses only
b7:b0 - Reading or writing font data auto-increments the font index
- Reading or writing pattern data auto-increments the pattern index
0xA8usesb9:b0for the interrupt line
Line interrupt timing #
The line interrupt compare runs from the VGA-domain timing path and is edge-qualified so the same line does not retrigger repeatedly.
Current behaviour:
- In bitmap and tilemap modes, the compare is performed against the logical 320x240 line number, derived from the VGA line number by dividing by 2
- In text mode, the compare is performed against the full VGA line number
- The compare happens around
hblank_start, using the upcoming line value from the timing pipeline - Vertical blank resets the one-shot tracking used to prevent duplicate triggers on the same line
Software should therefore treat the line interrupt value as:
- logical line coordinates in 320x240 bitmap/tile modes
- full 640x480 line coordinates in text mode
Identification registers #
| Addr | Name | R/W | Description |
|---|---|---|---|
0xFC |
Board version | Read | Returns major version in high byte and minor version in low byte |
0xFE |
Board ID | Read | Returns board type ID duplicated in both bytes |
For the current source:
- Board version =
1.0 - Board type ID =
0x13
Notes for software #
- Reads are pipelined in the register controller, so software should honour the bus handshake rather than assume a purely combinational register read
- Text, font, pattern, and some palette accesses use indexed data ports rather than flat address-mapped RAM windows
- Several registers are implemented here as raw control fields, while their detailed meaning is defined by the downstream rendering blocks
Bus access pattern #
The register file is handshake-based rather than purely timing-based.
Typical software access pattern:
- Present register address and data with the correct read/write direction.
- Assert the register request.
- Wait for register acknowledge.
- On reads, sample returned data when acknowledge is asserted.
- Deassert the request before starting the next access.
This matters most for:
- all reads, because they are pipelined through the register controller
- indexed text/font/pattern/palette accesses, where the address register and data register are separate operations