You may be wondering how the CPU is programmed. It contains a special register—the instruction register—whose bit pattern determines what the CPU will do. Once that action has been completed, the bit pattern in the instruction register can be changed, and the CPU will perform the operation specified by this next bit pattern.
Most modern CPUs use an instruction queue. Several instructions are waiting in the queue, ready to be executed. Separate electronic circuitry keeps the instruction queue full while the control unit is executing the instructions. But this is simply an implementation detail that allows the control unit to run faster. The essence of how the control unit executes a program is represented by the single instruction register model.
Since instructions are simply bit patterns, they can be stored in memory. The instruction pointer register always has the memory address of (points to) the next instruction to be executed. In order for the control unit to execute this instruction, it is copied into the instruction register.
The situation is as follows:
A sequence of instructions is stored in memory.
The memory address where the first instruction is located is copied to the program counter.
The CPU sends the address in the program counter to memory via the address bus.
Memory responds by sending a copy of the state of the bits at that memory location on the data bus, which the CPU then copies into its instruction register.
The instruction pointer is automatically incremented to contain the address of the next instruction in memory.
The CPU executes the instruction in the instruction register.
Go to step 3.
The wfi (“wait for interrupt”) instruction places the CPU in an idle state, where it remains until an I/O device sends an interrupt signal to the CPU. We will give a very brief look at interrupts in Chapter 17, but the details are beyond the scope of this book. For now, it is sufficient to understand that the wfi instruction stops the program execution cycle.
Actually, the ARM fetches two instructions at a time. But this is an implementation detail that helps speed up program execution. The logical flow of a program follows the instruction execution cycle shown in Figure 8.4.1.
This raises a couple of questions:
How do we get the instructions into memory? The instructions for a program are stored in a file on a storage device; for example, a disk, device memory, or an SD card. The computer system is controlled by an operating system. When you indicate to the operating system that you wish to execute a program, e.g., by tapping on its icon on a touch screen, the operating system locates a region of memory large enough to hold the instructions in the program, and then copies them from the file to memory. The contents in the file remain unchanged.
How do we create a file on the disk that contains the instructions? This is a multi-step process using several programs. The programs and the files that each create are:
An editor is used to create source files.
The source file is written in a programming language, e.g., C++. This is very similar to creating a file with a word processor. The main difference is that an editor is based on plain characters, while a word processor formats the text. You see all the characters that you type in an editor, but a word processor includes many hidden formatting codes that define things like paragraphs, bold font, etc.
A compiler or assembler is used to create object files.
The compiler or assembler translates the programming language in a source file into the bit patterns that can be used by a CPU (machine language). The source file contents remains unchanged.
A linker is used to create an executable file.
Most programs are made up of several object files. For example, a GNU/Linux installation includes many object files that contain the machine instructions to perform common tasks. These are programs that have already been written and compiled. Related tasks are commonly grouped together into a single file called a library.
Whenever possible, you should use the short programs in these libraries to perform the computations your program needs rather that write it yourself. The linker program will merge the machine code from these several object files into one executable file.
You may have used an integrated development environment (IDE), e.g., Microsoft Visual Studio® or Eclipse™, which combines all of these three programs into one package where each of the intermediate steps is performed automatically. You use the editor program to create the source file and then give the run command to the IDE. The IDE will compile the program in your source files, link the resulting object files with the necessary libraries, load the resulting executable file into memory, then start your program. In general, the intermediate object files resulting from the compilation of each source file are automatically deleted from the disk.
In this book we will explicitly perform each of these steps separately so we can learn the role of each program—editor, assembler, linker—used in preparing the application program.