8

Were there any computers that did not support virtual memory? if yes, were these computers able to run multiple processes at the same time?

By “virtual memory” I mean when a process would want to access a memory address, it would access a virtual address, and then this virtual address would be translated into a physical address.

2
  • Comments are not for extended discussion; this conversation has been moved to chat.
    – Chenmunka
    Jan 16 at 19:08
  • Voted to reopen because it is clearly not a duplicate of the referenced question. In fact, any answer to that question is most definitely not an answer to this question, by definition.
    – JeremyP
    Jan 20 at 8:53
24

The Amiga from Commodore shipped in October 1985 with a preemptive multitasking operating system designed to run many processes. The hardware lacked any support for virtual memory, and the Operating System never added it.

As a multitasking system, it worked very well, especially measured against similarly priced competition that usually lacked this feature (Sinclair QL, notwithstanding). Indeed, most of the drawbacks of the Amiga OS would trace to lack of support for hardware protected memory, not the lack of support for virtual memory.

Protected memory is what allows a system to withstand corruption to kernel memory that is easily caused by errant application in a non-protected memory system. You might be familiar with the "Blue Screen of Death" famous on Windows systems in the past. On the Amiga, such crashes were a common occurrence, but had the less ominous sounding name "Guru Meditation" errors. Either way, you usually had to reboot the machine to recover.

5
  • 1
    Yeah, the Amigas were pretty much awesome during the times between crashes. They definitely crashed a good bit. Jan 15 at 8:11
  • 3
    The benefit is that growing up coding on such a system you become careful with your off-by-ones, pointer arithmetic, and stack usage.
    – pipe
    Jan 15 at 13:09
  • Loading programs mean that the loader had to rewrite the absolute memory address in the compilate IIRC. Jan 15 at 14:59
  • 1
    @DavidTonhofer: Yep. The Amiga executable "hunk" file format contained sections called relocation tables that basically listed locations in the code that the OS executable loader would need to adjust in order to load the code at a different address. Technically they were optional, since a careful programmer (or compiler) could generate code that didn't use any absolute memory addresses in the first place, but in practice most non-trivial programs would have one. Jan 15 at 18:59
  • Doing relocation with relocation tables is actually a pretty common feature of all modern loaders. An executable could get away without one, but a shared object library might be loaded anywhere in the address space depending on what other binaries have also been loaded and how big they are. In fact, it is common now to ransoms loading locations to prevent certain types of hacking attacks.
    – JeremyP
    Jan 20 at 9:00
22

There are three different concepts which may be bundled into the term "virtual memory", depending on whose definitions you prefer.

  1. Separation between program addresses and physical memory addresses. This can be as simple as datum and limit registers to relocate the program.

  2. Splitting of the program address space into pieces that can be independently relocated; the pieces may be variable-sized ('segments') or fixed-size ('pages').

  3. Support for parts of the address space being non-resident, together with a way to stop an instruction that attempts to reference a non-resident part, and a way to restart the instruction when the missing part has been made resident.

There's a natural hierarchy there, in that the higher numbered facilities usually required the lower-numbered ones.


But yes, there were dozens of computers without any of that in hardware. I will note a few from memory, in no particular order and with no particular significance other than what I first thought of, off the top of my head.

A couple of 'firsts':

EDSAC
Manchester Mark 1

Big iron:

IBM 7090
IBM System/360 at its introduction.

Minicomputers:

PDP-8
PDP-11/20
PDP-11/40 without a KT11-D MMU.

The last-mentioned one nevertheless managed to run an operating system (RSX-11M) that supported multiple simultaneous tasks; it just required that you link the task file for a specific physical address.

4
  • Some PDP-8 models also supported timesharing. The first computer I used was a PDP-8/E running TSS-8.
    – Barmar
    Jan 15 at 16:02
  • Indeed. I have a PiDP-8 which can run TSS-8. Jan 15 at 18:06
  • Usually is correct; for instance, Windows 1.0 would happily relocate, move and discard code segments on a whim, and you could also allow it to move and even discard data segments (obviously you lost the data if that happened, but in particular it was used to save the area of the screen behind a dialog so it could be quickly restored instead of having to invalidate and repaint it).
    – Neil
    Jan 15 at 20:51
  • Incidentally, my own preferred terminology is to use "virtual memory" only for case #3, and refer to #1 as "virtual addressing". Jan 15 at 22:53
