> 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.

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.

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.

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.

still worth it because otherwise you have essentially no software advantage over competing architectures (at the time, mainly Motorola 6800 successors and the PDP-11 architecture)

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...

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.

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.

I recall turbo (Pascal I guess but I was a kid and this was 40 years ago) having options, small for all in one. Then code and data in different segments, but only one each. Then code in one but multiple data, and finally multitude of both. I probably remember the options a bit off but there is enough to state that compilers could handle segments. Though they didn't optimize it well and so the smallest option was fastest

No, that was C (and C++).

Turbo Pascal 3.x always had a single code segment, a single data segment, a single stack segment + a heap. Heap allocations were paragraph aligned (ofs=0). All pointers were far pointers.

Turbo Pascal 4.0 and up had one code segment per module (that they called units). It still had a single data segment and a single stack segment + a heap. Heap allocations were still paragraph aligned and all pointers were still far pointers.

Turbo/Borland Pascal 7.0 also supported 16-bit protected mode. I don't know if heap allocations had ofs=0 there.

None of them had "huge" arrays/pointers where pointers can point to things bigger than 64K -- at the cost of a lot of instructions for pointer arithmetic and array indexing.

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.

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.

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.

I remember that at some point compiler ads would brag that the new "Microland" compiler could do "segment pointers" where only the segment was stored. I don't remember when it was, but it was fairly late in the DOS era.

In retrospect, they seem so useful and obvious but apparently not. I guess the type of person who thinks near/far/huge is extremely complicated found segment pointers even more complicated.

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.

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.