Vector hardware · Game development

Vectrex Mastery

From an empty folder to a cartridge you can sell — C and 6809 assembly, with every number in the text measured against a ROM that really ran.

A Vectrex console with its controller
Chapters
40 + 7 appendices
Words
46,440
Cycles per frame
30,000
Runnable here
1 ROMs

05 — Measuring and debugging

Goal

Build the habit the rest of this book depends on: never believe the picture, always read the numbers, and know exactly what each number does and does not mean. By the end you can answer "did that change help?" with a figure.

Why the screen cannot be your witness

On a raster machine you debug by looking. Here you cannot, for three reasons that compound:

  1. The phosphor decays. A line drawn early in the frame is dimmer than one drawn late. Brightness on screen encodes when, not what.
  2. The camera lies. A photograph integrates over its exposure, which has no relationship to your frame.
  3. The emulator flatters. Its glow is tuned to look like a Vectrex, not to be one.

The ground truth is the vector list: the segments the machine drew, in order, with their intensity. Everything in this chapter reads that list.

The four tools

ToolWhat it does
vecdumpruns a ROM headless; per frame reports the vector list, counts, beam travel, cycles and RAM
vecshot.pydraws a dumped frame to PNG — the figures in this book
vecplay.pyruns a ROM against a written input script and captures chosen frames
vectest.pythe seven acceptance checks; exits non-zero on failure
vecdump game.bin -f 300 -q              # summary only
vecdump game.bin -f 300 -F 60,120       # dump the vector list for two frames
vecshot.py game.vec -H 600              # render them
vectest.py game.bin -f 300              # pass or fail

Reading a frame

Here is one frame of this chapter's program, drawing a single square:

LINE       0  38350 ->   6300  38350  i=95
dot     6300  38350 ->   6300  38350  i=95
dot     6300  38350 ->   6300  38350  i=95
LINE    6300  38350 ->   6300  30700  i=95
...

A square is four lines and eight dots. The dots are lit segments of zero length — the beam standing still between the sides. They cost no beam travel but they are in the list, and counting them as vectors inflates line art roughly threefold. vecdump reports the two separately for this reason, and never adds them together.

This is not a hypothetical. The first version of the tool counted every lit segment as a vector and reported a square as 12 vectors. Every "vectors per frame" figure it produced for line art was three times too large.

The method: measure the slope, not the reading

This is the most important paragraph in the chapter.

While your frame's work fits inside the budget, Wait_Recal absorbs whatever is left over. The measured frame length is then about 30,000 cycles no matter what you did inside it. Here is the same program with a workload that doubles and doubles again:

workloadcycles per frame
030,015
1030,015
2030,441
4057,221
80110,781

Between 0 and 10 the workload went from nothing to ten units of real work and the measurement did not move by a single cycle. A change that halved your workload in that region shows up as no change at all.

The way out is to take two readings well above the budget and use the difference. That cancels the frame's fixed cost, the call overhead, and the absorption. In the table above, 40 → 80 gives 53,560 cycles for 40 units of work: 1,339 cycles each, and the same slope holds at every point beyond the budget. Chapter 06 uses exactly this to compare C against assembly, and chapter 27 makes it routine.

Build it, step by step

boxes.c draws BOXES squares and nothing else. The point is not the picture: it is that every number changes in a way you can predict.

source ../../tools/env.sh
make sweep
boxes     vectors    dots      beam    cycles
1             4.0     8.0     24480     30017
4            16.0    32.0     97920     30017
16           64.0   128.0    391680     32283

Four vectors per square, exactly. Beam travel exactly four and sixteen times the single-square figure. When your measurement scales the way arithmetic says it should, both the tool and your model of the machine are working.

Note the cycles column doing precisely what the section above warned about: one box and four boxes are identical to the cycle, despite four times the drawing, and only at 16 does the frame overrun far enough to show anything at all.

sixteen squares
sixteen squares

Traps that catch everyone here

moveto_d is relative. It moves the beam from where it already is, not to an absolute position. Without a reset0ref() first, the second square is drawn relative to the end of the first, the third relative to that, and they walk off the screen. This chapter's program had that bug, and here is how it announced itself:

BOXES=1 and BOXES=4 reported identical vector counts and identical beam travel.

The numbers said it before the picture did — one square looks much like another, but two identical measurements from different programs is impossible. That is the whole argument for measuring.

The usable screen is not ±128. At the default scale one unit passed to moveto_d is 255 DAC units, which puts the usable area at roughly x ±64, y ±80. Place a shape outside it and the beam clips against the edge silently. The symptom is a square with three sides — which is exactly what appeared when this chapter's grid was first laid out at ±70.

A single benchmark reading is worthless. See the section above. The first figure produced for chapter 06 was wrong by a factor of two and looked entirely plausible.

Not every part of a tool is equally tested. vecplay's button lines are verified end to end; its stick lines are not — injected analog values do not reach the game in this emulator build (chapter 22). A tool you wrote yourself earns trust one feature at a time, and the untested ones should say so out loud rather than look identical to the tested ones.

What only real hardware shows

Nothing in this chapter needs a Vectrex, and that is the point: the acceptance run is automatic and can be part of a build. What it cannot tell you is whether the result is legible — brightness, contrast and the tube's own geometry are chapter 30.

Exercise

Take the sweep table above and predict, before running it, the vectors, dots and beam travel for BOXES=9. All three are exactly predictable from the numbers you already have. Then run make BOXES=9 and check. If you are wrong, you have found either a bug or a gap in your model of the machine, and both are worth more than a correct guess.