Skip to content

(VERA 0.8) The Composer

Stephen Horn edited this page Mar 23, 2020 · 1 revision

This page refers to the VERA 0.8 and needs to be updated for emulator versions r37 and later.

The Composer

VRAM Address Description
$0F0000 Output mode and chroma toggle
$0F0001 Horizontal scale (HSCALE)
$0F0002 Vertical scale (VSCALE)
$0F0003 Border color palette index
$0F0004 Horizontal start of display area, bits 0-7
$0F0005 Horizontal end of display area, bits 0-7
$0F0006 Vertical start of display area, bits 0-7
$0F0007 Vertical end of display area, bits 0-7
$0F0008 Horizontal and vertical display area, various high bits
$0F0009 Scanline IRQ timing, bits 0-7
$0F000A Scanline IRQ timing, bit 8

What does the composer do?

The composer is responsible for outputting the results of all other video settings and memory to the display. It controls the video signal, coloration, image scaling, and display borders.

Display mode and color

The display mode and color are set via $0F0000. It follows the format %C0000BAA:

Field Description
AA Display mode. See the table "Display Modes", below.
B Chroma disable bit. If set, the NTSC composite mode will output a monochrome signal, which will improve image quality on monochrome displays.
C Current NTSC field. This is a read-only bit.

Display Modes

Mode Description
0 Video disabled
1 VGA mode
2 NTSC composite mode
3 RGB interlaced, composite sync (via VGA output)

NTSC field bit

The NTSC standard is an interlaced video signal, meaning it alternates between drawing the even-numbered lines ("field 0") of the display and the odd-numbered lines ("field 1"). This mean it's technically only drawing half of the lines each frame, even though it's operating at 60Hz. NTSC modes allow for clever color logic that can mimick transparency effects as well as create colors not otherwise possible for the display signal. Reading this bit, then, can be a signal to flip certain tiles or toggle sprites to create transparency effects or otherwise create more subtle color gradations than the VERA would otherwise be capable of in progressive display mode.

Horizontal and vertical scale (HSCALE and VSCALE)

The Composer treats a horizontal or vertical scale of 128 to mean "1x". This outputs square pixels at a 640x480 resolution. The emulator (and perhaps the final hardware as well) is only capable of scaling the display by nearest-neighbor approximation. It cannot output, for instance, 5:4 pixels at a SNES-like 512x448 resolution; the display is 640x480, and the scale parameters only influence the which pixel from the internal 640x480 logic that the composer maps to an output 640x480 pixel.

The easiest way to work with the scale parameters is to use factors of 2 to cleanly multiply the size of pixels by a factor of 2:

HSCALE Size factor Width
128 1x 640
64 2x 320
32 4x 160
16 8x 80
VSCALE Size factor Height
128 1x 480
64 2x 240
32 4x 120
16 8x 60

For a more advanced treatment of scale, think of some "screen position" X and Y, where X and Y are each fixed-point binary numbers; let's also say they're each 16 bits wide, with an 11-bit significand followed by a 7-bit mantissa. This means a value of "1.0" would be represented as $0080, which in decimal is 128; "0.5" is represented at $0040, or 64; "0.25" is $0020, or 32; and so on. The highest value this could represent is 1023.9921875, which is more than we need to represent 640 pixels.

As the composer outputs each pixel of a given line to the display, it increments its "screen position" X by the HSCALE. When deciding which pixel to output next, simply ignores the mantissa. At the end of the line, it similarly increments its "screen position" Y by VSCALE, and ignores the mantissa of the result when choosing which line to output next.

Borders and display area

The display area is where the VERA will output image data, starting with the coordinates (0, 0) in the upper-left of the display area, and ending at whatever (X,Y) is in the bottom-right corner of the display area. In effect, the composer pretends that anything outside of the display area no longer exists as part of the display, asides from filling in the space with whatever color is at the palette index specified in the "border color palette index" address, $0F0003.

The actual display area box is defined as 4 fields which are spread across 5 VRAM addresses:

Field Size in bits Description
HSTART 10 The horizontal screen coordinate where the display area should start
HSTOP 10 The horizontal screen coordinate where the display area should stop
VSTART 9 The vertical screen coordinate where the display area should start
VSTOP 9 The vertical screen coordinate where the display area should stop

The least significant byte (e.g. the lowest byte) of each of these values is contained in the VRAM addresses $0F0004-$0F0007, respectively. That leaves $0F0008, which is special. It follows the bit format %00DCBBAA:

Field Description
AA 2 most significant bits of HSTART
BB 2 most significant bits of HSTOP
C Most significant bit of VSTART
D Most significant bit of VSTOP

The video signal is always 640x480, regardless of any other settings, so if you wanted a display border that was 10 pixels wide on all edges, you would set the HSTART to 10, HSTOP to 630 (e.g. "640-10"), VSTART to 10, and VSTOP to 470 ("480-10").

That's $00A, $276, $00A, $1D6, respectively, so you would write $0A, $76, $0A, and $D6 to VRAM addresses $0F0004-$0F0007. That leaves $0F0008 with its special format, which becomes %00101000, or $28, specifying all the most-significant bits that didn't fit into the other addresses.

Try this example:

BASIC

10 VPOKE $0F,$04,$0A
20 VPOKE $0F,$05,$76
30 VPOKE $0F,$06,$0A
40 VPOKE $0F,$07,$D6
50 VPOKE $0F,$08,$28

6502

; Configure $9F23 to $0F0004, with an address auto-increment of 1
lda #$04
sta $9F20
stz $9F21
lda #$1F
sta $9F22
; Setup box
lda #$0A
sta $9F23
lda #$76
sta $9F23
lda #$0A
sta $9F23
lda #$D6
sta $9F23
lda #$28
sta $9F23

The display area is then the 620x460 pixel area not taken up by the border. A sprite placed at (0, 0) will be completely visible, located at the top-left corner of the display area and not overlapping with the border. If the sprite were moved left one pixel, it would become truncated because nothing is shown on top of the system border. The tilemaps also respect this. As previously stated, asides from having a system border color, this is analogous to reducing the display size to a bespoke resolution, and pretending that the border area no longer exists.

Line IRQs

For an introduction to interrupts, see the wiki entry on ASM programming and interrupts. BASIC programs are generally too slow to make use of line interrupts in a meaningful way.

In addition to the VBLANK interrupt that can be checked by reading $9F27 in the system memory, the VERA can also fire an interrupt when the composer reaches a specified display line.

To specify the line, simply write the line number in little-endian order to $0F0009 and $0F000A (the low byte to $0F0009, the high byte to $0F000A). Upon reaching the specified line, the VERA will trigger an interrupt. You can distinguish a line interrupt from the VERA by checking $9F27 in system memory for $02. Be sure to clear the bit before your interrupt handler exits!