Join the discussion

Write your take first — we'll ask for email only when you're ready to publish.

  • Hacker News
  • > Need more than 64KB? Allocate two blocks.

    How is that compatible with an array and a simple implementation of the index operator?

    by pif
  • It isn't.

    This was a problem.

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

  • 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"?

  • 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)?

    by M95D
  • 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.

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

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

  • Oops! 256KB, not 256MB. Sorry about that. It was on a dedicated image capture board plugged into the PC.
  • 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.
  • > 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).

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

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

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

  • It's pretty much the same thing, except that all the memory mapping logic has moved from 'custom memory mapping hardware' into the CPU.
  • 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.

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

  • 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.
  • 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.
  • Why would you ever want a single 64k object? That's like an entire machine's worth of memory!
  • 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).

  • 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.
  • What? It has 4 times as many general purpose registers as you'd ever need, right? /s
  • 1992-author (me) is wondering if he'll ever get a girlfriend.

    (And I completely agree.)

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

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