VBXE 240p TEST SUITE v1.0 - basic test patterns for VBXE (any FX core v1.2x from v1.26)

FILES
  vbxe240p.xex   program (about 11 KB)
  vbxe240p.c, vbxe240p.ld  - program sources (llvm-mos)
  pmgen.py       draws the PM5544 test card 320x240 fully algorithmically and turns it into a
                 plan for the blitter: pm_blt.h (operations, circle cut-out, antialiased edge),
                 pm_pal.h (palette)
  pm_blt.h, pm_pal.h - generated by pmgen.py
  build.sh       builds everything

PICTURE
  VBXE SR Overlay 320x240, 256 colors, NORMAL width, 240 lines = the whole XDL area
  (lines 8..247). The 640 px tests use the HR mode 640x240 (16 colors) - the maximum
  pixel rate of the VBXE. Used: XDL, palette, MEMAC-A window and blitter (standard 21-byte
  BCBs) - all present in FX v1.26. Every pattern is a few different lines in VRAM; the XDL
  points to them with step 0, so all patterns are prepared at start and switching is only
  a change of XDL_ADR (immediate).

TESTS (variant: SPACE)
  1 PLUGE        black background, 7.5% / 4% / 2% bars (symmetrical) and a white center
  2 COLOR BARS   8 EBU bars (white, yellow, cyan, green, magenta, red,
                 blue, black): 100% / 75%
  3 TEST CARD    PM5544 drawn anew for 320x240 (pmgen.py): grid every 18 px,
                   all areas of constant color with sharp edges, all lines
                   1 px; drawn in layers: gray background with the grid, the circle
                   patterns separately on a rectangle larger than the circle, cut out with
                   the circle (center 160.5/120.5, radius 108.9) and placed on the
                   background - antialiasing only on the edge (coverage of 16x16 samples);
                   multiburst bars drawn anew: period 8, 4, 3 and 2 px, sinusoidal
                   profile; colors in free positions of palette 1.
                   Drawn by the blitter at start (about 250 operations), the CPU adds only
                   the antialiased edge of the circle (725 bytes).
  4 RAMPS        gray, R, G, B in bands of 60 lines: 16 steps (20 px) /
                 smooth - 128 steps, all levels of the component from 0 to 255
                 (palettes 2 and 3, switched by the XDL in every band)
  5 CONV/FOCUS   convergence grid of 20x15 fields 16x16: every field has a 1 px frame (lines
                 between fields 2 px) and a 2x2 dot in the center:
                 - outer ring of fields red, the rest white
                 - all white
                 - FOCUS: checkerboard of 8x8 fields (40x30) alternating vertical and horizontal
                   1 px lines (white columns / rows 1, 3, 5 of the field); column/row 0 and 7
                   of every field black, so white pixels of neighbouring fields never touch
  6 SOLID        full screen: black, white, red, green, blue, 75% gray
  7 STRIPES      vertical 1 px stripes (320), horizontal 1 line, vertical 1 px in 640 (HR)
  8 CHECKERBOARD black and white 1x1 checkerboard: 320x240 / 640x240 (HR)

PALETTE (Overlay palette 1)
  Component values: 100% = 255, 75% = 191, PLUGE: 2% = 6, 4% = 10, 7.5% = 19,
  16 steps: step k = round(k * 127 / 15) in 7 bits; the last bar = full value,
  128 steps: all levels 0..127 in 7 bits (palettes 2 and 3).
  The VBXE keeps 7 bits per component (bit 0 is dropped): 191 -> 190 (74.5%),
  19 -> 18, 6 and 10 unchanged.

KEYS
  menu:  1..8 select a test, ESC exit to DOS
  test:  SPACE / RETURN / FIRE - next variant
         1..8 - first variant of that test; if this test is already on,
                works like SPACE (next variant) - the same at any time
         joystick left/right (or + / *) - previous / next test
         ESC - back to the menu

REQUIREMENTS / MEMORY
  VBXE with an FX core v1.2x from v1.26 up (VERSION $26..$2F, RAMBO bit ignored),
  at $D640 or $D740. Other / older core: message and return to DOS.
  Program $2000-$7FFF, MEMAC-A window $8000-$8FFF (enabled only while writing VRAM).
  Preparation at start: about 0.68 million CPU cycles (about 0.4 s). The CPU
  writes only small things (palette, short patterns, a few lines, glyphs, unique XDL records,
  the PM5544 circle edge) and the BCB lists; the blitter does the rest:
  - fills; a line with a short period (stripes, focus, grid) is one period written by the
    CPU and a blitter copy over the rest of the line (source and destination overlap);
    ramps: the CPU writes the first one, the others are blitter copies of it with an XOR mask;
  - XDL of repeating patterns (stripes, checkerboards, grid, focus): the CPU writes one block
    of records, the blitter repeats it along the XDL;
  - menu: the CPU expands glyphs from the OS ROM (byte $FF per pixel), the blitter builds
    9x9 cells with a shadow from them and copies them in mode 1 (0 = transparent) with
    AND mask = text color; the blitter itself replicates the text BCBs from a template, the
    CPU changes only 6 bytes in each;
  - PM5544: background layer to $60000, the circle interior on a rectangle larger than the
    circle to a temporary buffer, then a copy of the circle line by line; finally the CPU
    writes the edge. The plan data are packed: operations of 6-7 bytes, circle ranges of
    2 bytes (symmetrical about the center), the edge by lines - a pair of mirrored runs
    shares one header.
  Assembler only where time matters: filling, copying to the MEMAC window, appending a
  BCB to the list, the PM5544 edge, palettes 2 and 3.
  Three BCB lists: 1) clearing of the glyph atlas and replication of the text BCBs,
  2) lines, XDL, PM5544, menu background, 3) menu text. Each list is built while the
  previous one runs.
  The menu is an SR 320x240 Overlay screen: background with a gradient, text in the OS ROM
  font in its natural 8x8 size (font pixel = SR pixel, no scaling), in several colors,
  with a 1 px shadow; separating lines with a shadow.

BUILD
  ./build.sh  (mos-atari8-dos-clang, python3; Pillow only for the pmgen.py previews)
  = python3 pmgen.py  (when pm_blt.h / pm_pal.h are missing)
  + mos-atari8-dos-clang -Os -fno-builtin -T vbxe240p.ld -o vbxe240p.xex vbxe240p.c
    (-fno-builtin: short loops stay loops, no slow memset / strlen from the library)
