Internal Floating Point Representation
The Wang 2200 BASIC used a BCD floating point number system. All numbers are double precision and occupy eight bytes of memory. Internally, the format is: Signs nibble, Exp. Low nibble, Exp. High nibble, Mantissa (13 nibbles). Both the mantissa and exponent are represented as BCD sign/magnitude form.
| Signs | Low Exp. | High Exp. | MS Mantissa digit | ... | LS Mantissa digit |
|---|---|---|---|---|---|
| 1 nibble | 1 nibble | 1 nibble | 1 nibble | 11 more nibbles | 1 nibble |
The mantissa is always normalized. If the exponent gets too small, the value simply flushes to zero (which is encoded as all zero bytes).
The signs nibble has four bits. The ms bit of the sign nibble is 1 if the exponent is negative. The ls bit of the sign nibble is 1 if the mantissa is negative. The other two bits are always zero, or in a verilog-ish syntax, { exponent_sign, 0, 0, mantissa_sign }. Stated another way, there are four legal values for this sign nibble:
| Sign nibble value | indicates | Example value |
|---|---|---|
| 0 | mantissa and exponent both positive | +1.0 |
| 8 | mantissa positive, exponent negative | +0.1 |
| 9 | mantissa and exponent both negative | -0.1 |
| 1 | mantissa negative, exponent positive | -1.0 |
Wang BASIC-2, which ran on the 2200VP and related CPU, is also BCD and also occupied eight bytes. It is very likely similar if not identical, but it hasn't yet been researched.
CPU Microarchitecture Synergy
The 2200 CPU had a few features to make working with floating point BCD numbers more efficient.
- the CPU had instructions for BCD addition and subtraction
- the CPU was a nibble addressed machine with 4b operations
- some addressing modes caused the address pointer to increment or decrement with a wrap at 16 nibbles
- although the CPU was a 4b machine for the most part, reads fetched 8b at a time. There were two modes of reading. In one mode, the 8b were the adjacent nibbles of a byte (horizontal mode). In the other mode, they were corresponding nibbles that were 16 nibbles apart (vertical mode).
Synergy occurs when these separate features work together to mutually enhance the usefulness of each individual feature. In the case of Wang BASIC, the interpreter would place the two operands of whatever operation was being performed (addition, multiplication, etc.) into memory aligned to a 16 nibble boundary with the two operands 16 nibbles apart. By using the vertical read mode, corresponding nibbles of the two operands could be fetched in one memory access. By using autoincrementing addressing, each ALU operation would have the side effect of advancing to the next nibble in the operands. By using the wrapping feature the CPU could sometimes avoid having to reset the nibble pointer at the end of the mantissa operation.
Exploration
Wang BASIC has a few functions for converting between numeric and alphanumeric representations (ASCII or packed hex). Attempts to feed the string to number conversion command malformed strings to see what kind of number is generate has met with no interesting results. For example:
10 A$=HEX(0000000000000000) 20 CONVERT (+#.############^^^^) A$ TO A 30 PRINT A
Produces 0 (mantissa and exponent signs are positive, all mantissa nibbles are zero, exponent is zero). First, some vanilla values; to make it easier to decode, the nibble with the S over it is the signs nibble, the M nibbles are the mantissa digits, and EE are the exponent digits.
SMMMMMMMMMMMMMEE
10 A$=HEX(0000000000000000) --> 0
10 A$=HEX(0100000000000000) --> 1
10 A$=HEX(0150000000000000) --> 1.5
10 A$=HEX(0100000000000001) --> 10 (exponent of positive 01)
10 A$=HEX(8100000000000001) --> 0.1 (exponent of negative 01)
10 A$=HEX(1100000000000000) --> -1 (negative mantissa sign bit)
Now throw in some values that stretch the rules:
SMMMMMMMMMMMMMEE
10 A$=HEX(0010000000000001) --> 1 (unnormalized mantissa is accepted)
10 A$=HEX(8010000000000099) --> error (would be 1E-100; not flushed to zero)
10 A$=HEX(010000000000000A) --> error (illegal exponent nibble value)
10 A$=HEX(2100000000000001) --> 10 (unspecified sign bit is ignored)
10 A$=HEX(4100000000000001) --> 10 (unspecified sign bit is ignored)
The two middle bits of the signs nibble appear to be completely ignored.