# Waveform graphics

Waveform graphics is a simple vector graphics system introduced by Digital Equipment Corporation (DEC) on the VT55 and VT105 terminals in the mid-1970s. It was used to produce graphics output from mainframes and minicomputers. DEC used the term "waveform graphics" to refer specifically to the hardware, but it was used more generally to describe the whole system.
The system was designed to use as little computer memory as possible. At any given X location it could draw two dots at given Y locations, making it suitable for producing two superimposed waveforms, line charts or histograms. Text and graphics could be mixed, and there were additional tools for drawing axes and markers.
The waveform graphics system was used only for a short period of time before it was replaced by the more sophisticated ReGIS system, first introduced on the VT125 in 1981. ReGIS allowed the construction of arbitrary vectors and other shapes. Whereas DEC normally provided a backward compatible solution in newer terminal models, they did not choose to do this when ReGIS was introduced, and waveform graphics disappeared from later terminals.

## Description

Waveform graphics was introduced on the VT55 terminal in October 1975, an era when memory was extremely expensive. Although it was technically possible to produce a bitmap display using a framebuffer using technology of the era, the memory needed to do so at a reasonable resolution was typically beyond the price point that made it practical. All sorts of systems were used to replace computer memory with other concepts, like the storage tubes used in the Tektronix 4010 terminals, or the zero memory racing-the-beam system used in the Atari 2600. DEC chose to attack this problem through a clever use of a small buffer representing only the vertical positions on the screen. Such a system could not draw arbitrary shapes, but would allow the display of graph data.
The system was based on a 512 by 236 pixel display, producing 512 vertical columns along the X-axis, and 236 horizontal rows on the Y-axis. Y locations were counted up from the bottom, so the coordinate 0,0 was in the lower left, and 511, 235 in the upper right. Had this been implemented using a framebuffer with each location represented by a single bit, 512 ⨉ 236 x 1 = 120,832 bits, or 15,104 bytes, would have been required. At the time, memory cost about $50 per kilobyte, so the buffer alone would cost over $700, equivalent to $4,325 in 2023.
Instead, the waveform graphic system used one byte of memory for each X axis location, with the byte's value representing the Y location. This required only 512 bytes for each graph, a total of 1024 bytes for the two graphs. Drawing a line required the programmer to construct a series of Y locations and send them as individual points, the terminal could not connect the dots itself. To make this easier, the terminal automatically incremented the X location every time an Y coordinate was received, so a graph line could be sent as a long string of numbers for subsequent Y locations instead of having to repeatedly send the X location every time. Drawing normally started by sending a single instruction to set the initial X location, often 0 on the left, and then sending in data for the entire curve.
The system also included storage for up to 512 markers on both lines. These were always drawn centered on the Y value of the line they were associated with, meaning that a simple on/off indication for X locations was all that was needed, requiring only 1024 bits, or 128 bytes, in total. The markers extended 16 pixels vertically, and could only be aligned on 16-pixel boundaries, so they were not necessarily centered across the underlying graph. Markers were used to indicate important points on the graph, where a symbol of some sort would normally be used. The system also allowed a vertical line to be drawn for every horizontal location and a horizontal one at every vertical location. These were also stored as simple on/off bits, requiring another 128 bytes of memory. These lines were used to draw axes and scale lines, or could be used for a screen-spanning crosshair cursor. A separate set of two 7-bit registers held additional information about the drawing style and other settings.
Although complex from the user's perspective, this system was easy to implement in hardware. A cathode ray tube produces a display by scanning the screen in a series of horizontal motions, moving down one vertical line after each horizontal scan. At any given instant during this process, the display hardware examines a few memory locations to see if anything needs to be displayed. For instance, it can determine whether to draw a marker on graph 0 by examining register 1 to see if markers are turned on, looking in the marker buffer to see if there is a 1 at the current X location, and then examining the Y location of graph 0 to see if it is within 16 pixels of the current scan line. If all of these are true, a spot is drawn to present that portion of the marker. As this will be true for 16 vertical locations during the scanning process, a 16-pixel high marker will be drawn.
Sold alone, the VT55 was priced at $2,496, equivalent to $15,421 in 2023. Like other models of the VT50 series, the terminal could be equipped with an optional wet-paper printer in a panel on the right of the screen. This added $800 equivalent to $4,943 in 2023 to the price.
DEC also offered VT55 in a package with a small model of the PDP-11 to create one model of the DEClab 11/03 system. The DEClab normally sold for $14,000, equivalent to $86,494 in 2023 with a DECwriter II (LA36) hard-copy terminal for $15,000, equivalent to $86,494 in 2023, with the VT55. The system had I/O channels for up to 15 lab devices, and included libraries for FORTRAN and BASIC for reading the data and creating graphs. The fairly extensive VT55 Programmers Manual covered the latter in depth.