16

Based on your clarification from comments, “I mean when a process would want to access a memory address, it would access a virtual address, and then this virtual address would be translated into a physical address”, yes, there were computers that did not support virtual memory: any computer where addresses were used with no indirection. There are many examples of this: most 8-bit micros, 8088- and 8086-based PCs...

Virtual memory is not required to run multiple processes simultaneously (within the limits of a system without multiple processors), nor even is bank switching; for example, MS-DOS arguably supports multiple processes loaded simultaneously in memory, and processes can grab control from each other (this is what TSRs do).

Hardware support isn’t even necessary to implement virtual memory; the Z-machine provided paging and virtual memory for its virtual machine, and worked very well on rather limited 8-bit micros.

3
  • 1
    In the late 80s, I worked on a system that did simple round-robin multitasking on top of MS-DOS. (Or I guess it was a clone?) Regardless, not even a hint of virtual memory. Jan 15 at 1:42
  • Considering DOS was, initially, floppy disk based operating system, using virtual memory would have been... "interesting". (Probably same with early hard drives, too). While MS DOS and it's clones might seem to be running multiple programs or tasks at the same time to the user, from the processor's standpoint it was always running one program "thread". Multiple programs running in parallel didn't happen until multiple processors or multithreading in the MS -world (Windows).
    – DocWeird
    Jan 15 at 9:04
  • @DocWeird other computers would swap to floppy or tape, it’s not necessarily that much of a problem ;-). Note that virtual memory doesn’t necessarily involve swapping... And yes, multiple programs can’t run in parallel without multiple processors (and support for them, which DOS never had). Jan 15 at 9:10
12

Preface:

Reading question and comment, it feels as if there is a confusion between address translation and virtual addressing vs. memory protection and separate (process) address spaces. These are more or less independent issues.

  • Address Translation is a mechanism to turn an address issued by a program into a real memory address to be used. There is no principal need for programs or processes to use different address spaces.

  • Virtual addressing is about allowing addressing more memory than there is, by providing a way to detect access to addresses that are currently not in main memory and have them brought in (one way or another)

  • Memory protection is about stopping one process from accessing memory assigned to another. This can and has been done long before usage of virtual addresses. For example the /360 family provides a 4-bit field for each memory page meant to hold a storage key. Similarly, a dedicated CPU register holds the key of the process running. Whenever it accesses memory with a different key, a protection fail is inserted.

  • Separate memory spaces are about giving every process the same (virtual) addresses, so it seems as if it's the only process on a machine - simplifying relocation issues a swell.

Equally important to this question, hardware support for virtual memory is the least important part here: it's all about an OS using this feature. An OS can still provide multi-processing without virtual memory, despite the hardware being present - like Classic MacOS on a 68040 LC475.


For the Questions:

Were there any computers that did not support virtual memory?

Yes, essentially every computer did in the early days.

There were already a number of computers working when the concept of virtual addressing was first described in 1956 by F. Güntsch at TU Berlin, Germany. It wasn't until 1959 when the Manchester MUSE project showed off a first prototype of virtual addressing. Still, it only reached mainstream usage in the late 60s with the IBM 360/67.

It's important to understand that, at that time, virtual addressing wasn't about separating processes, but to allow a process to grow beyond existing memory. We all know that there is never enough memory in a computer, but that was even more scarce back in the days when mainframes with 128 KiB were considered large.

And while virtual addressing as a tool to support multiprocessing became useful in universities during the 1970s, most commercial use stayed with real mode environments to avoid the speed penalty of address translation.

The same was true when minis became a thing in the 1960s/70s - and it repeated of course with micros. Here, much as before, virtual addressing became available quite early on in the 1970s, but it wasn't until the mid-1980s that it caught on with workstations and mid 90s with mass market PC - not at least as its usage is way more of an OS issue than hardware related.

if yes, were these computers able to run multiple processes at the same time?

Of course= multi-programming and multi-processing do not rely on having virtual addressing. It only needs well-behaved processes, staying away from accessing any resources (memory, I/O, Disk, etc.) not assigned to them. Something to be expected anyway from any program, isn't it?

