Bits and bytes

The purpose of computers is to process information.

The smallest unit of information is called a bit. Bits may be either set (1) or cleared (0).

A sequence of bits is called a byte. The most common width (length) of a byte is 8 bits. Such bytes are called octets for precise definition, because bytes might as well be defined as having 5 or 10 bits.

For example, the octet 011011102 stores bits which are, in order: cleared, set, set, cleared, set, set, set, cleared. This sequence of bits does not mean anything on its own. One needs to define how to interpret such sequences of bits.

A common interpretation is an unsigned binary number. Each bit is assigned a value equal to 2n when set, and 0 when cleared, where n is the bit position. (Positions are counted from the last and starting from 0.) If we read 011011102 as an unsigned binary number, the byte then reads:
0 + 26 + 25 + 0 + 23 + 22 + 21 + 0 = 64 + 32 + 8 + 4 + 2 = 110.

Devices and memory

A computer is a set of interconnected computing devices. All of these devices store and manipulate information expressed in bytes. These bytes are stored in a part of the device called its memory.

The most important device in a computer (computing system) is the central processing unit (CPU). CPUs have access to two kinds of memory: registers and physical memory.

Registers are small units of memory within a CPU. Their width in bits depends on what kind of operation they take part in.

For example, let us define an arithmetic addition operation that operates on 64-bit registers. Their values are interpreted as unsigned binary integers. The operation takes two register arguments, A and B, adds their values, and stores the resulting sum in A.

Such operations are defined by a CPU’s instruction set. The instruction set together with other requirements and defintions compose an instruction set architecture, which is then implemented as a physical device (a specific CPU model).

Processor (CPU) instructions can either embed values directly within the instruction, refer to values stored within registers, or instruct the processor to store or load a value from physical memory.

Physical memory is a sequence of bytes. Position of a byte in the sequence is called its address.

Devices are connected to each other though a message bus. Each device is configured to occupy a certain range of memory addresses. Devices use the bus in order to pass messages to each other. The most notable messages tell the other device to load (fetch) or save (store) bytes within their memory, which is referenced by a physical memory address.

For example, if random acccess memory (RAM) is configured to reside at addresses since 1024 to 10240 and the CPU sends a message to the bus for loading a byte at address 2048, the RAM will respond to that message with the byte that has been mapped to that address. Mapping is the translation of an address from one memory space to another, in this case from the physical memory space to the RAM’s internal space.

Programs

Every CPU has a register called the instruction pointer. This register contains the physical memory address of the next instruction. When an instruction is loaded (from physical memory), this address is incremented by the length of the instruction, advancing the pointer to the next instruction. This cycle repeats since the CPU is powered on until it is powered down.

Instructions that change the value of the instruction pointer are called jump instructions, because they cause the CPU to ‘jump’ to a specific instruction instead of advancing to the next one.

Every CPU also implements instructions for checking conditions (such as a test whether a value in a register is equal to 0) and conditional jump instructions which change the value of the instruction pointer only if the condition has been met.

Instructions are grouped into sections called routines. Routines are written so that the CPU jumps from one routine to another. A collection of one or more routines is called a program.

A function is a specific kind of a routine, which jumps back to the routine from which it was called from. If a function is defined to have parameters, it means that the routine expects a specific state of registers at the time its execution begins. The same applies to the return value. Before jumping back, a function stores a value in a specific register.

Which registers are used, how and when is defined by a set of rules called a calling convention. Each program chooses a convention and complies with it, so that other programs (written by someone else) may call its functions.

Firmware

The initial address loaded into the instruction pointer when a device is powered on is specifc to and varies by device.

The value is an address of the device’s firmware, which is a program that initializes and controls the device.

Firmware in devices such as personal computers (PCs) loads a program from a hard disk, inserted optical media or other storage device. The firmware then jumps to the program, effectively passing on the responsibily of controlling the device to the loaded program.

This process is called bootloading. It may be chained – the loaded program loads another program and jumps to it in the same fashion as the firmware did initially. This happens on older PCs where the first program is very short.

On complex machines such as personal computers or smartphones, the last loaded program is usually the kernel of an operating system.

Operating systems

An operating system is a collection of programs and a set of rules that programs written for the system must all follow.

Within this set of rules is the application binary interface. Part of this interface is the calling convention used by the system. The ABI also defines the layout of data structures used by the system.

The most crucial program in an operating system is its kernel. The kernel has full control over the computer and its main purpose is execution and management of other programs - its tasks. It manages their memory and separates their execution context in order to protect devices and other tasks against them. Programs may be created with a malicious intent or simply contain errors.

In a multi-tasking operating system tasks have a time limit. When the task reaches its limit, the kernel saves the state of the current task and switches to the next one in the queue. The now-current task continues from the previously saved point.

For task switching to occur, a CPU must support interrupts. Upon reception of an interrupt request, the CPU saves the instruction pointer and loads into it an address of an interrrupt handler routine. The handler finishes by instructing the CPU to load the saved value of the instruction pointer back and continue executing the interrupted program.

Interrupt requests may come from other devices or be caused by instructions. The time limit for tasks is usually implemented by setting a timer device to issue an interrupt request when a specific amount of time passes. This time is usually measured in micro- or nanoseconds, giving the illusion that all the tasks execute ‘at the same time.’

That said, modern CPUs do execute few programs at the same time, if the CPU is configured to do so – by default it executes only one.