Tanenbaum's Structured Computer Organization says:

Every computer has an ISA (Instruction Set Architecture), which is a set of registers, instructions, and other features visible to its low-level programmers.

This ISA is commonly referred to as machine language, although the term is not entirely accurate.

A program at this level of abstraction is a long list of binary numbers, one per instruction, telling which instructions to execute and what their operands are.

My questions are:

  1. ISA includes instructions and registers. As far as I know, an instruction consists of an opcode (i.e. operation) and operand(s). Is an opcode too small to be an member in the ISA?

  2. As far as I know, a programming language is a set of some programs. So is a machine language also a set of some programs?

  3. What is the difference between ISA and machine language? Is it that a machine language is a set of programs, while a ISA is not a set of programs but a set of more basic units (e.g. registers, instructions) which together form programs?

  • What do you mean "a programming language is a set of some programs"? Do you mean the set of all programs that can be written using that language? Do note that's an infinite set, even if you remove filler sentences.
    – Andres F.
    Mar 3, 2015 at 23:30
  • Yes to your second question.
    – Tim
    Mar 3, 2015 at 23:33
  • As a quick concrete example to distinguish between the two: machine languages almost always have pseudo instructions. These are instructions that are actually a sequence of commands that are run on the CPU. Because the commands sent to the CPU (the ISA) is not identical to the commands typed in code (the machine language), you can say that they are not technically the same.
    – riwalk
    Mar 4, 2015 at 6:12

3 Answers 3


It looks like you borrowed some vocabulary from theoretical computer science (regarding the words "set" and "language"), and tried to use that to interpret the textbook description of the lower level computer systems (CPU and hardware).

The word "set" as in "instruction set architecture" refers to the set of predefined opcodes that are valid for the given CPU architecture.

For example, this page (x86 instruction listings, on Wikipedia) lists the opcodes one can expect on various generations of the IA32 architecture. Each opcode is a member in this "instruction set".

When the author says "... is not entirely accurate", my guess is that he is referring to the fact that there is no grammar one could expect from a sequence of machine instructions.

To clarify further, the CPU reads the instruction bytes, and if it is a valid machine instruction, it will be executed. Otherwise, typically an "invalid instruction" hardware exception will be generated, which will stop the current execution and transfer control to a different program (possibly belonging to the operating system).

However, there is no grammar that defines what is a valid sequence of machine instructions. In some sense, there is no structure or hierarchy that one can expect all valid sequences of machine instructions to conform to.

The machine instructions found in most compiled software programs are formed with some structure; however, not all of them do. The CPU will happily execute a "spaghetti sequence of machine instructions", performing unconditional or conditional jumps as it encounters each; and until recently, it is possible for a sequence of machine instructions to modify parts of itself.

Some CPU instructions are designed to facilitate structured programming:

  • the stack register and push / pop instructions
  • the return address register, and the call / return instructions for executing subroutines (also known as procedures or functions)
  • loop instructions (increment or decrement a register, checks against a limit, and then jumps to a specified address if the limit has not been reached)
  • string copy instructions (a loop instruction that repeatedly copies bytes from one address range to another address range)

Even though some of these instructions appear to form pairs (push vs pop, call vs return), in reality a valid sequence of machine instructions does not need to match these pairs. That is, one could write the next program counter value into the memory address pointed to by the stack register (simulating a push), and then perform a jump into the start of a subroutine (which, together with the previous push, becomes a simulation of a subroutine call). The subroutine could use the regular return instruction.


Note that Tanenbaum talks about what is exposed to low level programmers, not what happens at the level of CPU execution cycles. Down at that level are various micro operations that are involved in branch prediction, prefetch, pipelining, etc.

Machine code instructions get broken down into smaller chunks after the point where programmers have direct access.


The point is that the same Instruction Set can be used differently.

And in practice, for efficiency purposes, that may matter a lot. An optimizing compiler can (and will, e.g. GCC with -O2 -mtune=native) produce different machine code for the same ISA, depending on the target processor. So the code optimized for an Intel processor is not the same as the code optimized for a AMD processor, even if it uses the same ISA. Machine code optimized for one will not be the fastest code on the other one.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.