Introduction
Two floating-point options existed. The FIS (also called the KEV11 on the LSI-11) is four instructions that work on numbers held on the stack. The
FP11 is a separate floating-point processor with its own registers and instructions in the 17xxxx range, used by the 11/45, the 11/70 and later models; it is
what UNIX and the Fortran and C compilers of those machines used. The disassembler decodes both and marks them with their feature group (fis, fpp).
The FP11 registers
Six 64-bit accumulators ac0 to ac5, a 16-bit status register FPS, an error code FEC and an error address FEA (the address of the instruction that failed). An instruction’s own accumulator field is two bits, so it names only ac0 to ac3;
but a floating-point operand in addressing mode 0 names a register number 0 to 5 as an accumulator (ac4 and ac5 are reachable only that way). Mode 0 with register 6 or 7 is an error. The UNIX assembler writes the accumulators fr0 to fr3.
| FPS bit | Name | Meaning |
|---|---|---|
| 15 | FER | floating-point error |
| 14 | FID | interrupt disable: no trap for any error |
| 11 | FIUV | interrupt on undefined variable |
| 10 | FIU | interrupt on underflow |
| 9 | FIV | interrupt on overflow |
| 8 | FIC | interrupt on integer conversion error |
| 7 | FD | double-precision mode: floating-point operands are 64 bits (clear: 32 bits) |
| 6 | FL | long-integer mode: integer operands are 32 bits (clear: 16 bits) |
| 5 | FT | truncate instead of round |
| 3–0 | FN FZ FV FC | the floating condition codes, set by the floating instructions; CFCC copies them to the processor’s N Z V C |
The mode bits (FD, FL) decide how many bytes a memory operand has, so the stepping of an autoincrement register (4 or 8 bytes for a floating operand, 2 or 4 for an integer one) depends on them; the instruction’s length does not, so the disassembler needs no mode to decode and does not track SETD and SETF.
Formats
- F (floating, 32 bits, two words): the first word has the sign in bit 15, an 8-bit exponent in bits 14–7 (excess 128) and the top 7 fraction bits; the second word has the other 16 fraction bits. The fraction has a hidden leading 1, so the value is ±0.1fff… (binary) × 2exponent−128.
- D (double, 64 bits, four words): the same with 55 fraction bits.
- Zero is exponent 0 with sign 0. Sign 1 with exponent 0 is the undefined variable (“−0”): it is not a number, and reading it can trap.
- I and L integers are 16 and 32 bits, twos complement; the 32-bit one has its high word first.
- Immediate: a floating-point operand written with
#(autoincrement of the PC) is one word, whatever the mode: the sign, exponent and top 7 fraction bits, with the rest of the number zero. Soldf #40200,ac0loads 1.0 (040200) and the instruction is two words long. The emulator core used for the explorer’s checks does exactly this, and says it is peculiar to the hardware; the same one word is used for an integer immediate in L mode.
Errors
A floating-point error sets FER and stores a code in FEC; unless FID is set, the processor then traps through vector 244 before the next instruction. The codes (as in the emulator core):
2 illegal op code, 4 divide by zero, 6 conversion error, 8 overflow, 10 underflow, 12 undefined variable, 14 maintenance trap.
FP11 instructions
fsrc and fdst are a floating operand (mode 0 is an accumulator), src and dst an integer one, ac the instruction’s own accumulator (ac0 to ac3). The opcode is 17 with the number below; the accumulator takes
bits 7–6 and the operand bits 5–0. Unless noted, the condition codes set are the floating FN FZ FV FC. The UNIX assembler’s name is in the second column where it differs.
| Instruction | UNIX as | Opcode | Effect |
|---|---|---|---|
cfcc | cfcc | 170000 | Copies the floating condition codes to the processor’s N Z V C: how a program branches on a floating compare. |
setf | setf | 170001 | Floating mode: FD = 0 (32-bit floating operands). |
seti | seti | 170002 | Integer mode: FL = 0 (16-bit integers). |
setd | setd | 170011 | Double mode: FD = 1 (64-bit floating operands). |
setl | setl | 170012 | Long mode: FL = 1 (32-bit integers). |
ldfps src | ldfps | 1701SS | Loads FPS from a word. |
stfps dst | stfps | 1702DD | Stores FPS into a word. |
stst dst | stst | 1703DD | Stores FEC and FEA (two words) after an error. |
clrf fdst | clrf | 1704DD | Sets a floating number to zero. |
tstf fsrc | tstf | 1705DD | Sets FN and FZ from a floating number. |
absf fdst | absf | 1706DD | Absolute value. |
negf fdst | negf | 1707DD | Negates (changes the sign). |
mulf fsrc,ac | mulf | 171(0–3)SS | ac = ac × fsrc. |
modf fsrc,ac | modf | 171(4–7)SS | Multiplies and separates integer and fraction: the fractional part goes to ac, the integer part (as a floating number) to the next accumulator. |
addf fsrc,ac | addf | 172(0–3)SS | ac = ac + fsrc. |
ldf fsrc,ac | movf | 172(4–7)SS | Loads the accumulator from fsrc (and sets the codes: STF does not). |
subf fsrc,ac | subf | 173(0–3)SS | ac = ac − fsrc. |
cmpf fsrc,ac | cmpf | 173(4–7)SS | Compares fsrc with ac and sets the codes; nothing is stored. |
stf ac,fdst | movf | 174(0–3)DD | Stores the accumulator. (The UNIX assembler spells both LDF and STF movf and picks the instruction by whether the first operand is a register.) |
divf fsrc,ac | divf | 174(4–7)SS | ac = ac ÷ fsrc. |
stexp ac,dst | movei | 175(0–3)DD | Stores the exponent of ac (without the excess 128) into an integer word. |
stcfi ac,dst | movfi | 175(4–7)DD | Converts ac to an integer and stores it: 16 or 32 bits by FL (STCFI, STCDI, STCFL, STCDL). |
stcfd ac,fdst | movfo | 176(0–3)DD | Converts ac to the other floating format (D to F when FD is set, F to D when clear) and stores it (STCFD and STCDF share this opcode). |
ldexp src,ac | movie | 176(4–7)SS | Loads the exponent of ac from an integer. |
ldcif src,ac | movif | 177(0–3)SS | Converts an integer (16 or 32 bits by FL) to floating and loads it. |
ldcdf fsrc,ac | movof | 177(4–7)SS | Loads and converts from the other floating format (LDCDF and LDCFD share this opcode: FD says which way). |
Everything in 170003–170010 and 170013–170077 is reserved. (The emulator core executes these as no-operations; the decoder shows them as reserved.)
The FIS instructions
The FIS (11/35 and 11/40 option, and the LSI-11’s KEV11) works on 32-bit F numbers on the stack. The register R in the opcode points at the stack: the instruction takes two operands from it, replaces them with the result, and moves R up by 4. The emulator core in the explorer’s checks has no FIS, so these four are checked only against the tables.
| Instruction | Opcode | N Z V C | Effect |
|---|---|---|---|
fadd r | 07500R | * * * * | Add the two numbers on the stack. |
fsub r | 07501R | * * * * | Subtract. |
fmul r | 07502R | * * * * | Multiply. |
fdiv r | 07503R | * * * * | Divide. |
Not described
Known, not yet covered
- The rounding rules, the exact flag changes of each instruction, the maintenance mode, and the operand order of the FIS’s stack arguments.
Unknown
- Which operand a FIS instruction takes first and the flags it sets: from names only.
Links
Reference
- pdp11-js – Paul Nankervis’s emulator: its
fpp.jsdocuments the formats, the FPS bits and the error codes used above - UNIX Assembler Reference Manual – the UNIX names of the floating-point moves
- GNU as, PDP-11 notes – FIS (KEV11) and FP-11 as separate extensions