Computer Architecture

— Christopher Genovese and Alex Reinhart

Soon, we will be covering how to use the command line to control your computer. For this – and more generally for thinking about programming – it is helpful to step back and consider as context how a computer works.

Here’s a (somewhat simplified) picture of computer architecture:


The Components of Computer Architecture #

The Central Processing Unit (CPU) #

The CPU is the control center of the computer. It carries out the instructions given by computer programs for arithmetic, logic, system control, and input/output.

There are many CPU designs with different performance trade-offs. The main components of the CPU are:

Control Unit
manages the execution of instructions
Arithmetic Logic Unit
carries out arithmetic, logic, and bitwise operations
specialized, very fast storage used in executing instructions. Some registers have fixed uses and some are general purpose. There are only a few of these available.
a fast but limited memory space to speed computations
Memory Management Unit
helps the operating system manage memory resources (optional)
fixed program for initialization and startup

In modern CPUs, some or all of these components are on a single integrated circuit chip; at the very least, they are colocate on a common circuit board (the motherboard).

The Cache #

The cache is a small (kilobytes or megabytes) memory unit that is very fast: one or two orders of magnitude faster than main memory. It’s usually directly attached to the processor. It is used to store copies of data currently being used by the processor; the processor automatically decides which data should be in the cache and ensures the main memory is updated with any changes made to the cache.

The Bus #

Specialized communication circuitry that allows transfer of data among the various parts of the computer. A fast bus is as valuable as a fast CPU to get high performance.

Main Memory (RAM) #

A large, fast, random access storage area. Each slot in memory has a unique address, by which it can be read or written. There are different types of Random Access Memory, with different cost and performance characteristics.

RAM is volatile: its contents are lost as soon as the power is cut off. RAM can’t be used to store data permanently.

When you say you have 16GB of RAM, this is the memory you’re referring to.

External Storage (e.g., Hard Disks, USB Drives, …) #

A very large storage area that is very slow compared to memory. Rotating hard disks (and even solid-state drives) impose physical constraints on the order in which information can be accessed.

Ports #

Addressable access points to other peripheral devices, allowing expansion of the system in a general way. Special programs called device drivers manage the details of how these devices are controlled.

How Programs (aka Apps) Run #

At the lowest level, a program is a set of instructions in machine code, each instruction encoded in a fixed number of bits in the following form

opcode data-to-operate-on-if-any

The opcode is a number representing a specific operation that is hardwired into the CPU circuitry. The data operated on depends on the instruction and consists of register “names”, memory addresses, or numeric constants.

For example, here is a program for the Intel x86 processor to compute the GCD of two integers via Euclid’s algorithm:

55 89 e5 53  83 ec 04 83  e4 f0 e8 31  00 00 00 89  c3 e8 2a 00
00 00 39 c3  74 10 89 b6  00 00 00 00  39 d3 7e 13  29 c3 39 c3
75 86 89 1c  24 e8 6e 00  00 00 8b 5d  fc c9 c3 29  d8 eb eb 90

This is not easy to read or reason about, which is why we have programming languages! (To get a taste of programming “closer to the metal” I recommend you try a simple program in assembly language, which adds only the barest syntax to this machine code. Here’s the above program in assembly language, for reference:

   pushl %ebp                      jle  D
   movl  %esp, %ebp                subl %eax, %ebx
   pushl %ebx                   B: cmpl %eax, %ebx
   subl  $4, %esp                  jne  A
   andl  $-16, %esp             C: movl %ebx, (%esp)
   call  getint                    call putint
   movl  %eax, %ebx                movl -4(%ebp), %ebx
   call  getint                    leave
   cmpl  %eax, %ebx                ret
   je    C                      D: subl %ebx, %eax
A: cmpl  %eax, %ebx                jmp  B

When the CPU runs a program, it is given a starting address which points to the machine code of the program and it proceeds through the instructions, modifying registers and memory, interacting with external storage and with peripheral devices, and keeping track of where in the code it is.

The CPU uses special registers to manage the control of the program’s flow. For example, the program counter (PC) register (sometimes called instruction pointer, IP, or instruction address register, IAR) holds the next instruction to be executed. It is normally incremented with each instruction, but instructions like brances (conditionals), jumps, function calls, and function returns can change the PC register directly.

Similarly, the stack pointer (SP) points to an area in main memory that is used as a stack for temporary computation and storage, such as holding the arguments to a function before calling it. This is updated automatically for certain instructions.


Programs that run other programs #

The process of turning a program into machine code is (loosely) called compiling. A C++ compiler, for instance, parses and processes the potentially complex C++ code and produces an executable file containing the program in machine code.

But from a programmer’s perspective, we can write programs that parse and execute symbolic commands. These symbolic commands look just like programs, though written in some higher-level language. Thus, not every program we run in practice gets converted to machine code to run, though there is always a program running machine code underneath.

For instance, by specification, Java programs are converted into the “machine code” of an idealized, non-physical machine called the Java Virtual Machine (JVM), which is run by yet another program. A number of other languages produce JVM code as well and can be “run” by the same underlying program.

Similarly, scripting languages (Python, R, Ruby) have associated programs (python, Rscript, ruby) that run natively on the machine to process code in that particular language.

We’ll talk more about compilers, interpreters, and so on later in the course.

Files and Directories (aka Folders) #

A File is persistent collection of data that is treated as a distinct and identifiable object by the operating system. Files can be accessed by the system and by users (with the appropriate permissions).

A directory (aka folder) is a special file that holds a list of other files (including directories) that are “contained” in that directory.

Files and directories are arranged in a hierarchical file system through which each file has a unique “address” called its path. This file system is essentially a tree, and the path tells how to access the file from the root of the tree.

Thus, when you see a name (more specifically a path) like /Users/spock/logic-puzzles/Kolinahr, we are referring to the file Kolinahr contained within the directory logic-puzzles, which is contained in the directory spock, which is contained within the directory Users, which finally is contained in the root directory of the file system.

Graphical user interfaces for file systems (e.g., as shown under OS X or Windows) provide a physical metaphor. Files and directories are represented by icons (documents or folders). You navigate the file system by clicking on directories (folders) to see the files contained within. You “open” a file by clicking on the file. When we work with files on the command line or within a program, we will typically eschew this metaphor and refer to files by a more direct means.

The Role of the Operating System #

A user’s primary interaction with a computer comes from running programs that operate on memory, files, and peripheral devices (e.g., printers, screens, robots).

Representing/working with programs and files at the level of the system is incredibly complex.

For example, while your Word file looks like a single stream of characters and encodings, it may be represented on disk as a collection of widely separated chunks of data that must be linked. together to read the file.

Similarly, each running process on the system gets an allocation of part of main memory. But not all of the process’s storage might be kept in memory at a given time (as it can be huge). Parts are swapped in and out from disk as needed. The memory the program sees is actually virtual memory that is managed by the system.

The operating system is a special program running on the computer that acts as an interface between the system architecture that hides the system’s complexity from the programs and the user.

The operating system has access to the computer’s resources and manages them so that each program (and its programmer) sees a simple view of the available resources. Memory looks like a long, linear stretch of storage, files look contiguous, and the program sees itself as always running.

The operating system also makes available special operations (called system calls) by which a program can request and modify its resources or interact with peripheral devices.