Orthogonal instruction set
is a term used in computer engineering
. A computer's instruction set
is said to be orthogonal
if any instruction can use data of any type via any addressing mode
. Generally, having an orthogonal instruction set
is a desirable attribute for many computer architectures
In this context, the word orthogonal, which means right angle, implies that it is possible to move along one axis (the operations) independently of the other axis (the addressing modes) and vice versa; this meaning being similar – but not identical – to the meaning of the word in pure mathematics.
Orthogonality in practice
In many CISC
computers, an instruction could access either registers or memory, usually in several different ways. This made the CISC machines easier to program, because rather than being required to remember thousands of individual instruction opcodes, an orthogonal instruction set allowed a programmer to instead remember just thirty to a hundred operation codes ("ADD", "SUBTRACT", "MULTIPLY", "DIVIDE", etc.) and a set of three to ten addressing modes ("FROM REGISTER 0", "FROM REGISTER 1", FROM MEMORY", etc.). The DEC PDP-11
and Motorola 68000
computer architectures are examples of nearly orthogonal instruction sets, while the ARM11
is an example of a CPU with a fully orthogonal instruction set.
With the exception of its floating point instructions, the PDP-11 was very strongly orthogonal. Every integer instruction could operate on either 1-byte or 2-byte integers and could access data stored in registers, stored as part of the instruction, stored in memory, or stored in memory and pointed to by addresses in registers. Even the PC
and the stack pointer
could be affected by the ordinary instructions using all of the ordinary data modes. In fact, "immediate" mode (hardcoded numbers within an instruction, such as ADD 0x04, R1 (R1 = R1 + 4) was implemented as the mode "register indirect, autoincrement" and specifying the program counter (R7) as the register to use reference for indirection and to autoincrement.
Since the PDP-11 was an octal-oriented (3-bit sub-byte) machine (addressing modes 0 - 7, registers R0 - R7), there were (electronically) 8 addressing modes. Through the use of the Stack Pointer (R6) and Program Counter (R7) as referenceable registers, there were 10 conceptual addressing modes available.
The VAX-11 extended the PDP-11's orthogonality to all data types, including floating point numbers (although instructions such as 'ADD' was divided into data-size dependant variants such as ADDB, ADDW, ADDL, ADDQ, ADDF for add byte, word, longword, quadword and floating point, respectively). Like the PDP-11, the Stack Pointer and Program Counter were in the general register file (R14 and R15).
The general form of a VAX 11 instruction would be:
opcode [operand ] [operand ] ...
Each component being one byte, the opcode a value
in the range 0 - 255, and each operand consisting of two nibbles, the upper 4 bits specifying an addressing mode, and the lower 4 bits (usually) specifying a register number (R0 - R15).
Unlike the octal-oriented PDP-11, the VAX-11 was a hexadecimal-oriented machine (4-bit sub-byte). This resulted in 16 logical addressing modes (0-15), however, addressing modes 0-3 were "short immediate" for immediate data of 6 bits or less (the 2 low-order bits of the addressing mode being the 2 high-order bits of the immediate data, when prepended to the remaining 4 bits in that data-addressing byte). Since addressing modes 0-3 were identical, this made 13 (electronic) addressing modes, but as in the PDP-11, the use of the Stack Pointer (R14) and Program Counter (R15) created a total of over 15 conceptual addressing modes (with the assembler program translating the source code into the actual stack-pointer or program-counter based addressing mode needed).
By comparison, Motorola's designers attempted to make the assembly language orthogonal while the underlying machine language was somewhat less so. Compared to the PDP-11, the MC68000 used separate registers to store instructions and the addresses of data in memory; the assembly language "hid" some of this separation from the programmer. Many programmers disliked the "near" orthogonality, while others were grateful for the attempt.
At the bit level, the person writing the assembler (or debugging machine code) would clearly see that these "instructions" could become any of several different op-codes. It was quite a good compromise because it gave almost the same convenience as a truly orthogonal machine, and yet also gave the CPU designers freedom to use the bits in the instructions more efficiently than a purely-orthogonal approach might have.
The 8080 and follow on designs
The Intel 8080
8-bit microprocessor was a highly non-orthogonal machine. An assembly-language programmer needed to be constantly mindful of what operations were legal on which registers. Most operations could only be performed on data in the A (accumulator
) register while other operations could only be performed on the HL pair and so forth. This was partly due to the 8008 source compatibility
combined with a desire to keep all opcodes one byte long (later "violated" by the binary-compatible
Z80). The 8086
was an partially orthogonalized and fully 16-bit source compatible
successor to the 8080 which maintained some of this non-orthogonality for the sake of good code density, even though this was derided as being "baroque
" by some computer scientists. The subsequent 32-bit extension of this architecture introduced with the 80386
, is in practice
fully orthogonal, despite keeping all 8086 instructions and their 32-bit counterparts. Traces from the 8080 can still be seen in the binary encodings though; for instance, the eax register use shorter encodings than the other registers on many operations, a fact which has sometimes been used for code optimization.
Into the RISC age
A fully orthogonal architecture may not be the most "bit efficient" architecture. In the late 1970s research at IBM
(and similar projects elsewhere) demonstrated that the majority of these "orthogonal" addressing modes were ignored by most programs. Perhaps some of the bits that were used to express the fully orthogonal instruction set could instead be used to express more virtual address
bits or select from among more registers.
In the RISC age, computer designers strove to achieve a balance that they thought better. In particular, most RISC computers, while still being highly orthogonal with regard to which instructions can process which data types, now have reverted to "load/store" architectures. In these architectures, only a very few memory reference instructions can access main memory and only for the purpose of loading data into registers or storing register data back into main memory; only a few addressing modes may be available, and these modes may vary depending on whether the instruction refers to data or involves a transfer of control (jump). Conversely, data must be in registers before it can be operated upon by the other instructions in the computer's instruction set. This tradeoff is made explicitly to enable the use of much larger register sets, extended virtual addresses, and longer immediate data (data stored directly within the computer instruction).