There have been many examples for operating systems supporting concurrent execution without virtual addressing on all classes. By just focusing on micros, a short list may look like this:

  • MP/M for 8080 compatible CPUs (1979)
  • OS/9 for 6809 (1979)
  • MP/M-86 (later Concurrent CP/M and Concurrent DOS) for x86 (1981)
  • QNX for x86 (1982)
  • [OS-9/68k] port of OS/9 to 68,000 (1983). Later ported to many other architectures
  • (Classic) Mac-OS for 68,000 (1984)
  • Sinclair QDOS for 68,000 (1984)
  • GEM for x86 and 68,000 (1985)
  • Amiga OS for 68,000 (1985)
  • Windows for x86 (1987)

Please note that there are many ways to run different processes, and all of the above changed over time in what types were supported, or what restrictions applied. Also, some added virtual addressing (and memory protection) in later versions.

1
  • 1
    There's also UniFlex for the 6809, which was used in GIMIX
    – CSM
    Jan 15 at 13:45
10

For classic Macintosh system versions prior to system 7, all applications used physical memory accesses all the time. Multiple applications could be resident in memory because the address of every application instance's static data would be immutably determined before it launched, and the static data would include a jump table with an entry for every function that could be called between 32K code segments, or whose address could be taken. Generated code Address register A5 was at all times left holding the base address of the current application's static data which, as noted, would never change during the execution of an application instance.

A multi-tasking OS like Multifinder 6.1b9 could switch between application instances whenever an application polled for events by saving the values CPU registers in the current application instance, and loading those registers with values for the application to switch to (either startup values or the last values saved for the that instance). An application which wrote to addresses it didn't own could corrupt other applications, but most applications didn't do such things and the system was remarkably functional and stable.

2
  • Actually, Mac OS didn't have real virtual memory until Mac OS X 10.0 (released in 2001!). Jan 15 at 20:27
  • @GordonDavisson: I think System 7 added paging support to allow Quadra systems with sufficient hard drive space to emulate larger memory, which means logical and physical addresses were different, even though all applications used a shared address space. Also, I would expect that early 1990s A/UX (which was compatible with Macintosh applications) probably used virtual memory.
    – supercat
    Jan 15 at 21:46
7

The PDP-8 did not have virtual memory — in the classic sense that there was no hardware page tables, no hardware page faults, no expandable virtual address space.

The PDP-8 has 12-bit instruction size and 12 bit address space for 4k 12-bit words.  It was expanded with bank switching to hold up to 8 4k banks or 32k words total.

Under TSS/8, the operating system required 8k (2 4k banks), and you needed at least one more for user programs.  User programs were given a full 4k bank and the bank switching instructions were privileged so could not access any other banks.  In time sharing, the operating system would swap a user process to disc, swap another into memory, and give it a time slice.  This worked best if you had at least 2 4k banks for processes, because it would use DMA to the disc to swap processes in/out while at the same time giving a CPU time slice to the user process in the other bank.

4
  • Though one could argue that "it would access a virtual address, and then this virtual address would be translated into a physical address" does fit the bank switching.
    – dirkt
    Jan 14 at 20:14
  • @dirkt, it has 2 3-bit registers: one to select the bank from which to source instructions, and the other to select the bank for data reads & writes. It is effectively virtualizing the original 12-bit PDP-8, but is this enough to qualify as virtual memory and translating virtual address into a physical address? Maybe, by some definition. It's certainly not much hardware; there's no tables -- just 6 bits of state.
    – Erik Eidt
    Jan 14 at 22:01
  • I have written PDP-8 programs, I know how it works. :-) And it was used for multiuser in TSS/8, as you wrote, so it can be definitely used for some kind of virtualization. The "memory field control module" in the PDP-1, that was also used for multi-user, worked in the same way. You don't need "tables" to do that, tiny bits of hardware are enough. Later on MP/M also used tiny bits of hardware for the same purpose.
    – dirkt
    Jan 15 at 5:36
  • Of course, the question is whether we consider 6 bits of state as a virtual memory system, whether we consider appending 3 bits to extend a 12 bit address to 15 bits as virtual to physical translation. Maybe it is or maybe it isn't. Here the "virtual addresses" are narrower than the wider physical, usually in virtual memory systems it is the opposite. So, I say it is a matter of definition & terminology whether to consider simple bank switching as virtual memory. I say it is a stretch but I can also see the analogy.
    – Erik Eidt
    Jan 15 at 5:41
