18

I was reading through PCI and PCIe configuration access mechanism in Chapter 3 (page 96) of PCIe System Architecture (Mindshare series). As a solution to prevent locking (in case of multiple threads) due to two CPU I/O space access for a single Configuration Space access and expanding configuration space (256 B to 4 KiB), there has been a shift to use memory address space instead of I/O address space.

Why wasn't this done in the first place and what would have motivated having two different address spaces in the past?
(With x86 having special in and out instructions to access I/O address space.)

I tried finding the motivation for separate address space on the web, but I couldn't find it. All resources I laid my hands over mention the presence of two address spaces (I/O address space and memory address space), but they do not mention why or why not a single memory address space could be used from the beginning.

9
  • This was posted in StackOverflow. Adding @MargaretBloom 's comments from there: "Maybe Retrocomputing can answer this better. My guess is that comes from a time when there were really two separate buses for memory and IO and the memory bus was just wires dedicated to the RAM. With time we realized we can unify the two at least in the initial segment."
    – analogkp
    Oct 30, 2022 at 14:40
  • 3
    crossposting is not considered a great idea. you should have the question migrated over here.
    – Raffzahn
    Oct 30, 2022 at 14:52
  • 8
    In my oppinion (it's an oppinion, that's why its just a comment), the main point of a separate I/O space is that the whole memory space can be used for memory (as the name says, that's its point!). Today, x86-64 provides us with 48 bits of physical memory space, but no system provides 256TB of RAM. In the old days, 64KB of RAM was not that uncommon in system like the C64, as the memory space was just 64KB, Instead of bank switching between being able to access the SID or VIC registers or RAM at an adress aliasing to it, having a separate I/O space is actually a good idea. Oct 30, 2022 at 21:58
  • 2
    @Raffzahn: Thank You. I've deleted it from stackoverflow to avoid duplication.
    – analogkp
    Oct 31, 2022 at 5:29
  • 2
    In 1961, DEC introduced the PDP-1. It had two busses and two adress spaces. By 1971, DEC had introduced the PDP-11. It featured one bus, the Unibus, that could address both memory locations and device controllers. Both of these predate microcomputers. Oct 31, 2022 at 10:32

2 Answers 2

32

do not mention why or why not a single memory address space could be used from the beginning.

Simply because a dedicated I/O space simplifies system design.


It may be assumed that you're asking mainly about the way it is done on x86 machines. As 8080 descendants, they signal I/O access by a dedicated addressing cycle and using a dedicated address space but using the same address lines. These are not two separate buses - due to reduce pin count

Having an I/O Space Has Advantages:

  • Memory decoding does not need to care for I/O specialities, like slower access times.
  • I/O address decoding and memory decoding can be designed independently of each other
    • Decoding of I/O chips did not need to decode the whole address space, but only the way smaller I/O space, as a dedicated I/O signal does the rest.
    • Different approaches for incomplete decoding can save chips
  • The full primary address space are available for code/data
    • 64 Ki RAM (8080) aren't that much to start with, especially with ROM and buffers included, excluding I/O reliefs that (a bit)
    • But even with the 1 Mi address space of an 8086, having additional 64 Ki for I/O is as helpful (*1).
  • Full 256 (8080) or later full 64 Ki (Z80, 8086) can be used for I/O
    • The later quite handy to take for example video and/or disk buffers out of main memory
  • By separating I/O instructions from memory instruction no random memory access can initiate an unwanted or even dangerous I/O process.
  • Last but not least, a dedicated I/O space and dedicated I/O instructions ease the task of handling I/O privilege and I/O virtualization

It's a Matter of Heritage:

  • The i8086 inherited that concept from the i8080 (*2)
  • The i8080's implementation is a generalized version of the way the i8008 handled I/O
  • The i8008 is in turn just a single chip implementation of the Datapoint 2200 CPU.
  • The Datapoint 2200 was a discrete TTL design featuring about 100 chips. Having dedicated I/O instructions removed the need for address decoding at all. Quite useful to keep it simple.

It Wasn't Just Intel's Thing

Other early CPU followed the same or similar concepts:

  • The Valvo/Signetics 2650 had an 8 bit address space, much like the 8080, and in addition a 1 bit space.
  • TI's 9900 supported an additional 12 bit address space for bitwise I/O which could transfer 1 to 16 bits from either address.
  • The Fairchild F8 in turn had no address bus at all, but featured two I/O ports that could transfer addresses to an external unit containing the PC (3851) or generate an address bus (3852) - but these two ports cold be as well used for direct I/O (1 bit address space). They were part of a 4 bit address space to be accessed by dedicated instructions.

So there is (well, was) way more out there and the 64Ki 8086 I/O space is eventually just the most simple and generic implementation of that idea.


*1 - That IBM did nonetheless put I/O into memory is design decision - not the best, but that's a common theme with the original PC, isn't it?

*2 - After all, it was THE main requirement of the 8086 design to be bus and instruction compatible to allow low effort redesign of systems and mostly automated software conversion.

19
  • 3
    x86 IN AL,DX takes a 16-bit IO port number in DX. IO address space has 16-bit addresses. Are you talking about 8080 when you say there are only 256 IO addresses, or did IBM-PC only wire up / support the low 8 bits? (Some things that use fixed port numbers in x86 use a number in the low 8 bits anyway, because the immediate form of in al, imm8 only allows an 8-bit port number.) Oct 30, 2022 at 20:19
  • 4
    When you say 8086 was "instruction compatible" with 8080, important to clarify that it's not binary compatible; a translating assembler was needed. But yes 8086 was designed to make mechanical translation possible. (I know you know this, but I worried your phrasing might have misled some readers.) See The start of x86: Intel 8080 vs Intel 8086? and other Q&As for more details. Oct 30, 2022 at 20:23
  • 5
    Another aspect that you tangentially touch on - a separate IO space means the processor can assume that all of memory behaves like memory. (Reads return what was written, speculative accesses are safe, accesses can be restarted, access sizes are unimportant, etc.) Modern processors already have significant amounts of machinery to do quick translation table lookups and so can 'just' encode that info into the translation table (ARM MAIR indexes, etc); this would be far more expensive (comparatively speaking) on a smaller cpu that doesn't already have all that machinery.
    – TLW
    Oct 31, 2022 at 3:01
  • 3
    @Raffzahn: BIOS text routines are horribly inefficient, but many programs for the CGA and MDA use other means of performing screen I/O. Graphics code benefits from being able to use instructions like AND, OR, and XOR, as well as the ability to perform sequential addresses to e.g. SI, SI+80, SI+160, etc. without having to use an AND instruction between each pair of addresses.
    – supercat
    Oct 31, 2022 at 22:48
  • 4
    @PeterCordes In the original (8088) PC, it was a 16-bit I/O address space but there was a design rule that only the low ten bits were significant to peripherals. See retrocomputing.stackexchange.com/questions/12370/…
    – smitelli
    Nov 1, 2022 at 13:09
0

This answer should not be seen as @Raffzan's rival but a complement.

There were indeed many microprocessors that did not use dedicated I/O space. Computers using the Motorola 6800 and derivatives (I'm using the term "derivatives" in the broad sense) usually had restrictions on where the ROM had to be placed and this had some unpleasant effects on how they where programmed.

First of all the ROM area had to be placed at the high-address area - fact that physically limits the code and makes it unexpandable unless jumps are made (if you heard the term "spaghetti code", that's it exactly). I/O area was by convention mapped at FExxh inside the ROM space, which means there were cells in the ROM that had to be sacrified for the sake of I/O. Having the I/O in the ROM space also meant more decodification had to be done.

Additionally, there are even more troubles, especially when expanding the memory space:

  • When designing a microcomputer with bank-based memory expansions to use with most 8-bitters not derived from Intel this means either the page corresponding to the ROM position must sacrifice the cells at the I/O area which turns out to be extremely inneficient memory wise. The other way is to not bank at all the page containing the ROM.

  • When designing a microcomputer with a linear memory but expecting it to be code-compatible with a previous generation microcomputer with a microprocessor with a smaller memory map things also can go awry very easy. Remember that those microprocessors expected the ROM area at the end of the memory map... but the legacy I/O and ROM may not be at the end to ensure compatibility. This means both ROM and RAM may not have a single and big space but multiple smaller ones across the memory map. The same happens with the I/O: wou may end with not one but multiple and scattered I/O spaces across the map. There are also other hazards related to this implementation but are outside of the scope of this answer.

To sum it up a separate I/O:

  1. Enables the designers of having the ROM and RAM areas to be compact and without having to sacrify cell space.
  2. Enables easy addition of more memory in subsequent models of the microcomputer line in case the microprocessor gets replaced with a derivative (now in the strict sense) with more addressing space.
  3. Allows easier backwards-compatibility among models because it is always located at the same positions.
  4. Allows designers simple decoding circuits, with also simple modifications in case the I/O space is increased with newer microprocessors offering more area for this purpose.
  5. Eases bank-switching mechanisms and makes possible clean implementations.
  6. Nobody forbids to use a microprocessor with separated I/O to have memory-mapped I/O. In fact back in the day most 8-bitters using 8080 and derivatives (again in the broad sense) had an hybrid I/O system by using the I/O designed area for most purposes but had the video memory in the CPU memory map - only systems such as the MSX, Tatung Einstein, Sega 8-bit, NES/Famicom et all which had separate video memory managed by a dedicated VDP ic or similar everything else used this doctrine.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .