Contents Up << >>

Registers

In 16-bit mode, such as provided by the Pentium processor when operating as a Virtual 8086 (this is the mode used when Windows 95 displays a DOS prompt), the processor provides the programmer with 14 internal registers, each 16 bits wide. They are grouped into several categories as follows:

Although I refer to the first four registers as "general-purpose'', each of them is designed to play a particular role in common use:

Here are brief descriptions of the four special-purpose registers:

Since all of these registers are 16 bits wide, they can only contain addresses for memory within a range of 64K (=2^16) bytes. To support machines with more than 64K of physical memory, Intel implemented the concept of segmented memory. At any given time, a 16-bit address will be interpreted as an offset within a 64K segment determined by one of the four segment registers (CS, DS, ES, and SS).

As an example, in the instruction MOV [BX], AX mentioned above, the BX register really provides the offset of a location in the current data segment; to find the true physical address into which the contents of the accumulator will be stored, you have to add the value in BX to the address of the start of the data segment. This segment start address is determined by taking the 16-bit number in DS and multiplying by 16. Therefore, if DS contains 1234h and BX contains 0017h, then the physical address will be 1234h TIMES 16+0017h=12340h+0017h=12357h. (This computation illustrates one reason why hexadecimal is so useful; multiplication by 16 corresponds to shifting the hex digits left one place and appending a zero.) We refer to this combined address as 1234:0017 or, more generally, as DS:BX.

Since segment starts are computed by multiplying a 16-bit number by 16=2^4, the effect is that physical addresses have a 20-bit range, so that a total of 1M (=2^20) of memory may be used. Intel considered that this would be enough for applications of the 8086 over its projected lifetime of about five years from its introduction in 1978; by the time microcomputers were needing more than a meg of main memory, the next Intel processor (the iAPX432) was due to be available, with a 32-bit address space (able to address 4G---over 4 billion memory locations). However, the IBM PC's debut in 1981 and subsequent popularity has forced Intel to continue the 80x86 family of backward-compatible processors to the present, including support for a mode in which only 1M of memory is accessible. Processors since the 80286 have also provided the "protected'' mode of operation, which in the Pentium gives each process a flat 32-bit address space of up to 4G.

You might think that a segment register would only need to provide the uppermost 4 bits to extend an address out to 20 bits, but consider one of the implications of only having 16 different, non-overlapping segments: every segment would have to occupy a full 64K of memory, even if only a small fraction of this space were needed. By allowing a segment to start at any address divisible by 16, the memory may be allocated much more efficiently---if one program only needs 4K for its code segment, then theoretically the operating system could load another program into a segment starting just 4K above the start of the first. Of course, MS-DOS is not really this sophisticated, but the Intel designers wanted it to be possible.

Each segment register has its own special uses:

The instruction pointer, IP, gives the address of the next instruction to be executed, relative to the code segment. The only way to modify this is with a branch instruction.

The status register, FLAGS, is a collection of 1-bit values which reflect the current state of the processor and the results of recent operations. Nine of the sixteen bits are used in the 8086:

There are numerous operations that will test and manipulate various of these flags, but to get the contents of the entire FLAGS register one has to push the flags onto the stack (with PUSHF or by calling an appropriate interrupt handler with INT) and then pop them off into another register. To set the entire FLAGS register, the sequence is reversed (with POPF or IRET). For example, one way to set the carry flag (there are much better ways, including the STC instruction) is the following:
        PUSHF
        POP     AX
        OR      AX, 1
        PUSH    AX
        POPF
Most of the time you will not have to deal with the FLAGS register explicitly; instead, you will execute one of the conditional branch instructions, Jcc, where cc is one of the following mnemonic condition codes: All of the conditions on the same line are synonyms. The Above and Below conditions refer to comparisons of unsigned numbers, and the Less and Greater conditions refer to comparisons of signed (two's complement) numbers.