7

Most current microcontrollers

Most microcontrollers have no support for virtual memory in hardware. Microcontrollers running Linux will have this supported in software, but microcontrollers are typically used more for real-time systems. As such, they will normally run an RTOS instead, or often will simply go straight for bare metal. Neither will use virtual memory.

It is perfectly possible to run multiple tasks simultaneously in an RTOS. Unlike the time-slicing multitasking which you are probably most familiar with, RTOSes work slightly differently. The important part of real-time processing is that important processing is turned around in time, so tasks are prioritised. One task at a time (the highest priority) runs with full control over the processor, and it runs until it finishes. If a higher priority task comes along, the current task is frozen and the new task gets full control until it finishes. If a lower priority task is triggered, it goes in the queue. When this task finishes, the RTOS checks the queue for the next highest priority task which has been triggered, and runs that. Sometimes this is supported directly by the hardware using prioritised interrupts, and sometimes it is handled in software. This is called "pre-emptive multitasking", because a higher-priority task can "preempt" (interrupt) a lower.

10
  • 1
    Interrupts are generally considered separately from multi-tasking, since when a "normal" interrupt occurs it must run to completion before control returns to whatever was running previously. Many real-time operating systems are not preemptive, but instead require that work be subdivided into small enough chunks that even a high-priority task which gets added to the schedule by an interrupt will be able to afford to wait for the currently-executing lower-priority chunk to finish before it executes.
    – supercat
    Jan 15 at 17:58
  • 1
    @supercat If it's an RTOS, by definition it does preemption. Some also do your prioritised robin-robin, sure. And it's common for an RTOS to be hooked into processor interrupts for preemption. Preemptive and round-robin are both very much considered multitasking though, it's just that computer scientists who work almost exclusively on PCs and servers have much less awareness of other methods.
    – Graham
    Jan 15 at 19:25
  • 1
    An RTOS is one which offers latency guarantees when used properly. They often use preemption, but an RTOS which requires that tasks be subdivided into small chunks may be able to satisfy latency guarantees without preemption, and an OS can use preemption without being able to meet any particular latency guarantees.
    – supercat
    Jan 15 at 21:15
  • 1
    If a time-critical task needs to share resources with non-time-critical tasks, even a preemptive RTOS would be unable to meet latency requirements if the non-critical tasks don't voluntarily refrain from holding the resources excessively long. If there are multiple resources used by multiple tasks, a program using mutexes, semaphores, etc. running on a preemptive RTOS may be able to coordinate access better than a non-preemptive one, but if a non-critical task would need to use a resource for 5ms in the absence of preemption, and the critical task couldn't tolerate a delay of more than 20ms...
    – supercat
    Jan 16 at 17:08
  • 1
    Who said anything about round-robin? A non-preemptive RTOS should at each context switch identify the highest-priority task which is ready to run.
    – supercat
    Jan 17 at 3:08
3

Were there any computers that did not support virtual memory?

Yes, a great many.

if yes, were these computers able to run multiple processes at the same time?

Yes, if the operating system was designed for it and the programs were well-behaved. Generally, programs need to work when they're loaded at different locations in memory, they need to be able to figure out (with OS help) where they were loaded and how much memory is available to them, and they need to refrain from messing with each other's memory. It's helpful if they limit themselves to using OS facilities to access hardware, instead of direct access (otherwise, strange things can happen during task switch). And there needs to be some way (either preemptive or cooperative) to actually switch between tasks.

All of these things were, in fact, possible on MS-DOS on an 8086 (which had no memory management); DOS had sensible memory allocation routines (if programs used them) and facilities for hardware access (if programs used them), and third party software such as Quarterdeck DESQview provided task switching and even the ability to run multiple apps simultaneously in text-based "windows".

Many early time-sharing systems and early Unix also operated this way — sharing was based on convention and well-behaved apps. Putting processes into "virtual" spaces where everything they can see is their own was a later development.

Not the answer you're looking for? Browse other questions tagged or ask your own question.