Microprocessor Design/Instruction Set Architectures
The instruction set or the instruction set architecture (ISA) is the set of basic instructions that a processor understands. The instruction set is a portion of what makes up an architecture.
Historically, the first two philosophies to instruction sets were: reduced (RISC) and complex (CISC). The merits and argued performance gains by each philosophy are and have been thoroughly debated.
Complex Instruction Set Computer (CISC) is rooted in the history of computing. Originally there were no compilers and programs had to be coded by hand one instruction at a time. To ease programming more and more instructions were added. Many of these instructions are complicated combination instructions such as loops. In general, more complicated or specialized instructions are inefficient in hardware, and in a typically CISC architecture the best performance can be obtained by using only the most simple instructions from the ISA.
The most well known/commoditized CISC ISAs are the Motorola 68k and Intel x86 architectures.
Reduced Instruction Set Computer (RISC) was realized in the late 1970s by IBM. Researchers discovered that most programs did not take advantage of all the various address modes that could be used with the instructions. By reducing the number of address modes and breaking down multi-cycle instructions into multiple single-cycle instructions several advantages were realized:
- compilers were easier to write (easier to optimize)
- performance is increased for programs that did simple operations
- the clock rate can be increased since the minimum cycle time was determined by the longest running instruction
The most well known/commoditized RISC ISAs are the PowerPC, ARM, MIPS and SPARC architectures.
We will discuss VLIW Processors in a later section.
We will discuss Vector Processors in a later section.
We will discuss computational RAM in a later section.
Instructions are typically arranged sequentially in memory. Each instruction occupies 1 or more computer words. The Program Counter (PC) is a register inside the microprocessor that contains the address of the current instruction. During the fetch cycle, the instruction from the address indicated by the program counter is read from memory into the instruction register (IR), and the program counter is incremented by n, where n is the word length of the machine (in bytes).
In addition to fetches of the executable instructions, many (but not all) instructions also fetch data values from memory ("load") into a data register, or write data values from a data register to memory ("store"). The address of the particular memory word accessed in such a load or store instruction is called the "effective address". In the simplest instruction sets, the effective address always contained in some address register. Other instruction sets have more complex "effective address" calculations — we will discuss such "addressing modes" later.
Move, Load, Store
Move instructions cause data from one register to be moved or copied to another register. Load instructions put data from an external source, such as memory, into a register. Store instructions move data from a register to an external destination.
Instructions that move (or copy) data from one place to another are the #1 most-frequently-used instructions in most programs.
Branch and Jump
Branching and Jumping is the ability to load the PC register with a new address that is not the next sequential address. In general, a "jump" or "call" occurs unconditionally, and a "branch" occurs on a given condition. In this book we will generally refer to both as being branches, with a "jump" being an unconditional branch.
A "call" instruction is a branch instruction with the additional effect of storing the current address in a specific location, e.g. pushing it on the stack, to allow for easy return to continue execution. A "call" instruction is generally matches with a "return" instruction which retrieves the stored address and resumes execution where it left off.
An "interrupt" instruction is a call to a preset location, generally one encoded somehow in the instruction itself. This is often used to reach commonly-used resources such as the operating system. Generally, a routine entered via an interrupt instruction is left via an interrupt return instruction, which, similarly to the return instruction, retrieves the stored address and resumes execution.
In many programs, "call" is the second-most-frequently used instruction (after "move").
The Arithmetic Logic Unit (ALU) is used to perform arithmetic and logical instructions. The capability of the ALU typically is greater with more advanced central processors, but RISC machines' ALUs are deliberately kept simple and so have only some of these functions. An ALU will, at minimum, perform addition, subtraction, NOT, AND, OR, and XOR, and usually also single-bit rotates and shifts. Many CISC machine ALUs can also perform multi-bit rotates and shifts (with a barrel shifter) and integer multiplication and division. While many modern CPUs can also do floating point mathematical operations, these are usually handled by the FPU, a different part of the machine. We describe the ALU in more detail in the ALU design chapter.
Input / Output
Input instructions fetch data from a specified input port, while output instructions send data to a specified output port. There is very little distinction between input/output space and memory space, the microprocessor presents an address and then either accepts data from, or sends data to, the data bus, but the sort of operations available in the input/output space are typically more limited than those available in memory space.
NOP, short for "no operation" is an instruction that produces no result and causes no side effects. NOPs are useful for timing and preventing hazards.
There are several different ways people balance the various advantages and disadvantages of various instruction lengths.
Fixed-length instructions are less complicated for a CPU to handle than variable-width instructions for several reasons, and are therefore somewhat easier to optimize for speed. Such reasons include: CPUs with variable-length instructions have to check whether each instruction straddles a cache line or virtual memory page boundary; CPUs with fixed-length instructions can skip all that. 
There simply are not enough bits in a 16 bit instruction to accommodate 32 general-purpose registers, and also do "Ra = Rb (op) Rc" -- i.e., independently select 2 source and 1 destination register out of a general purpose register bank of 32 registers, and also independently select one of several ALU operations.
And so people who design instruction sets must make one or more of the following compromises:
- sacrifice code density and use longer fixed-width instructions, typically 32 bit, such as the MIPS and DLX and ARM.
- sacrifice fixed-width instructions, requiring a more complicated decoder to handle both short 16 bit instructions and longer 3-operand instructions, such as ARM Thumb
- sacrifice 3-operands, using no more than 2 operands in all instructions for everything, such as the Atmel AVR. 3-operand instructions allow better reuse of data; without 3-operand instructions, programs occasionally require extra copy instructions when both variable input operands to some ALU operation need to be preserved for some later instruction(s).
- sacrifice registers, so only 16 or 8 programmer-visible registers.
- sacrifice the concept of general purpose register -- perhaps only 16 or 8 "data registers" are visible to 3-operand ALU instructions, as in the 68000, or the destination is restricted to one or two "accumulators", but other registers (such as "address registers") are visible to other instructions.
Any one particular machine-language instruction for any one particular CPU can typically be divided up into fields. For example, certain bits in a "ADD" instruction indicate the operation -- that this is actually an "ADD" rather than a "XOR" or "subtract" instruction. Other bits indicate which register is the source, other bits indicate which register is the destination, etc.
A few processors not only have fixed instruction widths but also have single instruction format -- a fixed set of fields that is the same for every instruction.
Many processors have fixed instruction widths but have several instruction formats. The actual bits stored in a special fixed-location "instruction type" field (that is in the same place in every instruction for that CPU) indicates which of those instruction format is used by this specific instruction -- which particular field layout is used by this instruction. For example, the MIPS processors have R-type, I-type, J-type, FR-type, and FI-type instruction formats. For example, the J1 processor has 3 instruction formats: Literal, Branch, and ALU. For example, the Microchip PIC mid-range has 4 instruction formats: byte-oriented register operations, bit-oriented register operations, 8-bit literal operations, and branch instructions with an 11-bit literal. 
Occasionally some new CPU has a different instruction set formats from some other CPU, making it "not binary-compatible" with that other CPU. However, sometimes this new CPU can be designed to have "source code backward-compatibility" with some other CPU -- it is "assembly-language compatible but not binary-compatible" with programs written some other CPU. (Such as, for example, the 8080 which was source-compatible but not binary-compatible with the 8008). (Such as, for example, the 8086 which was source-compatible but not binary-compatible with programs written for the 8085, the 8080, and the 8008).
- Practically all modern CPUs maintain the illusion of a program counter sequentially walking through code one instruction at a time. However, a few complex modern CPUs internally execute several instructions simultaneously (superscalar), or execute instructions out-of-order, or even speculatively pre-execute instructions down the "wrong" path, then back up and take the right path. When designing and testing such internal structures, the concept of "the" PC is a bit fuzzy. Some processor architectures, for instance the CDP1802, do not have a single Program Counter; instead, one of the general purpose registers is used as a program counter, and which register that is can be changed under program control.
- Peter Kankowski. "x86 Machine Code Statistics"
- The evolution of RISC technology at IBM by John Cocke – IBM Journal of R&D, Volume 44, Numbers 1/2, p.48 (2000)
- MIPS Assembly/Instruction Formats
- Victor Yurkovsky. "HOMEBREW CPUS: MESSING AROUND WITH A J1"
- "PICmicro MID-RANGE MCU FAMILY: Section 29. Instruction Set" Section 29.2 Instruction Formats.