• Please review our updated Terms and Rules here

Bus Machine Design: I/O Space or Memory-Mapped I/O?

glitch

Veteran Member
Joined
Feb 1, 2010
Messages
5,051
Location
Central VA
I'm looking for some input on the design of the bus-oriented generic 8-bit system I've been working on. My experience with 8-bit processors has been limited to processors with I/O space support (8085, Z80)...as such, I've gotten used to using IN and OUT and having a 256 byte I/O space. It's easy to decode, the instructions are handy (unless you're doing something sequential like a character display), and 256 8-bit I/O devices seems like plenty.

The problem with that is the primary goal of the bus machine is to be processor-inspecific. There will be at least an 8085 and a 6502 CPU board design, and of course the 6502 has no I/O space. It would be easy to produce two sets of option boards (one memory mapped and one using I/O space), but part of the project goal is universal option boards. OSI and Apple accomplished this by using all memory-mapped devices.

The other option, and my original thought on the matter, was to create a board to map I/O space into a 256-byte block of memory, probably using a faster PIC microcontroller to interpret memory reads/writes and pull them from the I/O space. This is obviously more complicated, but preserves I/O space. It seemed like a pretty decent idea, and shouldn't be super-hard to implement.

But in the end, with memory-mapped processors you're going to end up using 256 bytes of memory address space for I/O anyway. Is it worth having the extra 256 bytes for processors that support I/O space? Will it make a worthwhile difference in, say CP/M, to be worth the trouble? Do people who have coded for both memory-only and I/O space devices really care either way?
 
Interesting design question. I know the Commodore 128 has a 4KiB block of memory-mapped I/O, though due to incomplete decoding only about 28% of it is used, and that much only because 1KiB is allocated to video RAM for the legacy C64 VIC-II display (it's used for character-cell colour data, IIRC). Now that I come to look at the issue, 256 bytes seems like more than most people would ever need for pure I/O and control-register purposes. That said, having the option to put things like (for example) video RAM on a separate bus -- i.e., accessible at the same time as main memory by suitably clueful hardware -- seems like a pretty good idea. I guess it depends on how capable you want the theoretical performance limit of your design to be.
 
Last edited:
From a hobbyist programmer's perspective, one who grew up with Commodore computers, I've never really wrapped my head around port-based I/O like you have on the Z80. Frankly I find the concept a pain in the *** compared to memory-mapped I/O, if you have the room in the memory map. Take for example a C64 which has both screen matrix (part of regular RAM), colour matrix (nibbles IIRC), VIC-II, SID and both CIA's mapped into memory. Indeed there are a number of POKEs required to address e.g. the SID chip, but at least every address does different things. If that chip had been accessed through one or two I/O addresses, the number of calls to determine which register and then what data would have become even greater and more cumbersome, in particular from Basic.
 
(a tidbit: Few people know that the Z80 has a 64K I/O address space.)

But why have a CPU involved in the mindless minutiae of I/O anyway in this day and age? Establish, say, 16 mailboxes in memory space and let cheap MCUs (Cortex M0/M3s are probably faster than anything you'll ever hang on a bus) handle the I/O. You could even set up an inter-MCU mailbox so that one MCU could talk to another without CPU intervention. That way, changing CPUs is no big deal, since most of the I/O programming resides elsewhere.
 
Hi! My opinion is to use IO mapping to the maximum extent possible so you'll have a contiguous and unencumbered memory map. Working around memory mapped IO is a real PITA as are non-switchable ROMs. Motorola/MOS CPUs are relatively easy to convert to IO mapping by just reserving a small region (256 bytes) of memory to simulate the Intel/Zilog IO mapping.

Put slow IO on the external bus and keep fast memory local to the CPU is my philosophy. This will simplify the design and reduce costs since slow IO tends to accept the signal conditions of an external bus much better than memory does.

Good luck with your project! Thanks and have a nice day!

Andrew Lynch
 
Working around memory mapped IO is a real PITA as are non-switchable ROMs. Motorola/MOS CPUs are relatively easy to convert to IO mapping by just reserving a small region (256 bytes) of memory to simulate the Intel/Zilog IO mapping.

That was more or less my feeling on the matter, but people who have worked exclusively with memory-mapped I/O seem to find it superior to systems with I/O space.

In thinking more about the problem, I may have come up with a simple solution for mapping the I/O bus into memory space for 6502/6800/et c. processors -- by pulling the IO/M line of my bus low with a pulldown resistor (active LOW for M), I could have a comparator like the 74LS688 pull the line high for I/O whenever there was a read/write to any of 256 addresses determined by comparing the upper 8 address lines and the state of a DIP switch. This would kick the memory devices (except for the mapper board) off the memory bus and allow the processor to talk to the I/O devices, addressed on the low 8 bits of the address lines.

As an added bonus, if this was built on a separate option board, you could cut a trace/add a jumper to the 8085 CPU board and allow it to use memory-mapped I/O, for those users who would rather do it that way! I think I have an answer then: we'll do both, and it will be simpler than I originally thought.
 
As long as the documentation is clear and forgiving to newbies, I'm sure even someone like me could get into port based I/O mapping. The problem to me isn't the port use as such, more what the hardware (chip) on the other side requires for input and output. If it is a chip that I should be able to read single or continuous data from, how can I do it in an effective way. Perhaps if I had grown up with e.g. a Z80 design this had not been a personal matter. I don't know if the instruction sets on Intels and Zilogs are better suited for I/O mapping than the ones on Motorolas and MOS?
 
As long as the documentation is clear and forgiving to newbies, I'm sure even someone like me could get into port based I/O mapping. The problem to me isn't the port use as such, more what the hardware (chip) on the other side requires for input and output. If it is a chip that I should be able to read single or continuous data from, how can I do it in an effective way. Perhaps if I had grown up with e.g. a Z80 design this had not been a personal matter. I don't know if the instruction sets on Intels and Zilogs are better suited for I/O mapping than the ones on Motorolas and MOS?

The instruction set is better suited because there's no separate I/O bus on the 6800 or 6502, for example. The 8080/8085/Z80 have an IO/M line that indicates whether an I/O or memory operation is taking place on the bus and allows devices to respond accordingly. With the 8080/8085, the I/O space is 256 bytes, so you have 256 input ports and 256 output ports. If you want to read data from input port #3, you do IN 3 (in 8080/8085 Assembly) and the value found at I/O port 3 is placed in the accumulator. The main advantage is that memory space is contiguous, with no I/O devices mapped in.

I've got an idea drawn up as to how I'm going to map I/O space into memory space for memory-only processors like the 6502. I'll probably breadboard it with my S-100 system since I've got a full monitor to work with there. Essentially, it will let you select a 256-byte block on any 256-byte boundary that will act as your I/O space. Reads and writes in the 256-byte block will present data from devices that answer to the IO/M line being high, so software-wise it should be no different than true memory-mapped I/O.
 
(a tidbit: Few people know that the Z80 has a 64K I/O address space.)

But why have a CPU involved in the mindless minutiae of I/O anyway in this day and age? Establish, say, 16 mailboxes in memory space and let cheap MCUs (Cortex M0/M3s are probably faster than anything you'll ever hang on a bus) handle the I/O. You could even set up an inter-MCU mailbox so that one MCU could talk to another without CPU intervention. That way, changing CPUs is no big deal, since most of the I/O programming resides elsewhere.

Really? I thought the Z80 only used the lower 8-bits of the address bus for IO and the IN/OUT instructions only used an 8-bit address... or are there some undocumented features?
 
Really? I thought the Z80 only used the lower 8-bits of the address bus for IO and the IN/OUT instructions only used an 8-bit address... or are there some undocumented features?

It's documented--if you carefully read the documentation, it states that when an IN r,(C) or OUT (C),r instructions (or any I/O instruction that uses the C register for indirect port addressing, the contents of the B register appear on the upper 8 bits of the address bus also, giving, in effect, a 64K address space).

It's sort of like the 8088 having a 4MB addressing space.
 
It's documented--if you carefully read the documentation, it states that when an IN r,(C) or OUT (C),r instructions (or any I/O instruction that uses the C register for indirect port addressing, the contents of the B register appear on the upper 8 bits of the address bus also, giving, in effect, a 64K address space).

It's sort of like the 8088 having a 4MB addressing space.

Huh... well I'll be. I've never noticed that before and I've read through the manual a few times. Learn something new everyday. :)
 
Back
Top