It's the "great idea" that sounds great 5 min in and horrible 10min afterwards
You know, kinda like using null as a string end character
But more importantly it kept the x86 world for too long in that dead end that was 8086 mode programming
"Oh if developers would just..." They won't. They haven't. And they will not ever.
In hindsight maybe a binary level translator from 8080 to 8086 would have worked better (and be simple enough)
billpg•Jun 21, 2026
Indeed, I say as much at the end.
But what should Intel have done? They needed a CPU that can run 8080 code but with more memory. Also it's the year ~1980 and we're limited to the technology of the age.
A system with 64k sized windows seems unavoidable.
If you extend the size of the address registers, 8080 code will only run in the first 64k, or require some kind of current window register.
An 8080 mode might have worked but that would have been expensive.
flohofwoe•Jun 23, 2026
> Also it's the year ~1980 and we're limited to the technology of the age.
Tbf the Motorola 68000 which was released around the same time (1979) had a proper linear address space with 32-bit address registers (of which 24 bits were wired up).
Also the 8086 was intended as a cheap and temporary stop gap until Intel's "proper" 32-bit CPU architecture was ready for prime time (the doomed iAPX 432).
smallstepforman•Jun 23, 2026
New platforms were 68000, old platforms with legacy code just wanted access to more memory, so 8086 segments allowed 64kb chunks. A hack only usable by folks that still wanted to run their old 64kb programs.
It would be a piece of trivia today if motorola were not 6 months late which forced IBM in frustration to change tracks to Intel and MS DOS instead (which worked on 8086). That 6 month drlay created WinTel of today.
nwallin•Jun 23, 2026
The Motorola 68000 was roughly an order of magnitude more expensive than the Intel 8086.
torusle•Jun 21, 2026
> In hindsight maybe a binary level translator from 8080 to 8086 would have worked better (and be simple enough)
Many programs written in assembly language used self modifying code back then. It saved RAM and improved performance. All programs that used such trickery would have broken by a binary translator.
flohofwoe•Jun 23, 2026
It's not all that different from the memory pages we have today, except that the 'segment' addressing has become a lot more complex under the hood (multi-level page tables) and a lot simpler at the surface (by merging the 'segment-' and page-address bits into a single virtual address).
PS: and segmented memory wasn't all that different from the memory banking used before in 8-bit home computers to address more than 64 KBytes, except that the memory mapping hardware was implemented outside the CPU.
amiga386•Jun 23, 2026
> It's not all that different from the memory pages we have today
An MMU gives you a flat addressing model. There is no comparison. 8086 segments are rigidly locked to a 64KB window that goes forward in memory 16 bytes for every segment (so segmented address 1234:5678 is linear address $12340 + $5678 = $179B8)
It didn't do this to offer a useful feature like an MMU. It did this to allow code that doesn't know segment registers exist to think they're still running on an 8-bit Z80. What a waste of potential. The 68000 didn't pretend to be a 6502.
The 80286 introduced protected mode with "segment descriptors", but this is well after MMUs existed on other CPUs, it didn't invent virtual memory. Only the 80386 offered a 32-bit flat memory model.
If you want to see something to make you weep, look at the MS-DOS version of unzip. It has to do all kinds of crazy, just to allocate 64KB of RAM and get all 64KB, not 8 bytes less. And it's still locked into a memory access model that will not let it ever address more than 64KB of any one object. It's why MS-DOS was viewed as a toy OS for a toy computer.
#if defined(__TURBOC__) && !defined(OS2)
#include <alloc.h>
/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
* and farmalloc(64K) returns a pointer with an offset of 8, so we
* must fix the pointer. Warning: the pointer must be put back to its
* original form in order to free it, use zcfree().
*/
...
static ptr_table table[MAX_PTR];
/* This table is used to remember the original form of pointers
* to large buffers (64K). Such pointers are normalized with a zero offset.
* Since MSDOS is not a preemptive multitasking OS, this table is not
* protected from concurrent access. This hack doesn't work anyway on
* a protected system like OS/2. Use Microsoft C instead.
*/
rep_lodsb•Jun 23, 2026
That's a limitation of the Turbo C library, as the comment says. DOS memory allocation functions take the size in 16-byte "paragraphs", and return a segment, with the allocated memory starting at offset zero in that segment.
mschaef•Jun 23, 2026
The 8086 was a stopgap measure to accommodate the fact the iAPX432 was in the middle of turning into the disaster it did. Given the engineering resources and timelines involved in the 8086, it wasn't a bad compromise approach.
> But more importantly it kept the x86 world for too long in that dead end that was 8086 mode programming
>
> "Oh if developers would just..." They won't. They haven't. And they will not ever.
8086 real mode programming in the mainstream lasted from 1981 until 1991 or so. The last 35 years have 32-bit (and later 64-bit) flat model addressing with pages for the most part. Seems like a reasonable transition period, really.
> In hindsight maybe a binary level translator from 8080 to 8086 would have worked better (and be simple enough)
Part of the reason they liked the segmented model is that it was possible to set the segments to the same value and then ignore them entirely. That gave a programming model for the 8086 that was sufficiently close to the 8080 that it was possible to use a sort of cross assembler to do something like what you suggest. You could then opt into 8086 specific instructions and segmentation as you needed. (Which took a few years... the first IBM PC's shipped with as little as 16K of RAM.)
wewewedxfgdf•Jun 23, 2026
Don't know why you're being voted down - you're correct - segmented memory was an awful nasty complex way to program and the industry was eager to see the backside of it.
Why would someone be popping up in 2026 saying it was awesome? Weird.
tliltocatl•Jun 21, 2026
It might have worked better if x86 had general-purpose registers where every register could work as a segment. Or maybe just many more segment registers. But with only two data segment registers to play with and quite cubersome (and slow!) loads, most software just chose not to bother.
musicale•Jun 22, 2026
Google's native client (NaCl) even used it on 32-bit x86...
Segmented memory (on hardware that supported segment permissions) was used to good effect in Multics as well.
gpderetta•Jun 23, 2026
x86 32 bit protected mode segments were a very different beast.
hexmiles•Jun 23, 2026
What is the difference between the segmentation model used by Intel and the banking model used by a lot of consoles? I've worked with the code of a couple of NES and GBC games, and while banking could be annoying, I never saw it as a particularly difficult model to follow and use. It did require more planning for the various functionality, but it wasn't even the most complex or difficult thing about developing for consoles.
flohofwoe•Jun 23, 2026
It's pretty much the same thing, except that all the memory mapping logic has moved from 'custom memory mapping hardware' into the CPU.
rzzzt•Jun 23, 2026
Banking also appeared on the platform in the form of EMS.
Someone•Jun 23, 2026
> and while banking could be annoying, I never saw it as a particularly difficult model to follow and use
Segments aren’t conceptually difficult, either, but definitely could be annoying, and certainly were, if you had to access data structures larger than 64 kB.
As to the differences:
- you had four segment registers that you could ‘point’ anywhere, allowing you to access four 64kB regions of memory without changing them (the equivalent of bank switching) (one always was used for accessing the instruction to run, one for accessing the stack, but you could use those for other purposes, too (Could, not SHould)
- segments can overlap. You could set DS and ES to the same value, for example.
Segments also can be moved at 16-byte granularity. If you wanted, you could have DS address address memory range 0x0000 ≤ x < 0xFFFF and SS address memory range 0x0010 ≤ x < 0x1000F.
pjc50•Jun 23, 2026
Banking is different in that the banks swap in and out. The 8086 segments were all available at the same time once you loaded the segment register, and they overlapped.
Banking was one solution to the 1MB limit; was it extended or expanded mode? I can no longer remember, but one of those gave you a 64kb window somewhere above the 640kb limit in the address space not used by either video RAM or BIOS. That window could then be paged around the rest of memory.
trollbridge•Jun 23, 2026
Expanded memory is identical to banking. It wasn’t particularly popular since it’s a pain to program and compilers never got around to automatically generating code for it.
RiverCrochet•Jun 23, 2026
On the NES, most mappers would control which 16Kbyte blocks from the PRG ROM appeared in the upper ($C000) or lower ($8000) block of the NES ROM space. Often the upper block was fixed because of IRQ/RES/NMI vectors. I think later mappers allowed 8K blocks. So you only had those fixed windows at those fixed granularities, not the 16-byte granular sliding window 8086 offered.
I don't know about DMG/GBC/GBA games. Some very interesting stuff happened on those platforms (e.g. Game Boy Camera, and some game that lets you control a sewing machine in Japan?) and I bet a pure sliding window mapper exists.
The PC Engine/Turbografx-16 had platform support for mapping (specific CPU instructions did it) but it was 8 fixed windows in the CPUs 64K address space that pointed to 8K size offsets in the ROM I believe. SNES had a 24-bit address space and DMA to copy things to VRAM so not sure mappers were really on that platform.
st_goliath•Jun 23, 2026
> 8086 Segmented Memory Was a Good Idea.
Yet the article goes about the most ass backward way of explaining 8086 segments and constructs a convoluted mental picture of dividing memory into overlapping chunks.
It's really, really simple: segments on the 8086/88 are 64k sliding windows into an 1M address space. You can move them around at 16 byte granularity.
You need more than 64k for code + data? No problem, the CPU knows when it's fetching an instruction vs when it's fetching data, you can have two sliding windows: code (CS) and data (DS). Split them apart, and it's not much different than a Harvard-style machine and gives you access to more than 64k at a time.
Still need more? No problem, the CPU has a hardware stack with dedicated push/pop/call/ret instructions and a base pointer for stack indexing. It knows when it's accessing the stack, so we can split the data window into regular data (DS) and stack data (SS). Oh, you occasionally want to copy stuff between segments or somewhere else in memory? Well, to encode 3 segments we need 2 bits anyway, let's throw in an extra data window (ES) and some DS-to-ES copy instructions.
gdwatson•Jun 23, 2026
It was a clever hack for porting existing code. But it doesn’t scale at all – you’ve just described adding four registers to a register-starved architecture in order to solve the issue for one CPU generation or so.
rob74•Jun 23, 2026
Plus all this pointer juggling would have been more or less ok (or not ok, but doable) when programming in assembly, but for a compiler it would have been a recipe for disaster...
bluGill•Jun 23, 2026
I'm sure a modern compiler would have no problem with it, but in 1980 optimizer technology wasn't there yet. Modern compilers use more memory that engineers would dare dream of in 1980.
By having no problem I mean we know enough about writing an optimizer to write such a thing. I don't think any compiler does, just that they could.
trollbridge•Jun 23, 2026
Compilers in 1980 generated 64k code segments and had no other memory model.
Most people wrote assembler particularly if they wanted to use more then 64k.
Most non assembly programs were interpreted oddly enough and most such interpreters were also mostly 64k.
peterfirefly•Jun 23, 2026
Segment prefixes were rarely needed and you didn't need to spend any of the precious mod/rm bits on segment registers. The GPR count was limited to 8 partly because of the 3 bits allocated to specifying them and partly because of limited die space. Segment registers only added slightly to the latter cost.
juancn•Jun 23, 2026
Yeah, but it was probably the right call at the time.
Backward compatibility was a breath of fresh air at a time were code needed constant porting and rewriting. No two machines were alike.
It's one of the reasons the PC became so popular.
AshamedCaptain•Jun 23, 2026
I think you are missing the entire point of the article (which I kinda agree with), and just repeating the popular wisdom.
In the era a machine with "object addressing" sounded like a perfectly valid futuristic design (what a Lisp machine strived to be; I guess today you would call it tagged memory of some kind). The 8086 is not that, but the original design would have allowed to evolve it into something like that.
The article's point is that since programmers simply treated it as a sliding window (instead of an opaque object handle), the plan could not be implemented, and the half-assed thing became stuck.
Having seen other Intel RISC designs, I fully agree with the premise.
AnimalMuppet•Jun 23, 2026
But with only four segment registers, you couldn't treat it as that - not unless you only had four objects. So treating it as a sliding window was all you actually could do with it.
bonzini•Jun 23, 2026
With 6-7 general purpose registers you could have; since anyway only three of them were usable for addressing you constantly had to load from memory. just use MOV ES instead of MOV BX to load a pointer and you actually got to increase your GPRs by one or two. Nobody did it except for larger memory areas which were allocated using farmalloc() or the INT 21h allocator.
trollbridge•Jun 23, 2026
x86 has 7 general purpose registers.
Using a bare segment register as a pointer was quite common. That’s what the DOS memory allocation call would return.
AshamedCaptain•Jun 23, 2026
That's almost like saying that with 2 registers you can only do additions with 2 operands. True, but missing the picture. The number of segments is not limited by the number of segment registers, or even (gasp!) by the number of segment descriptors.
AKSF_Ackermann•Jun 23, 2026
The segment model seems clever if you assume that you never have an object that is larger than 64kb. And once you have that you need to care about segment overflow, pointer comparisons no longer work, everything now has to carry around segment+offset instead of just offset, and so on. And if you want an example of a >=64kb object - the html alone for that page is one.
rep_lodsb•Jun 23, 2026
A lot of that is just bloat that you wouldn't have had back then. But it could still be handled by an 8086, not by storing the raw HTML in memory at all, but parsing it as it loads. Each DOM node would be its own object with child pointers, with attributes and names all converted into binary numbers of (at most) 32 bits each.
64K of actual text content in a single node could be reached in some documents, but it's not that small, more than a chapter of a typical book.
What was always a problem for segmented memory was graphics, at least if you wanted higher resolution than 320x200 at 256 colors. But you could have a segment pointer to each row of pixels instead of an entire image, as long as it would still fit within 1 MB (16 MB in the 286 protected mode).
AKSF_Ackermann•Jun 23, 2026
True, graphics is a better example of a period-correct >=64k work, but the point is that there are multiple things where you don't expect the data to be that big until it suddenly is.
billpg•Jun 23, 2026
Why would you ever want a single 64k object? That's like an entire machine's worth of memory!
carry_bit•Jun 23, 2026
It's basically a 16-bit machine with PAE; 32-bit with PAE runs into similar issues if you want an object larger than 4GB.
senfiaj•Jun 23, 2026
For its time it was a decent idea. Software was smaller and simpler. But today (and even before 64-bit) software is larger, more complex, we also need memory protection / isolation and more flexible memory allocation / sharing, so paging memory was not introduced for nothing.
flohofwoe•Jun 23, 2026
> we also need memory protection / isolation
I seem to remember that memory segments came with a permission system (read-only, read/write, execute) in 'protected mode'. Probably only added in the 286 though (I was always more of an m68k guy at that time).
senfiaj•Jun 23, 2026
Maybe (I think it's possible in protected mode), but it still has an allocation problem, imagine there are programs A, B, C in the memory. Later, A and C are unloaded, leaving 2 free holes, totaling in 2MB. Now you want to load a 2MB program, but there is no unfragmented 2MB free block. The only solution I see, is to shift some loaded programs, which might be slow and even risky. Paging makes this problem much easier. Also, paging makes permissions and memory sharing more granular.
mschaef•Jun 23, 2026
There is no such thing as a "2MB program".... all you have is a program composed of <=64K segments, which are easy enough to fit into the hole.
If you do need something approaching a 2MB block of memory, you don't need a contiguous range of memory, what you need is a contiguous range of selectors, which is a different (and probably easier) problem to solve.
PunchyHamster•Jun 23, 2026
but without virtual memory you can't move them around and so program that wants to allocate 2MB of 64k segments can't run if there is no 2MB continuos hole
mschaef•Jun 23, 2026
I should preface this by saying I'm taking about x86 segmentation in general. On the 8086 you're right, but the 8086 can't address 2MB of memory to begin with. On the 80286 in protected mode, the situation is different in the way I'm about to describe.
The memory itself doesn't have to be contiguous.
2MB of 64K segments maps to 32 segments. So you need 32 locations in physical memory capable of storing 64K.
The programming model for addressing that block of memory necessarily includes both segment selectors and offsets. The segment selectors are indices into a segment table that contains the base address of each of the 32 segments. As long as the segment selectors themselves can be allocated contiguously in the segment table, you have enough to be able to compute which segment you need for which address in the 2MB range. It's the indirection through the segments table that maps it to physical addresses that do not need to be contiguous.
And this is the problem, it was very painful just to walk through a 200 KB buffer. This required compiler/runtime tricks, different selector increments in real vs protected mode, and special pointer types. Paging later made this kind of thing look like one flat array, a thing segmentation could not: making non-contiguous physical RAM appear contiguous to the program.
mschaef•Jun 23, 2026
> And this is the problem, it was very painful just to walk through a 200 KB buffer. This required compiler/runtime tricks, different selector increments in real vs protected mode, and special pointer types.
Most of that could be (and often was) hidden by the tooling. If you needed to bypass it, you could, but you didn't need to. That's not very different from today... there's a lot of hidden magic that can be bypassed if you need to for whatever reason.
I'd argue that these are useful engineering abstractions that made the best of a less than ideal situation. (The reality of the world being that there are no "ideal" situations... you have to work with what you have at the moment to solve the problem you have. These days, I'd argue that a pointer into a 'flat' memory space is counter productive to the extent it hides issues around cache hierarchy, NUMA, etc. In 1986, we had to worry that a flat memory space looked discontiguous. In 2026, we have to worry the a discontiguous memory space looks flat.
senfiaj•Jun 23, 2026
>> In 2026, we have to worry the a discontiguous memory space looks flat.
Well, there are large/huge pages (2MiB/4MiB/1GiB) that reduce this problem.
AnimalMuppet•Jun 23, 2026
OK, but we spent a decade having to worry about this garbage, until the tooling finally caught up. You always had to keep it in the back of your mind if you wrote PC software. Even if you just ran PCs, you had to worry about the compatibility between your OS, your "DOS extender", and your programs.
There were literally millions of man-hours wasted on segment registers. A kludge that helped Intel conquer the world, but what a filthy, disgusting architecture, and what a waste of everybody's time and brain power.
mschaef•Jun 23, 2026
> OK, but we spent a decade having to worry about this garbage, until the tooling finally caught up.
This was less about tooling than it was about economics - there was 32-bit hardware available in the personal computer space in 1984, if not before. The issue was cost. In today's currency, a 32-bit capable Mac was $8,000 with 128K. The first 32-bit capable PC was closer to $20,000.
That's a heavy lift in a world where a segmented architecture machine costs a fraction of that amount, runs software you might already have, and works the same way as your co-worker's machine.
> There were literally millions of man-hours wasted on segment registers.
A software developer in 1986 was not forced to deal with segment registers... but they often chose to deal with them to gain access a (much) bigger audience of potential customers for their software.
> A kludge that helped Intel conquer the world, but what a filthy, disgusting architecture, and what a waste of everybody's time and brain power.
The other side of the coin is that (for reasons I state above), segmented architectures got more capable software into more hands more quickly. It arguably did a lot for end users.
pjc50•Jun 23, 2026
I was under the impression that the permissions only kicked in once you were in 32-bit mode on the 386, what Windows called "386 Enhanced" mode.
justincormack•Jun 23, 2026
Wasm with multiple linear memories is basically segmented memory. Its a great security model.
PunchyHamster•Jun 23, 2026
It made fundamental mistake of starting as 32 bit memory model
actionfromafar•Jun 23, 2026
It puts some drag on bloat, I quite like it.
trollbridge•Jun 23, 2026
God help us all when a webpage needs > 4GB.
tlb•Jun 23, 2026
Some of mine do. They use WASM64 with threads to run robotics simulations.
trollbridge•Jun 23, 2026
That’s an “acceptable” use.
justincormack•Jun 23, 2026
You can use multiple segments (now, you couldnt originally)
wewewedxfgdf•Jun 23, 2026
I seem to recall at the time that flat memory was self evidently a better idea. It's not like people were sitting around going "gee I can't think of any better way to do memory addressing that this" until some genius suggests "how about flat?!?!?" Everyone knew flat was best but were stuck with 8086 crap.
PaulHoule•Jun 23, 2026
Personally I enjoyed writing assembly with segments. You can have 64k of code, 64k of data and 64k of stack without trying. So long as no individual data structure is larger than 64k there is no essential difficulty working with 16 bit pointers.
When I think back I think it would be fun to have a hierarchical structure where composite data structures (think an array or hash map) are referred to with a pointer that goes into the segment register and you index inside a data structure with a regular pointer.
trollbridge•Jun 23, 2026
Lots of 8086 code was written that way. You’d use the segment register on paragraph alignment and basically take advantage of the << 4 + logic.
This code was a nightmare to port to protected mode 80286 so it went away by the Windows 3.1 era.
KellyCriterion•Jun 23, 2026
-- Everyone knew flat was best but were stuck with 8086 crap.--
This! Thats one of the most interesting things to me: Actually very often in the IT-world, the worst competitor won the race while better solutions were known and available:
Microsoft, Intel etc.
Esp. that MS won for decades while making mainly a very bad OS, though they have some good enterprise products.
How would the world look, if Unix/BSD would have won this race?
wewewedxfgdf•Jun 23, 2026
Being technically best has long been known to not be correlated to market success in the way that makes logical sense to technical people who feel confused about this.
Ekaros•Jun 23, 2026
I really wonder if Unix is best we can do. Or is it also worst? So in the end two of the worst options won. It did make sense back in time. But could it have been replaced with something better later?
wewewedxfgdf•Jun 23, 2026
>> two of the worst options won
What do you mean, which are the two? Sure, Windows is crappy by Linus and MacOS? They are both awesome.
simiones•Jun 23, 2026
There are many crappy design decisions in Unix, Posix, Linux, MacOS, that have been known and worked around for decades (see the Unix Hater's Handbook). One example would be async IO, which has been famously bad in Unix, and Linux alone has tried 2 different generations of solutions - with the newer one, io_uring, being suspiciously similar to Windows' decades old IOCP. Fork/exec is infamous as a needlessly complex process creation API, requiring huge effort in the kernel just to handle the most common case of simply launching a new process. The traditional Unix security paradigm of simple user based file permissions is extremely weak and has required numerous solutions on top to handle realistic security scenarios - e.g. to protect a user's files from being tampered in unexpected ways by a process launched by that user (SELinux, jails, namespaces, etc).
I agree that Windows is crappy, but that doesn't mean that Linux and MacOS aren't also crappy in their own ways (not to mention iOS, Android).
KellyCriterion•Jun 23, 2026
Especially the enshittification over the decades:
All the bloat (XBog Game Icon on Win Server - really?), their update politics tangled with higher hardware specs for running the same stuff slower than before.
I do not understand how can one crash their own product/baby that way - and no, this must be Hanlors Razors: They are doing it with (sophisticated) intend, not by accident (or coincidence)
bux93•Jun 23, 2026
Linux is only used as a kernel temporarily until GNU is finished.
simiones•Jun 23, 2026
You mean GNU Hurd, I guess.
JdeBP•Jun 23, 2026
The operating system was going to be called GNU.
Don't open this can of worms. (-: There were endless discussions of this in the 1990s. Years's worth.
Scroll down to the 'What Is the Hurd?' section of this announcement post from 1996 and pay particular attention to its first and last sentences. That's the allusion here.
Adding more features to OS is for some use cases a benefit, for other it's a barrier. For one it might be less work to get what you want ,for other it might be more code between you and hardware that just slows it down
Unix-like simplicity is exactly that, for some use cases directness is a benefit, for others it means extra work to do on top to get what you want.
If you just want a house, getting a raw foundation to work with is a lot to build on top, you have to bring the rest of the walls up yourself.
But if you want exactly the house you want, getting entirely different house to start with and changing it is far more work than starting from simple foundation and building up.
Overall unix "here is relatively simple operating system that doesn't force you but needs some things to be built on top to hit your use case" probably IS the best abstraction, despise not being "best" at really anything. There is reason we build houses from concrete and wood, and not carbon fiber and titanium alloys
amiga386•Jun 23, 2026
There have been some very nice OSes in the past (e.g. AmigaOS, BeOS, QNX, Plan 9) that all failed to the Wintel juggernaut. MacOS only just made it out alive.
I wouldn't say Unix itself is the best. It suffered a war between competing implementations pushing their own proprietary components. POSIX is the compromise.
But, ultimately, what is good about it today is not so much "Unix" (the proprietary OS from Bell Labs and its heritage), but specifically Linux and the BSDs. Why? Because they are actually open. They are freedom incarnate. You can add anything you like to them, today, without asking any permission. Not just their kernels, but their userlands too (Linux obviously varies by distro here). There's even a chance you can get your changes adopted upstream (unless it's GNOME), much more than you'd ever get from a proprietary company's OS.
So, while there's always room for improvement on the technical aspects of the OS, the social and political aspects of Linux and the BSDs make them the best we can achieve as a society.
JdeBP•Jun 23, 2026
There was a Microsoft operating system for protected mode 80286 in 1983. It was Xenix 286; it was basically 7th Edition Unix without the branding; and it was touted as the multiuser operating system that MS-DOS would be the gateway to. How would the world look if Microsoft had won the race? (-:
trollbridge•Jun 23, 2026
A PC with DOS was cheaper than a PC with Xenix, let alone a typical Unix machine. Also much easier to learn to use.
Macs also existed but were expensive. The PC with DOS was both powerful and cheap.
Someone•Jun 23, 2026
Not entirely self-evidently. Position independent code was slower at the time and avoiding having to patching function addresses at load time is a net win.
More importantly, there’s backwards compatibility. By the time the 8086 came out, people had spent serious money on getting binary-only software (WordStar cost hundreds of dollars, for example). “Buy this computer, and you can keep running the software you paid for, but faster” was a good selling point.
rickas•Jun 23, 2026
I wonder why couldn't Intel simply introduce single 'offset' register for apps ported from 8080, and make all other registers 20-24bit. Why bother with 4 different registers and all that segmentation nightmare?
trollbridge•Jun 23, 2026
Lots of benefits to a word size a power of 2.
Very few benefits to a clunky 24 or 20 bit word size; now it costs more and is a bizarre boutique architecture in a world where it needs to compete with 8 bit Z80s and 6502s.
alerighi•Jun 23, 2026
Except than later we returned to a sort-of segmented memory. That is of course paging, our programs allocates pages of memory that are a fixed size (4096 bytes) and are arranged in memory or in swap space how the OS decides.
We just have the illusion of a "flat" memory model, but it's not really flat, the CPU and the operating system does an important job in translating our flat memory model in something that is not flat at all. All that address translation work could have been avoided if we accepted to not have a flat memory model and be aware that our memory is divided in pages.
Basically we are doing in hardware the job of managing a non flat memory space that the programmer, or well, the compiler (or these days you would say the AI agent) could probably to better because it knows how to allocate things to avoid being them on page boundaries, and all of this to give the illusion to the programmer that it's working with a flat memory (except when it does something wrong and gets a segmentation fault, that, as the name suggests, is an hint that at the end the memory is not really flat).
bluGill•Jun 23, 2026
In turn though, the thinking needed to handle non-flat memory is a complexity that most programmers cannot handle - and even those who could probably should spend their brain power on the complex parts of their program not managing memory. Best to leave that hard part to a few experts instead of make everyone understand it.
The above is very similar to the argument that you should use a garbage collected langauge.
trollbridge•Jun 23, 2026
Anyone writing an algorithm that needs to be high speed has to start thinking about caches and so forth. So it’s not exactly obsolete.
Back in 1980 most programs were being written in interpreted languages that did all the hard work of memory for you - just like today.
wang_li•Jun 23, 2026
Paging is not part of the CPU architecture. On CPUs of the time the MMU that brought paging to the party often was a completely separate peripheral that the CPU interacted with to gate access to RAM. By contrast segments are an integral part of the CPU instruction set and your code either has to limit itself to 64KB or your application had to be aware of and include logic to manage segments.
As an aside, the memory model is flat, it's just not physically linear when implementing virtual memory addressing.
phkahler•Jun 23, 2026
I was drooling over the MC68000. I had a pre-release reference manual from 1979 and it was the most awesome chip around. Atari and Commodore and Apple used it after their 6502 systems. Arcade games used it after their 6502 and 6809 days. The only reason x86 became popular was because IBM put it in the PC - not for any technical reasons.
trollbridge•Jun 23, 2026
A 68k was roughly double the cost of an 8086, plus the additional cost for the rest of the supporting chips.
The PC was intended to be cheap and was competing with 8 bit machines. Being 16/20 bit made it already high end.
If you wanted 24 or 32 bit, IBM had many other machines to sell you. Or you could just buy a VAX.
ThrowawayR2•Jun 23, 2026
Flat memory was a better idea but it wasn't a cheaper idea, and cheaper beats good. A casual Googling shows a price of $2,880 for a IBM PC in ~1982 dollars versus $8,900 for a Sun Microsystems Sun-1 with a MC68000.
amiga386•Jun 23, 2026
That was just Sun's market segment.
Also from a casual Google, an IBM PC launched in 1985 (picking the XT 5160-078 as an example) was around $4,995 at launch. Compare that to two 68000-based computers also launched in 1985: the Amiga 1000 launched at $1,295 and the Atari 520ST launched at $600.
These computer system prices - Sun, IBM, Commodore, Atari - came from the market segments the manufacturers aimed to sell to, rather than a cost saving enabled by cumbersome memory models.
The cumbersome memory model is just a historical accident; the 8086 designers wanted 8080 backwards compatibility so they could sell to former 8080 users, IBM did not require this. IBM would've picked the 68000 had it been "production ready" at the time, they did not reject flat memory on cost grounds!
trollbridge•Jun 23, 2026
Flat is not necessarily a better idea. In 1978, a 32 bit CPU would be stupidly expensive. The use case for > 64k was to simply have code and data split apart, and also have some MMIO, so basically 192k-256k of addressing needed.
Segmentation meant programs could remain essentially 16 bit with all the benefits to that like smaller code size.
b800h•Jun 23, 2026
I quite enjoyed using the memory segments - I thought they were quite intuitive and helped in reasoning about the machine.
RagnarD•Jun 23, 2026
I had to use it to do image processing on a 256MB image buffer back in the 1980s in assembly language. It was absolutely hideous. Give me a flat 32 bit memory address space any day (e.g. MC68000 around the same time.)
mschaef•Jun 23, 2026
> I had to use it to do image processing on a 256MB image buffer back in the 1980s in assembly language.... Give me a flat 32 bit memory address space any day (e.g. MC68000 around the same time.)
Huh?
There were no segmented x86 machines capable of addressing 256MB of RAM, aside from the 386 (maybe).
If you had a 386 and the $130K of memory your statement implies, you probably also could afford a Unix (or something else) license to get to that 32-bit address space. (If you weren't doing it all in memory, then you're having to depending on paging stuff out to disk, implying you either have a real OS or a flat memory model isn't enough to save you since you're manually having to page stuff to disk and back anyway.)
That's a super strange scenario you're describing.
porridgeraisin•Jun 23, 2026
Perhaps they meant KB?
mschaef•Jun 23, 2026
That would make more sense. I was trying to imagine what sort of (custom?) hardware would accommodate that amount of memory back then. That was large storage even for mainframes the time. (The Cray 2 in the mid-1980's had 2GB, which was considered notably large.)
sumtechguy•Jun 23, 2026
Probably talking about swapping it in from some external datastore. These days you would open the file and dump it into a single buffer and rip across it, and not even really stress about it. Even 256 meg of hard drive. That would have been impressively expensive in the 80s.
Back then you had to chunk it out and fiddle with the offsets. Even then you still would have had to manage loading out the next chunk.
If my memory is right 1MB of memory in the early 90s was like 200-300 per meg. Would have to dig up a computer shopper and look.
mschaef•Jun 23, 2026
> Even 256 meg of hard drive. That would have been impressively expensive in the 80s.
I only have a couple reference points around this scale:
My dad's company had a system set up with a searchable index of a bunch of legal testimony. It was a Compaq Deskpro 386 running Unix with an attached 1GB disk. The 1GB disk set up was as big as the machine itself.
A few years later, I worked with a Cyber mainframe equipped with around 30GB of total attached disk storage. The disk array literally filled a room.
256MB disk on an 80's PC would have definitely been quite a bit.
bigstrat2003•Jun 23, 2026
I remember my dad bought a 500MB hard drive for our Apple IIgs. It cost like $500-600 as I recall, not cheap by any means. I remember thinking that no way would we ever fill it up - which, to be fair, we never did. 500MB would fill up instantly now, but programs and data were so much smaller back then that it lasted until the computer eventually stopped being used.
PunchyHamster•Jun 23, 2026
Author comes from some weird assumption that software is some annoying byproduct of making hardware, rather than a fact that the hardware is made to run software and making it easier is a goal.
It was just a hack. Hack to delay migration to 32 bit architecture. Effective one, but hack nonetheless
NoGravitas•Jun 23, 2026
I think it's more like marking a transition in how we thought about software.
When I was learning C, we did things at a reasonably low level. I was learning data structures, and building things like binary trees out of things like structs, and the structs were fixed-sized memory blocks holding pointers to regions of memory which were either more structs or data fields. All reasonable stuff. But we weren't writing for a particular machine. We were writing for the idea of a machine, and part of that idea was that the machine had a flat memory model. This really struck me when I compiled my homework (parse some data into a tree) on the departmental SunOS server, and it worked fine, and then took it home and compiled it with Borland C for DOS on my 386 and it segfaulted on the same data. That was when I learned to hate segmented memory, but looking back, it seems to me that I learned the wrong lesson.
I learned to write software for a lowish-level model of an idealized computer. The generation before me was always writing software for a specific computer, consisting of a specific set of hardware. The software was always the goal, but the nature of the task was defined by the hardware. Things like memory segmentation were facts about the hardware, and the available hardware varied widely at the time in a way modern hardware doesn't, really, except maybe in the embedded space.
peterfirefly•Jun 23, 2026
Could have been fixed with an ADC-type instruction that operated on segments.
Imagine if you could have done something like this:
add si, some-delta
adsc es, 0
in order to move a seg:ofs ptr forward by 'some-delta' bytes.
ADSC (add with segment carry) would do:
segreg := segreg + imm + 1000h (if carry)
or:
segreg := segreg + imm (no carry)
Maybe there should also have been an instruction to normalize a seg:ofs ptr (so the new offset was in the 0-15 range).
ADSC could have been adapted for the 286 with ease, as long as a specific layout of the segment descriptor tables was mandated (probably with 10h instead of 1000h in protected mode).
Edited slightly for clarity (ofs => imm).
A normalizing instruction would be harder to do right for the 286 because you don't want to spend too many slots in the descriptor table(s) for a single memory object.
j16sdiz•Jun 23, 2026
> What we needed, in hindsight, was to treat segments as true selectors — opaque handles with no arithmetic meaning. If you can’t assume the next segment is 16 bytes ahead, you’re forced to use segmentation as intended.
Except we couldn't.
If we made each segment isolated from other, we would waste so much memory because memory are allocated in segment.
If we made each segment dynamic, we need something to manage them.
This "hindsight" is just a MMU in disguise.
deepsummer•Jun 23, 2026
1992-me hates the author. Coming from 68k assembly, x86 was a nightmare. And together with the ridiculous number of registers, segments made up a huge chunk of that horrible experience.
billpg•Jun 23, 2026
1992-author (me) is wondering if he'll ever get a girlfriend.
(And I completely agree.)
projektfu•Jun 23, 2026
What? It has 4 times as many general purpose registers as you'd ever need, right? /s
deftio•Jun 23, 2026
Agree.. 68k assembly was dreamy compared to 80x86..
BearOso•Jun 23, 2026
He's referring to accumulator styles, eg. the 6502.
forinti•Jun 23, 2026
I knew a bit of 6502 assembly, so I was happy just to have more RAM and more registers.
Looking back, the simplicity of the instruction set seems quaint next to the thousands of instructions we have today.
pif•Jun 23, 2026
> Need more than 64KB? Allocate two blocks.
How is that compatible with an array and a simple implementation of the index operator?
pjc50•Jun 23, 2026
It isn't.
This was a problem.
trollbridge•Jun 23, 2026
Not really. Compilers had huge pointers. They just were slower since they had to do 32 bit math.
billpg•Jun 23, 2026
I once developed for PC-GEOS, which wanted all memory in exactly 8K sized blocks. I wrote a set of C macros that presented an array-of-arrays as a single collection by using mod/divide operations on the index.
waynecochran•Jun 23, 2026
I blame 8086 segmented memory and the rest of its horrid architecture on why no one liked programming in assembly language. There were other elegant RISC machines with flat memory models and large general register sets that were a complete joy to program. Memory paging allowed you to do everything you needed to do that segmented memory provided and left the programmer unbothered for the most part.
deftio•Jun 23, 2026
Totally agree.
noitemtoshow•Jun 23, 2026
Nope. It was bad. It made computers in the 286/386 eras having RAM above 1MB sitting there and doing nothing. It took years to transit to DOS/4G and then finally 32bit OS Windows 95.
Wow.... I remember writing 8086 assembly on MASM and another assembler I've forgotten the name of, and then also doing inline ASM in Turbo C++
The segment thing and the convoluted different pointer math caused real gymnastics if you ever had data bigger than 64k... such as images.
I always thought of the segments as windows of 64k but moving between those windows, esp with the limited register set, required some real mental gymnastics.
trollbridge•Jun 23, 2026
Contemporary hardware rarely had images over 64k and memory bandwidth at the time made them a laughable concept.
trollbridge•Jun 23, 2026
Did anyone else find the AI written style of this offputting?
The original 20 bit vision of the 8086 was when memory was very expensive and they expected typical high end machines to have 128K of memory.
Intel’s assembler was designed so you could have up to 128K of code with a “shared” segment in the middle that either side could reach with near (16 bit only) pointers to call commonly shared routines, and more rarely executed code existed on either end.
In addition data could be its own segment, and/or memory mapped I/O outside of the 128K space.
But memory got so cheap that nobody bothered with this, and the performance gains of writing code that way wasn’t worth the effort. X86 code was compact enough most programs could cram their code into 64k anyway, or 64k per functional unit with calls between them being rare.
The real tragedy is they went for 20 bit instead of 24 bit. 8086 with 16MB of addressable space would have been a very different world and would have made little difference if there use. (Paragraphs would have been 256 bytes, the same size as a page; most data structures would have been fine with that.)
billpg•Jun 23, 2026
Hi. I wrote it, and I'm a human. (Or at least I think I am.)
I did use an AI for spell-checking, punctuation, generally making it flow, but its all my text.
You think a machine is going to come up with "near pointers, far pointers, wherever-you-are pointers"?
chowells•Jun 23, 2026
"generally make it flow" is exactly the problem. It's a process of smoothing over any interesting features of the text to replace them with plastic. It's submerging the actual information you wish to convey under a layer of low-entropy noise. The whole signal may still be there, but having to find it under a uniform glossy finish is work for the reader. It's work you didn't need to delegate to the reader.
LLMs generate low-entropy text. That's their entire purpose. But good writing isn't about being as low-entropy as possible. It's about producing peaks and valleys. As a person who's been participating in human-to-human communication your entire life, you probably have a pretty well-developed sense of how to structure the flow of a piece of communication. The small arcs with their ebbs and flows of tension and density provide the reader a rough surface that gives them enough traction to easily move from point to point. Don't let an LLM smooth out all the gaps. It makes it hard for a reader to keep their footing in the text.
saulpw•Jun 23, 2026
> As a person who's been participating in human-to-human communication your entire life, you probably have a pretty well-developed sense of how to structure the flow of a piece of communication.
Not OP, but this is where you're wrong. The vast majority of people, myself included, have difficulty structuring communication for effectiveness to a wide audience. When I manage to pull it off I'm very proud of the work, but I can't just sit down and do it. Review with an LLM helps me find those places where it CLANKS, distracting the reader, taking them out of the flow. This is why every professional writer has an editor; good communication is quite hard.
nvme0n1p1•Jun 23, 2026
He's not writing the bible. He's writing a blog post about segment registers. It's fine if there's a sharp edge here or there. You're probably better at communication than you think, and your readers are probably less picky than you're imagining. An occasional sharp edge in your text is not the end of the world.
trollbridge•Jun 23, 2026
Thanks for responding. The problem is:
- the “make it flow” made it flow in an AI generated way like short paragraphs that are one short sentence.
- I now have to decide if this is entirely AI generated and thus not worth my time reading or not.
- I would prefer to just interact with you as a real person; your writing doesn’t have to be perfect for what you write to be worth reading.
billpg•Jun 23, 2026
shrug
I've reviewed what I originally wrote and I prefer the text I published. Sure, I could review it all myself (indeed I used to) but that takes time and it was becoming a barrier to actually publishing stuff. Maybe I'd have got around to finishing it in a few months.
I don't use AI to write for me. I hate people who do that.
M95D•Jun 23, 2026
They could have used 16 bit segments with no overlap. It would have a 16 bit offset register + a 16 bit segment selector register with the top 12 bits reserved (always 0). 16 bit software would run as usual in a single segment, while larger programs would use both registers for 20 bit addresses.
286 could then use the next 4 bits from the segment register to allow 16 MB address space and 386 could use all of them for 4GB. And wouldn't it be nice if 386 had 64KB pages (1 segment)?
bonzini•Jun 23, 2026
That wouldn't have worked, the point was to pack data in memory. Even on 64kb computers, MS-DOS 1.x loaded .COM files at the bottom of available memory and allowed using the "familiar" CALL 5 interface even if the program was not loaded at physical address 0x100 (which is part of the interrupt table on x86). MS-DOS 2.x augmented that with TSR (terminate and stay resident) programs that could relocate themselves to use the minimal amount of memory at 16-byte offsets.
The 68000 was a complete break so it opted for relocatable code (which also needed more registers, and in fact the 68k had 16 instead of 8).
billpg•Jun 23, 2026
I kinda wish they had. 64k windows with no overlap would make segment registers a slightly inconvenient 32-bit address register.
I get why hey didn't. Someone might want to run two processes each with its own segment, but the whole machine might only have 64k in total.
richard_todd•Jun 23, 2026
The author assumes the way to keep segments going with larger memory would have been to change the amount of overlap, but it would have also been possible to make an 80286 where the segment registers were > 16bits, and everything else is 16 bits like before. Now you have extra segments that are still paragraphs apart and existing software could still function (you'd need new instruction variants to move data into and out of the enlarged portion of the segment registers.. call them ECS, EDS, or whatever). Anyway, just a thought.
22 Comments
No, it wasn't
It's the "great idea" that sounds great 5 min in and horrible 10min afterwards
You know, kinda like using null as a string end character
But more importantly it kept the x86 world for too long in that dead end that was 8086 mode programming
"Oh if developers would just..." They won't. They haven't. And they will not ever.
In hindsight maybe a binary level translator from 8080 to 8086 would have worked better (and be simple enough)
But what should Intel have done? They needed a CPU that can run 8080 code but with more memory. Also it's the year ~1980 and we're limited to the technology of the age.
A system with 64k sized windows seems unavoidable.
If you extend the size of the address registers, 8080 code will only run in the first 64k, or require some kind of current window register.
An 8080 mode might have worked but that would have been expensive.
Tbf the Motorola 68000 which was released around the same time (1979) had a proper linear address space with 32-bit address registers (of which 24 bits were wired up).
Also the 8086 was intended as a cheap and temporary stop gap until Intel's "proper" 32-bit CPU architecture was ready for prime time (the doomed iAPX 432).
It would be a piece of trivia today if motorola were not 6 months late which forced IBM in frustration to change tracks to Intel and MS DOS instead (which worked on 8086). That 6 month drlay created WinTel of today.
Many programs written in assembly language used self modifying code back then. It saved RAM and improved performance. All programs that used such trickery would have broken by a binary translator.
PS: and segmented memory wasn't all that different from the memory banking used before in 8-bit home computers to address more than 64 KBytes, except that the memory mapping hardware was implemented outside the CPU.
An MMU gives you a flat addressing model. There is no comparison. 8086 segments are rigidly locked to a 64KB window that goes forward in memory 16 bytes for every segment (so segmented address 1234:5678 is linear address $12340 + $5678 = $179B8)
It didn't do this to offer a useful feature like an MMU. It did this to allow code that doesn't know segment registers exist to think they're still running on an 8-bit Z80. What a waste of potential. The 68000 didn't pretend to be a 6502.
The 80286 introduced protected mode with "segment descriptors", but this is well after MMUs existed on other CPUs, it didn't invent virtual memory. Only the 80386 offered a 32-bit flat memory model.
If you want to see something to make you weep, look at the MS-DOS version of unzip. It has to do all kinds of crazy, just to allocate 64KB of RAM and get all 64KB, not 8 bytes less. And it's still locked into a memory access model that will not let it ever address more than 64KB of any one object. It's why MS-DOS was viewed as a toy OS for a toy computer.
> But more importantly it kept the x86 world for too long in that dead end that was 8086 mode programming > > "Oh if developers would just..." They won't. They haven't. And they will not ever.
8086 real mode programming in the mainstream lasted from 1981 until 1991 or so. The last 35 years have 32-bit (and later 64-bit) flat model addressing with pages for the most part. Seems like a reasonable transition period, really.
> In hindsight maybe a binary level translator from 8080 to 8086 would have worked better (and be simple enough)
Part of the reason they liked the segmented model is that it was possible to set the segments to the same value and then ignore them entirely. That gave a programming model for the 8086 that was sufficiently close to the 8080 that it was possible to use a sort of cross assembler to do something like what you suggest. You could then opt into 8086 specific instructions and segmentation as you needed. (Which took a few years... the first IBM PC's shipped with as little as 16K of RAM.)
Why would someone be popping up in 2026 saying it was awesome? Weird.
Segmented memory (on hardware that supported segment permissions) was used to good effect in Multics as well.
Segments aren’t conceptually difficult, either, but definitely could be annoying, and certainly were, if you had to access data structures larger than 64 kB.
As to the differences:
- you had four segment registers that you could ‘point’ anywhere, allowing you to access four 64kB regions of memory without changing them (the equivalent of bank switching) (one always was used for accessing the instruction to run, one for accessing the stack, but you could use those for other purposes, too (Could, not SHould)
- segments can overlap. You could set DS and ES to the same value, for example.
Segments also can be moved at 16-byte granularity. If you wanted, you could have DS address address memory range 0x0000 ≤ x < 0xFFFF and SS address memory range 0x0010 ≤ x < 0x1000F.
Banking was one solution to the 1MB limit; was it extended or expanded mode? I can no longer remember, but one of those gave you a 64kb window somewhere above the 640kb limit in the address space not used by either video RAM or BIOS. That window could then be paged around the rest of memory.
I don't know about DMG/GBC/GBA games. Some very interesting stuff happened on those platforms (e.g. Game Boy Camera, and some game that lets you control a sewing machine in Japan?) and I bet a pure sliding window mapper exists.
The PC Engine/Turbografx-16 had platform support for mapping (specific CPU instructions did it) but it was 8 fixed windows in the CPUs 64K address space that pointed to 8K size offsets in the ROM I believe. SNES had a 24-bit address space and DMA to copy things to VRAM so not sure mappers were really on that platform.
Yet the article goes about the most ass backward way of explaining 8086 segments and constructs a convoluted mental picture of dividing memory into overlapping chunks.
It's really, really simple: segments on the 8086/88 are 64k sliding windows into an 1M address space. You can move them around at 16 byte granularity.
You need more than 64k for code + data? No problem, the CPU knows when it's fetching an instruction vs when it's fetching data, you can have two sliding windows: code (CS) and data (DS). Split them apart, and it's not much different than a Harvard-style machine and gives you access to more than 64k at a time.
Still need more? No problem, the CPU has a hardware stack with dedicated push/pop/call/ret instructions and a base pointer for stack indexing. It knows when it's accessing the stack, so we can split the data window into regular data (DS) and stack data (SS). Oh, you occasionally want to copy stuff between segments or somewhere else in memory? Well, to encode 3 segments we need 2 bits anyway, let's throw in an extra data window (ES) and some DS-to-ES copy instructions.
By having no problem I mean we know enough about writing an optimizer to write such a thing. I don't think any compiler does, just that they could.
Most people wrote assembler particularly if they wanted to use more then 64k.
Most non assembly programs were interpreted oddly enough and most such interpreters were also mostly 64k.
Backward compatibility was a breath of fresh air at a time were code needed constant porting and rewriting. No two machines were alike.
It's one of the reasons the PC became so popular.
In the era a machine with "object addressing" sounded like a perfectly valid futuristic design (what a Lisp machine strived to be; I guess today you would call it tagged memory of some kind). The 8086 is not that, but the original design would have allowed to evolve it into something like that.
The article's point is that since programmers simply treated it as a sliding window (instead of an opaque object handle), the plan could not be implemented, and the half-assed thing became stuck.
Having seen other Intel RISC designs, I fully agree with the premise.
Using a bare segment register as a pointer was quite common. That’s what the DOS memory allocation call would return.
64K of actual text content in a single node could be reached in some documents, but it's not that small, more than a chapter of a typical book.
What was always a problem for segmented memory was graphics, at least if you wanted higher resolution than 320x200 at 256 colors. But you could have a segment pointer to each row of pixels instead of an entire image, as long as it would still fit within 1 MB (16 MB in the 286 protected mode).
I seem to remember that memory segments came with a permission system (read-only, read/write, execute) in 'protected mode'. Probably only added in the 286 though (I was always more of an m68k guy at that time).
If you do need something approaching a 2MB block of memory, you don't need a contiguous range of memory, what you need is a contiguous range of selectors, which is a different (and probably easier) problem to solve.
The memory itself doesn't have to be contiguous.
2MB of 64K segments maps to 32 segments. So you need 32 locations in physical memory capable of storing 64K.
The programming model for addressing that block of memory necessarily includes both segment selectors and offsets. The segment selectors are indices into a segment table that contains the base address of each of the 32 segments. As long as the segment selectors themselves can be allocated contiguously in the segment table, you have enough to be able to compute which segment you need for which address in the 2MB range. It's the indirection through the segments table that maps it to physical addresses that do not need to be contiguous.
Raymond Chen talks a bit about how it worked in Windows 3.x here: https://devblogs.microsoft.com/oldnewthing/20171113-00/?p=97...
This was just for illustration, not claiming that actual 8086 does this.
>> Raymond Chen talks a bit about how it worked in Windows 3.x here: https://devblogs.microsoft.com/oldnewthing/20171113-00/?p=97...
And this is the problem, it was very painful just to walk through a 200 KB buffer. This required compiler/runtime tricks, different selector increments in real vs protected mode, and special pointer types. Paging later made this kind of thing look like one flat array, a thing segmentation could not: making non-contiguous physical RAM appear contiguous to the program.
Most of that could be (and often was) hidden by the tooling. If you needed to bypass it, you could, but you didn't need to. That's not very different from today... there's a lot of hidden magic that can be bypassed if you need to for whatever reason.
I'd argue that these are useful engineering abstractions that made the best of a less than ideal situation. (The reality of the world being that there are no "ideal" situations... you have to work with what you have at the moment to solve the problem you have. These days, I'd argue that a pointer into a 'flat' memory space is counter productive to the extent it hides issues around cache hierarchy, NUMA, etc. In 1986, we had to worry that a flat memory space looked discontiguous. In 2026, we have to worry the a discontiguous memory space looks flat.
Well, there are large/huge pages (2MiB/4MiB/1GiB) that reduce this problem.
There were literally millions of man-hours wasted on segment registers. A kludge that helped Intel conquer the world, but what a filthy, disgusting architecture, and what a waste of everybody's time and brain power.
This was less about tooling than it was about economics - there was 32-bit hardware available in the personal computer space in 1984, if not before. The issue was cost. In today's currency, a 32-bit capable Mac was $8,000 with 128K. The first 32-bit capable PC was closer to $20,000.
That's a heavy lift in a world where a segmented architecture machine costs a fraction of that amount, runs software you might already have, and works the same way as your co-worker's machine.
> There were literally millions of man-hours wasted on segment registers.
A software developer in 1986 was not forced to deal with segment registers... but they often chose to deal with them to gain access a (much) bigger audience of potential customers for their software.
> A kludge that helped Intel conquer the world, but what a filthy, disgusting architecture, and what a waste of everybody's time and brain power.
The other side of the coin is that (for reasons I state above), segmented architectures got more capable software into more hands more quickly. It arguably did a lot for end users.
When I think back I think it would be fun to have a hierarchical structure where composite data structures (think an array or hash map) are referred to with a pointer that goes into the segment register and you index inside a data structure with a regular pointer.
This code was a nightmare to port to protected mode 80286 so it went away by the Windows 3.1 era.
This! Thats one of the most interesting things to me: Actually very often in the IT-world, the worst competitor won the race while better solutions were known and available: Microsoft, Intel etc.
Esp. that MS won for decades while making mainly a very bad OS, though they have some good enterprise products.
How would the world look, if Unix/BSD would have won this race?
What do you mean, which are the two? Sure, Windows is crappy by Linus and MacOS? They are both awesome.
I agree that Windows is crappy, but that doesn't mean that Linux and MacOS aren't also crappy in their own ways (not to mention iOS, Android).
I do not understand how can one crash their own product/baby that way - and no, this must be Hanlors Razors: They are doing it with (sophisticated) intend, not by accident (or coincidence)
Don't open this can of worms. (-: There were endless discussions of this in the 1990s. Years's worth.
Scroll down to the 'What Is the Hurd?' section of this announcement post from 1996 and pay particular attention to its first and last sentences. That's the allusion here.
* https://groups.google.com/g/gnu.announce/c/d0N2mLo5dxk/m/bDq...
Adding more features to OS is for some use cases a benefit, for other it's a barrier. For one it might be less work to get what you want ,for other it might be more code between you and hardware that just slows it down
Unix-like simplicity is exactly that, for some use cases directness is a benefit, for others it means extra work to do on top to get what you want.
If you just want a house, getting a raw foundation to work with is a lot to build on top, you have to bring the rest of the walls up yourself.
But if you want exactly the house you want, getting entirely different house to start with and changing it is far more work than starting from simple foundation and building up.
Overall unix "here is relatively simple operating system that doesn't force you but needs some things to be built on top to hit your use case" probably IS the best abstraction, despise not being "best" at really anything. There is reason we build houses from concrete and wood, and not carbon fiber and titanium alloys
I wouldn't say Unix itself is the best. It suffered a war between competing implementations pushing their own proprietary components. POSIX is the compromise.
But, ultimately, what is good about it today is not so much "Unix" (the proprietary OS from Bell Labs and its heritage), but specifically Linux and the BSDs. Why? Because they are actually open. They are freedom incarnate. You can add anything you like to them, today, without asking any permission. Not just their kernels, but their userlands too (Linux obviously varies by distro here). There's even a chance you can get your changes adopted upstream (unless it's GNOME), much more than you'd ever get from a proprietary company's OS.
So, while there's always room for improvement on the technical aspects of the OS, the social and political aspects of Linux and the BSDs make them the best we can achieve as a society.
Macs also existed but were expensive. The PC with DOS was both powerful and cheap.
More importantly, there’s backwards compatibility. By the time the 8086 came out, people had spent serious money on getting binary-only software (WordStar cost hundreds of dollars, for example). “Buy this computer, and you can keep running the software you paid for, but faster” was a good selling point.
Very few benefits to a clunky 24 or 20 bit word size; now it costs more and is a bizarre boutique architecture in a world where it needs to compete with 8 bit Z80s and 6502s.
We just have the illusion of a "flat" memory model, but it's not really flat, the CPU and the operating system does an important job in translating our flat memory model in something that is not flat at all. All that address translation work could have been avoided if we accepted to not have a flat memory model and be aware that our memory is divided in pages.
Basically we are doing in hardware the job of managing a non flat memory space that the programmer, or well, the compiler (or these days you would say the AI agent) could probably to better because it knows how to allocate things to avoid being them on page boundaries, and all of this to give the illusion to the programmer that it's working with a flat memory (except when it does something wrong and gets a segmentation fault, that, as the name suggests, is an hint that at the end the memory is not really flat).
The above is very similar to the argument that you should use a garbage collected langauge.
Back in 1980 most programs were being written in interpreted languages that did all the hard work of memory for you - just like today.
As an aside, the memory model is flat, it's just not physically linear when implementing virtual memory addressing.
The PC was intended to be cheap and was competing with 8 bit machines. Being 16/20 bit made it already high end.
If you wanted 24 or 32 bit, IBM had many other machines to sell you. Or you could just buy a VAX.
Also from a casual Google, an IBM PC launched in 1985 (picking the XT 5160-078 as an example) was around $4,995 at launch. Compare that to two 68000-based computers also launched in 1985: the Amiga 1000 launched at $1,295 and the Atari 520ST launched at $600.
These computer system prices - Sun, IBM, Commodore, Atari - came from the market segments the manufacturers aimed to sell to, rather than a cost saving enabled by cumbersome memory models.
The cumbersome memory model is just a historical accident; the 8086 designers wanted 8080 backwards compatibility so they could sell to former 8080 users, IBM did not require this. IBM would've picked the 68000 had it been "production ready" at the time, they did not reject flat memory on cost grounds!
Segmentation meant programs could remain essentially 16 bit with all the benefits to that like smaller code size.
Huh?
There were no segmented x86 machines capable of addressing 256MB of RAM, aside from the 386 (maybe).
If you had a 386 and the $130K of memory your statement implies, you probably also could afford a Unix (or something else) license to get to that 32-bit address space. (If you weren't doing it all in memory, then you're having to depending on paging stuff out to disk, implying you either have a real OS or a flat memory model isn't enough to save you since you're manually having to page stuff to disk and back anyway.)
That's a super strange scenario you're describing.
Back then you had to chunk it out and fiddle with the offsets. Even then you still would have had to manage loading out the next chunk.
If my memory is right 1MB of memory in the early 90s was like 200-300 per meg. Would have to dig up a computer shopper and look.
I only have a couple reference points around this scale:
My dad's company had a system set up with a searchable index of a bunch of legal testimony. It was a Compaq Deskpro 386 running Unix with an attached 1GB disk. The 1GB disk set up was as big as the machine itself.
A few years later, I worked with a Cyber mainframe equipped with around 30GB of total attached disk storage. The disk array literally filled a room.
256MB disk on an 80's PC would have definitely been quite a bit.
It was just a hack. Hack to delay migration to 32 bit architecture. Effective one, but hack nonetheless
When I was learning C, we did things at a reasonably low level. I was learning data structures, and building things like binary trees out of things like structs, and the structs were fixed-sized memory blocks holding pointers to regions of memory which were either more structs or data fields. All reasonable stuff. But we weren't writing for a particular machine. We were writing for the idea of a machine, and part of that idea was that the machine had a flat memory model. This really struck me when I compiled my homework (parse some data into a tree) on the departmental SunOS server, and it worked fine, and then took it home and compiled it with Borland C for DOS on my 386 and it segfaulted on the same data. That was when I learned to hate segmented memory, but looking back, it seems to me that I learned the wrong lesson.
I learned to write software for a lowish-level model of an idealized computer. The generation before me was always writing software for a specific computer, consisting of a specific set of hardware. The software was always the goal, but the nature of the task was defined by the hardware. Things like memory segmentation were facts about the hardware, and the available hardware varied widely at the time in a way modern hardware doesn't, really, except maybe in the embedded space.
Imagine if you could have done something like this:
in order to move a seg:ofs ptr forward by 'some-delta' bytes.ADSC (add with segment carry) would do:
or: Maybe there should also have been an instruction to normalize a seg:ofs ptr (so the new offset was in the 0-15 range).ADSC could have been adapted for the 286 with ease, as long as a specific layout of the segment descriptor tables was mandated (probably with 10h instead of 1000h in protected mode).
Edited slightly for clarity (ofs => imm). A normalizing instruction would be harder to do right for the 286 because you don't want to spend too many slots in the descriptor table(s) for a single memory object.
Except we couldn't. If we made each segment isolated from other, we would waste so much memory because memory are allocated in segment.
If we made each segment dynamic, we need something to manage them.
This "hindsight" is just a MMU in disguise.
(And I completely agree.)
Looking back, the simplicity of the instruction set seems quaint next to the thousands of instructions we have today.
How is that compatible with an array and a simple implementation of the index operator?
This was a problem.
https://en.wikipedia.org/wiki/Expanded_memory
https://en.wikipedia.org/wiki/Extended_memory
https://en.wikipedia.org/wiki/Physical_Address_Extension
The segment thing and the convoluted different pointer math caused real gymnastics if you ever had data bigger than 64k... such as images.
I always thought of the segments as windows of 64k but moving between those windows, esp with the limited register set, required some real mental gymnastics.
The original 20 bit vision of the 8086 was when memory was very expensive and they expected typical high end machines to have 128K of memory.
Intel’s assembler was designed so you could have up to 128K of code with a “shared” segment in the middle that either side could reach with near (16 bit only) pointers to call commonly shared routines, and more rarely executed code existed on either end.
In addition data could be its own segment, and/or memory mapped I/O outside of the 128K space.
But memory got so cheap that nobody bothered with this, and the performance gains of writing code that way wasn’t worth the effort. X86 code was compact enough most programs could cram their code into 64k anyway, or 64k per functional unit with calls between them being rare.
The real tragedy is they went for 20 bit instead of 24 bit. 8086 with 16MB of addressable space would have been a very different world and would have made little difference if there use. (Paragraphs would have been 256 bytes, the same size as a page; most data structures would have been fine with that.)
I did use an AI for spell-checking, punctuation, generally making it flow, but its all my text.
You think a machine is going to come up with "near pointers, far pointers, wherever-you-are pointers"?
LLMs generate low-entropy text. That's their entire purpose. But good writing isn't about being as low-entropy as possible. It's about producing peaks and valleys. As a person who's been participating in human-to-human communication your entire life, you probably have a pretty well-developed sense of how to structure the flow of a piece of communication. The small arcs with their ebbs and flows of tension and density provide the reader a rough surface that gives them enough traction to easily move from point to point. Don't let an LLM smooth out all the gaps. It makes it hard for a reader to keep their footing in the text.
Not OP, but this is where you're wrong. The vast majority of people, myself included, have difficulty structuring communication for effectiveness to a wide audience. When I manage to pull it off I'm very proud of the work, but I can't just sit down and do it. Review with an LLM helps me find those places where it CLANKS, distracting the reader, taking them out of the flow. This is why every professional writer has an editor; good communication is quite hard.
- the “make it flow” made it flow in an AI generated way like short paragraphs that are one short sentence.
- I now have to decide if this is entirely AI generated and thus not worth my time reading or not.
- I would prefer to just interact with you as a real person; your writing doesn’t have to be perfect for what you write to be worth reading.
I've reviewed what I originally wrote and I prefer the text I published. Sure, I could review it all myself (indeed I used to) but that takes time and it was becoming a barrier to actually publishing stuff. Maybe I'd have got around to finishing it in a few months.
I don't use AI to write for me. I hate people who do that.
286 could then use the next 4 bits from the segment register to allow 16 MB address space and 386 could use all of them for 4GB. And wouldn't it be nice if 386 had 64KB pages (1 segment)?
The 68000 was a complete break so it opted for relocatable code (which also needed more registers, and in fact the 68k had 16 instead of 8).
I get why hey didn't. Someone might want to run two processes each with its own segment, but the whole machine might only have 64k in total.