The first two editions of this book focused entirely on real mode segmented model, which was the mainstream programming model throughout the MS-DOS era, and still comes into play when you launch an MS-DOS window to run a piece of ''legacy'' software. It's a complicated, ugly system that requires you to remember a lot of little rules and gotchas, but it's useful to understand because it illustrates the nature and function of segments very clearly. Note that under both flat models you can squint a little and pretend that segments and segment registers don't really exist, but they are both still there and operating, and once you get into some of the more exotic styles of programming, you will need to be aware of them and grasp how they work.
In real mode segmented model, your program can see the full 1MB of memory available to the CPU in real mode. It does this by combining a 16-bit segment address with a 16-bit offset address. It doesn't just glom them together into a 32-bit address, however. You need to think back to the discussion of segments earlier in this chapter. A segment address is not really a memory address. A segment address specifies one of the 65,535 slots at which a segment may begin. One of these slots exists every 16 bytes from the bottom of memory to the top. Segment address 0000H specifies the first such slot, at the very first location in memory. Segment address 0001H specifies the next slot, which lies 16 bytes higher in memory. Jumping up-memory another 16 bytes gets you to segment address 0002H, and so on. You can translate a segment address to an actual 20-bit memory address by multiplying it by 16. Segment address 0002H is thus equivalent to memory address 0020H, which is the 32nd byte in memory.
But such multiplication isn't something you have to do. The CPU handles the combination of segments and offsets into a full 20-bit address internally. Your job is to tell the CPU where the two different components of that 20-bit address are. The customary notation is to separate the segment register and the offset register by a colon, as shown in the following example:
Each of these five register combinations specifies a full 20-bit address. ES:DI, for example, specifies the address as the distance in DI from the start of the segment called out in ES.
I've drawn a diagram outlining real mode segmented model in Figure 4-9. In contrast to real mode flat model (shown in Figure 4-8), the diagram here shows all of memory, not just the one little 64K chunk that your real mode flat model program is allocated when it runs. A program written for real mode segmented model can see all of real mode memory.
16-Bit Segment Addresses (Every 16 bytes in memory)
20-Bit Memory Addresses
Segment registers specify which paragraph boundary begins a segment. Segment registers do not contain memory addresses perse!
Segments need not be all the same size, and they may overlap.
Address pointed to is SS:SP
Address pointed to is ES:DI
Address pointed to is DS:SI
Next instruction executed is at CS:IP
You the programmer do not change code segments directly. "Long jump" instructions alter CS as needed.
Much of memory is taken up by the operating system and various buffers and tables dedicated to its use.
Segment 0 — Figure 4-9: Real mode segmented model
The diagram shows two code segments and two data segments. In practice you can have any reasonable number of code and data segments, not just two of each. You can access two data segments at the same time, because you have two segment registers available to do the job: DS and ES. (In the 386 and later processors, you have two additional segment registers, FS and GS.) Each can specify a data segment, and you can move data from one segment to another using any of several machine instructions. However, you only have one code segment register, CS. CS always points to the current code segment, and the next instruction to be executed is pointed to by the IP register. You don't load values directly into CS to change from one code segment to another. Machine instructions called jumps change to another code segment as necessary. Your program can span several code segments, and when a jump instruction (of which there are several kinds) needs to take execution into a different code segment, it changes the value in CS for you.
There is only one stack segment for any single program, specified by the stack segment register SS. The stack pointer register SP points to the memory address (relative to SS, albeit in an upside-down direction) where the next stack operation will take place. The stack requires some considerable explaining, which I take up in several places later in this book.
You need to keep in mind that in real mode, there will be pieces of the operating system (and if you're using an 8086 or 8088, that will be the whole operating system) in memory with your program, along with important system data tables. You can destroy portions of the operating system by careless use of segment registers, which will cause the operating system to crash and take your program with it. This is the danger that prompted Intel to build new features into its 80386 and later CPUs to support a ''protected'' mode. In protected mode, application programs (that is, the programs that you write, as opposed to the operating system or device drivers) cannot destroy the operating system or other application programs that happen to be running elsewhere in memory via multitasking. That's what the protected means.
Finally, although it's true that there was a sort of rudimentary protected mode present in the 80286, no operating system ever really used it, and it's not much worth discussing today.
Was this article helpful?