In computer engineering, an orthogonal instruction set is an instruction set architecture where all instruction types can use all addressing modes. It is "orthogonal" in the sense that the instruction type and the addressing mode may vary independently. An orthogonal instruction set does not impose a limitation that requires a certain instruction to use a specific register so there is little overlapping of instruction functionality.
Orthogonality was considered a major goal for processor designers in the 1970s, and the VAX-11 is often used as the benchmark for this concept. However, the introduction of RISC design philosophies in the 1980s significantly reversed the trend.
Modern CPUs often simulate orthogonality in a preprocessing step before performing the actual tasks in a RISC-like core. This "simulated orthogonality" in general is a broader concept, encompassing the notions of decoupling and completeness in function libraries, like in the mathematical concept: an orthogonal function set is easy to use as a basis into expanded functions, ensuring that parts don’t affect another if one part is changed.
Basic concepts
At their core, all general purpose computers work in the same underlying fashion; data stored in a main memory is read by the central processing unit (CPU) into a fast temporary memory (such as a set of CPU registers), acted on, and then written back to main memory. Memory consists of a collection of data values, encoded as numbers and referred to by their addresses, each also a numerical value. This means the same operations applied to the data can be applied to the addresses themselves. While being worked on, data can be temporarily held in processor registers, scratchpad values that can be accessed very quickly. Registers are used, for example, when adding up strings of numbers into a total.
Single instruction, single operand
In early computers, the instruction set architecture (ISA) often used a single register, in which case it was known as the accumulator. Instructions included an address for the operand. For instance, an <code>ADD address</code> instruction would cause the CPU to retrieve the number in memory found at that address and then add it to the value already in the accumulator. This very simple example ISA has a "one-address format" because each instruction includes the address of the data.
One-address machines have the disadvantage that even simple actions like an addition require multiple instructions, each of which takes up scarce memory, and requires time to be read. Consider the simple task of adding two numbers in memory, 5 and 4. In this case, the program would have to load the value 5 from memory into the accumulator with the <code>LOAD address</code> instruction, use the <code>ADD address</code> instruction pointing to the 4, and finally <code>SAVE address</code> to store the result, 9, back to another memory location. Most integer instructions operate on either 1-byte or 2-byte values 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 or memory. Even the PC and the stack pointer could be affected by the ordinary instructions using all of the ordinary data modes. "Immediate" mode (hardcoded numbers within an instruction, such as <code>ADD #4, R1</code> (R1 = R1 + 4) is implemented as the mode "register indirect, autoincrement" and specifying the program counter (R7) as the register to use reference for indirection and to autoincrement. (Encoded as <code>ADD (PC)+,R1 .word 4.</code>)
The PDP-11 uses 3-bit fields for addressing modes (0-7) so there are (electronically) eight addressing modes. An additional 3-bit field specifies the registers (R0–R5, SP, PC). Immediate and absolute address operands applying the two autoincrement modes to the program counter (R7), provide a total of ten conceptual addressing modes. Most two-operand instructions support all addressing modes for both parameters. Instructions such as 'ADD' were divided into data-size dependent variants such as ADDB, ADDW, ADDL, ADDP, ADDF for add byte, word, longword, packed BCD and single-precision 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).
In contrast, the NS320xx series were originally designed as single-chip implementations of the VAX-11 ISA. Although this had to change due to legal issues, the resulting system retained much of the VAX-11's overall design philosophy and remained completely orthogonal. This included the elimination of the separate data and address registers found in the 68k.
The 8080 and follow on designs
The 8-bit Intel 8080 (as well as the 8085 and 8051) microprocessor is basically a slightly extended accumulator-based design and therefore not orthogonal. An assembly-language programmer or compiler writer has to be mindful of which operations were possible on each register: Most 8-bit operations can be performed only on the 8-bit accumulator (the A-register), while 16-bit math can be performed only on the 16-bit pointer/accumulator (the HL-register pair). Simple operations, such as increment, are possible on all 8-bit registers and 16-bit register pairs. This was largely due to a desire to keep all opcodes one byte long.
The binary-compatible Z80 later added opcode prefixes to escape from this 1-byte limit and allow for a more powerful instruction set. The same basic idea was employed for the Intel 8086, although, to allow for more radical extensions, binary-compatibility with the 8080 was not attempted here. It maintained some degree of non-orthogonality for the sake of high code density at the time. The 32-bit extension of this architecture that was introduced with the 80386, is somewhat more orthogonal despite keeping all the 8086 instructions and their extended counterparts. However, the encoding-strategy still shows many traces from the 8008 and 8080 (and Z80). For instance, single-byte encodings remain for certain frequent operations such as push and pop of registers and constants; and the primary accumulator, the EAX register, employs shorter encodings than the other registers on certain types of operations. Observations like this are sometimes exploited for code optimization in both compilers and hand written code.
RISC
A number of studies through the 1970s demonstrated that the flexibility offered by orthogonal modes was rarely or never used in actual problems. In particular, an effort at IBM studied traces of code running on the System/370 and demonstrated that only a fraction of the available modes were being used in actual programs. Similar studies, often about the VAX, demonstrated the same pattern. In some cases, it was shown that the complexity of the instructions meant they took longer to perform than the sequence of smaller instructions, with the canonical example of this being the VAX's <code>INDEX</code> instruction.
During this same period, semiconductor memories were rapidly increasing in size and decreasing in cost. However, they were not improving in speed at the same rate. This meant the time needed to access data from memory was growing in relative terms in comparison to the speed of the CPUs. This argued for the inclusion of more registers, giving the CPU more temporary values to work with. A larger number of registers meant more bits in the computer word would be needed to encode the register number, which suggested that the instructions themselves be reduced in number to free up room.
Finally, a paper by Andrew Tanenbaum demonstrated that 97% of all the constants in a program are between 0 and 10, with 0 representing between 20 and 30% of the total. Additionally, between 30 and 40% of all the values in a program are constants, with simple variables (as opposed to arrays or such) another 35 to 40%. If the processor uses a larger instruction word, like 32-bits, two register numbers and a constant can be encoded in a single instruction as long as the instruction itself does not use too many bits.
These observations led to the abandonment of the orthogonal design as a primary goal of processor design, and the rise of the RISC philosophy in the 1980s. RISC processors generally have only two addressing modes, direct (constant) and register. All of the other modes found in older processors are handled explicitly using load and store instructions moving data to and from the registers. 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.
