An instruction set is a list of all the instructions that a processor can execute. Such instructions include arithmetic operations such as add and subtract, logical operations such as AND, OR and NOT, data instructions such as move, input and output, and control instructions such as goto, call and return. The instruction set specifies the opcodes (machine language operation codes) that are used to identify each instruction. The instruction set architecture (ISA) is largely independent of the microarchitecture used within the microprocessor itself. The Intel Pentium and the AMD Athlon, for example, implement almost identical versions of the x86 instruction set, but have vary different internal microarchitectures.
Historically, there have been several approaches used to store the instruction set inside the CPU, but these generally break down into two main approaches. All early computer designs (and some of the simpler RISC designs that came later) had the instruction set hard-wired into the CPU. Later, many designs implemented the instruction set as microcode within a separate ROM inside the CPU. The microcode used to implement a single machine code instruction consists of a number of microinstructions that are used to fetch, decode and execute the machine code instruction (or macroinstruction). The microcode may also be required to poll for hardware interrupts between each macroinstruction.
In the early days of computing, the cost of computer memory was very high, and the amount of memory available tended to be limited by this factor. Limiting the size of a program in memory was therefore an important consideration. Program size was influenced by the number and size of the instructions required to carry out a particular task. An instruction set with a high code density used powerful instructions that could perform several functions at once. Computers that used such an instruction set are called Complex Instruction Set Computers (CISC), and the instruction typically combine one or more basic operations such as add or multiply with the instructions required to access memory or update the contents of a CPU register.
The CISC approach made the best use of the available memory, but as more and more memory became available, Reduced Instruction Set Computers (RISC) began to appear that used a larger number of much simpler instructions to carry out program instructions. The resulting low code density meant that more memory space was required to store the program instructions for a given programming task, but the cost of the microprocessor could be reduced while performance (in terms of speed of operation) improved. The main disadvantage was to the programmer, who had to write more code to achieve the same goals.
Instruction sets may be categorised by the number of operands used in their most complex instructions. Early computers often used instruction sets that had only one operand. Each instruction performs its operation using a single operand, and places its result in a single accumulator (a CPU register in which intermediate arithmetic and logic results are stored). In the following example, the add operation is applied to the operand x:
Most RISC computers (and many CISC computers) use instructions that have two operands. In the following example, typical of a RISC computer, the contents of a memory location (x) are copied into a CPU register (reg1):
load x, reg1
Both CISC and RISC computers can have instructions that have three or more operands, although the more operands involved, the more bits are needed per instruction, so such schemes are usually only found on processors that have 32-bit (or above) instructions.
Some of the operation types available in most instruction sets include:
- Moving data - these instructions can be used to set a CPU register to a fixed constant value, or move data from a memory location to a register (or vice versa). They can be used to provide the data for a pending arithmetic or logic operation, store the result of a computation, or read and write data from a hardware device.
- Computational - this includes instructions that can be used to add, subtract, multiply, or divide the values of two CPU registers and place the result in another CPU register, to perform logical operations (e.g. AND, OR, NOT) on the contents of two CPU registers, or to compare the values stored in two CPU registers (e.g. to determine whether one value is less than, equal to, or greater than the second value).
- Program flow control - these instructions can be used to cause program execution to jump from one part of the program to another, either unconditionally or dependent on whether a certain condition is true. They include calls to subroutines, in which the address of the instruction immediately following the call instruction is preserved so that program execution can return to this point once the subroutine has been executed.