image of READY prompt

Wang2200.org

Synthetic Microcode

The Problem (link)

The first generation 2200 machines used a large number of ROMs to contain the microcoded Wang BASIC interpreter. The interpreter implemented the core BASIC language, and added a number of commands for peripherals that Wang knew would be commonly used, such as the disk commands, card readers, cassette drives, and plotters. Even providing for the popular, existing peripherals wasn't enough. Wang had plans for supporting many more, many of which hadn't even been dreamed up by the time the 2200 CPU was out the door.

Most other machines can simply install a driver for a new peripheral; the driver is typically written in assembly language and runs at high privilege. Such concepts are alien to the 2200. There is no assembly language, as the BASIC interpreter is written in microcode. Even if Wang was willing to write drivers for new peripherals in microcode, there was no practical way to support the wide variety of drivers that would be needed via replacing the mask ROM chips in the machines out in the field. Wang needed some solution to support new peripherals that would allow flexibility with decent performance.

The Solution (link)

Wang's solution was what I call "synthetic microcode". The $GIO command defined a small instruction set of 16b instructions that were interpreted in the true CPU microcode. The user's application would load up a string array with the synthetic microcode command words and the issue a $GIO command to perform that "microcode".

The $GIO instruction set contains a wide variety of instructions to select a device, send or receive single or multiple bytes, wait until a peripheral was ready, wait a certain time delay, etc. The commands to send/receive a string of bytes allowed data transfer at the full microcode rate, which was on the order of 50 KB/sec.

These $GIO commands sufficed to allow controlling telecommunication devices, 9-track tape drives, and lab instrument controllers. However the $GIO instruction set does not model a general purpose processor. It was intentionally quite limited in many ways (relaxed somewhat for Wang BASIC-2), such as the inability to directly reference memory or to have nested loops. This was done to prevent user programs from corrupting the state of the BASIC interpreter or causing other mischief.

Example Code (link)

Here is an example from the manual. It sends two header bytes to the device at address /03B, then writes the entire contents of array B$(), then sends an LRC byte, and finally receives a status response byte from the device. The status is saved in string R$.

100 $GIO WRITE /03B (6C01 4400 A206 8601, R$) B$()

This breaks down as

$GIO General-purpose I/O command
WRITE just a descriptive comment (and is optional)
/03B select device 03B
6C01 Single character output sequence
"WR, OBS/IMM, W5, CPB, IBS, VERIFY, TERM"
  • wait for ready signal from device
  • CPU sends a CBS output strobe with byte HEX(01)
  • wait 5 microseconds for strobe to finish
  • CPU sets the CPB signal indicating it is ready for input
  • CPU waits for IBS (input bus strobe) from selected device
  • make sure the received byte matches the one just sent
  • if they didn't match, set the termination flag
4400 Single character output sequence
"WR, CBS/IMM"
  • wait for ready signal from device
  • CPU sends a CBS output strobe with byte HEX(00)
A206 High speed multicharacter output
"(WR, DATAOUT/OBS), REPEAT, LEND"

For each character in the array,

  • wait for ready signal from device
  • send next byte a data from array and send OBS (Output Bus Strobe)

After sending all the bytes,

  • wait for the ready signal from the device
  • send the LRC of the bytes just sent and strobe the CBS output strobe
  • save the LRC in the R$() array along with other command status
8601 Single character input
"CPB, IBS, SAVE"
  • CPU sets the CPB signal indicating it is ready for input
  • CPU waits for IBS (input bus strobe) from selected device
  • Received byte is stored in byte 1 of the R$ string
R$ a string holding the working "registers" for the command
B$() a data array to be operated upon

Documentation (link)

For the full story, read the $GIO description for Wang BASIC or the $GIO description for Wang BASIC-2.

BASIC-2 added some additional command words beyond what was in the $GIO command set of the first generation Wang BASIC.

Aside (link)

The Apple II BASIC interpreter had a similar scheme although it was done for different reasons.

Steve Wozniak defined a 16 bit CPU instruction set that was simple and efficient to interpret in 6502 machine language. He called it SWEET16. Wozniak's purpose (other than showing off a cool idea) was to allow writing programs that were more dense than pure assembly language by dropping into SWEET16 mode when it was advantageous, such as when a lot of address pointer manipulation had to be done.