## Commands and data

Data was sent to the terminal using an extended set of codes similar to those introduced on the VT52. VT52 codes generally started with the ESC character (octal 33, decimal 27) and was then followed by a single letter instruction. For instance, the string of four characters ESCHESCJ would reposition the cursor in the upper left (home) and then clear the screen from that point down. These codes were basically modeless; triggered by the ESC the resulting escape mode automatically exited again when the command was complete. Escape codes could be interspersed with display text anywhere in the stream of data.
In contrast, the graphics system was entirely modal, with escape sequences being sent to cause the terminal to enter or exit graph drawing mode. Data sent between these two codes were interpreted by the graphics hardware, so text and graphics could not be mixed in a single stream of instructions. Graphics mode was entered by sending the string ESC1, and exited again with the string ESC2. Even the commands within the graphics mode were modal; characters were interpreted as being additional data for the previous load character (command) until another load character is seen. Ten load characters were available:
X and Y locations were sent as 10-bit decimal numbers, encoded as ASCII characters, with 5 bits per character. This means that any number within the 1024 number space (2$^{10}$) can be stored as a string of two characters. To ensure the characters can be transmitted over 7-bit links, the pattern 01 is placed in front of both 5-bit numbers, producing 7-bit ASCII values that are always within the printable range. This results in a somewhat complex encoding algorithm.
For instance, if one wanted to encode the decimal value 102, first you convert that to the 10-bit decimal pattern 0010010010. That is then split that into upper and lower 5-bit parts, 00100 and 10010. Then append 01 binary to produce 7-bit numbers 0100100 and 0110010. Individually convert back to decimal 40 and 50, and then look up those characters in an ASCII chart, finding ( and 2. These have to be sent to the terminal least significant character first. If these were being used to set the X coordinate, the complete string would be H2(. When used as X and Y locations for the graphs, extra digits were ignored. For instance, the 512 pixel X axis requires only 9 bits to encode, so the 10th bit was ignored. Likewise, Y locations ignored the 9th and 10th bits.
Control registers always contained 7 bits, with the most significant bits always being 01. In register zero, bit 0 (least significant) turned the entire line drawing system on or off. Bits 1 and 2 turned the individual graphs 0 or 1 on or off, and bits 3 and 4 controlled whether graphs 0 and 1 were lines or filled in to make histograms. For instance, if one wanted to have both graphs on-screen, but graph 0 would be a histogram and graph 1 would be a line, the required bit pattern would be 0101111, the leading 01 being fixed, the next bit saying graph 1 is a line (0), the next that graph 0 is a histogram (1), that both graphs are on (11) and that the entire graphics system is enabled (1). The resulting pattern is equivalent to decimal 47, the / character. This mode would be enabled with the string A/.
The I register was loaded using similar encoding, but the bits controlled the display of markers and the horizontal and vertical lines. As with A, the most significant bits were always 01, the least significant bit turned on or off horizontal lines, bit 1 the same for vertical, 2 and 3 whether or not to display markers on graph 0 or 1 respectively, and setting bit 5 would clear out all the data for the markers and lines. That meant that one could clear the display by sending the bit pattern 0110000, decimal 48, the character 0. This produces the easily readable command I0.
Markers and lines required only one coordinate to be sent, an X or Y. In the case of a marker, the Y location was defined by the data previously set with B or J. For lines, the second coordinate spanned the screen. For instance, a vertical line could be placed at location 102 on the X axis with the string L2(. Both markers and lines could be cleared by setting bit 5 of the third character, which would otherwise be unused.

## Example

The following example produces a simple graphic:
ESC1A'I?B1111111111111111H (J6666666666666666C$09K$8D+723L 0?? 8
The first two characters tell the terminal to enter graphics mode, while the next four set the two drawing mode registers to turn on both graph lines, markers on both, and enables horizontal and vertical lines. The B followed by the string of 1's produces an 8-pixel horizontal line in the lower left of the screen drawn using graph 0. The X location starts at the default location 0, and moves over one location with every following data point, which always consists of two characters. There is no need to type B in again, the string is modal and the current command remains B until another is encountered.
That occurs when the H is encountered, and the following two characters are used to move the starting X location to the center of the screen. This is followed by a second line segment being drawn in graph 1 using the J. Two markers are then added, one on each line, centered along the segments. The line segments are 16 pixels wide and the markers are always 16 high. The result are cross shapes, one in the lower left and another centered. As the markers are centered on 16-pixel boundaries and cannot be drawn outside the visible area, the first marker on the lower segment will appear above the line, creating an upside-down T shape rather than a cross. The last two commands, D and L, produce two horizontal lines at the bottom and center of the screen, and three vertical lines at the left, center and right.
At this point the terminal is still in graph drawing mode. One could turn graph 1 into a histogram by sending A7, causing a vertical bar to be drawn extending down from the center of the screen. Sending ESC2 would exit graphics mode, at which point further characters are interpreted as normal text.

## VT105 changes

The VT105 was broadly similar to the VT55, but added a number of additional features. One was a square format mode that reduced the display horizontally by eight character widths and extended it vertically by one line to make it more square than the original layout. This left additional room on the left for eight characters instead of a single vertical column, improving label displays. The VT105 also changed the meaning of register 0's bits slightly; bit 1 and 2 no longer turned on and off the entire graph, but the display of the graph points themselves. This allowed the display to make a line, a shaded histogram, or a histogram with a brighter line on top. In comparison, on the VT55 the graph bit controlled the display of the entire dataset, not just the line itself, so turning off the graph bit would make the histogram disappear as well.
Another change was to re-use the @ command, formerly the noop, to allow a new Y position to be sent in as the shade line. This worked in conjunction with the histogram to allow the direction of the filling to be changed. On the VT55 the filling always drew down from the graph to the base of the display, on the VT105 with the shade line set, this could be set to draw up to the top of the screen, or more commonly, towards a center-point in the data. For instance, with the shade line set to the middle of the screen, if a sine wave was plotted the areas above the center would be shaded downwards and the sections below center upwards, producing a filled-in waveform. Enabling a horizontal line at the same point adds a visual baseline. There were two shade lines in memory, one for each graph, but only one @ command. A bit in register 1 controlled which of the two buffers the @ data was loaded into.
Another major addition was the concept of strip graphs, a mode that emulated paper pen plotters that moved up and down while the paper was wound under them. These were commonly used for recording scientific data, but are perhaps best known on older lie detectors. As new data points were added to one of the graphs, previous data was shifted to the left. Thus, sending a series of Y values using B or J would first cause the line to be drawn from the left to right like the VT55, but additional data points would push the previous data to the left. If markers or vertical axis lines were set, they too were pushed over, following the data. In dual strip mode, adding data to graph 1 caused both graphs to move over at the same time.
All of these new features were controlled through optional second characters added to the A and I commands. The first data character worked as it had under the VT55, and thus provided backward compatibility. The second turned on the new features. The second character sent to the A controlled shading lines and the strip-chart feature; least significant bit, bit 0, set the shade line data sent with @ to be loaded into graph 0 or graph 1, while bits 2 and 3 turned the shade line on or off for graph 0 or 1, respectively. Turning on bit 3 allowed strip charts to be used, while bit 4 turned it on for both graphs, the dual strip feature. The second character on the I command had only two values, ! or space; sending ! put the terminal into square mode, while space, or nothing, left it in the VT55 compatible rectangle format.

## Other details

The VT50 series also included an alternate character set, graphics mode, that could be switched in and out while in text mode. These were used to provide additional glyphs useful for labeling and similar tasks. Among the characters were subscript 0 through 9 and the upper part of fractions 1/, 2/, 3/, 5/ and 7/. These could be combined to form, for instance, 3⁄7. The set also included horizontal bars at each of the 8 scan lines in a normal glyph, the degree symbol, and other common examples. These used separate character codes, so graphics characters could be mixed with the normal character set on a single screen.