6

In the 70's and 80's RAM chips worked at a lower frequency than the CPU.

That is, the processor worked at a frequency higher than the RAM. We have that the CPU cannot receive one instruction from the RAM, per clock, since the RAM is lagging behind. We have that the CPU is idle while waiting for the next command.

There are different ways to work with this.
One of it - make a CPU with microcode. While the CPU is waiting for a command from the RAM, the microcode is running at the CPU frequency (for example, doing a complex command on registers). Or you can add cache mem in CPU.

Is it possible to do so (approximately)?

The processor operates at a frequency of 25 MHz, the memory has a delay of 80 ns (12.5 MHz). The RAM cannot give the CPU a command at each of its clock cycles. You can take two identical RAM chips and run them by changing the frequency in the clock signal in one of chip. Pick up such a shift that. The 1st chip is being recharged, the 2nd chip is giving a command to the CPU. The 2nd chip is recharged, the 1st gives the command. It turns out that in RAM1 there are only even instructions, and in RAM2 only odd ones. That is, the CPU can receive commands at its own frequency (25 million times per second), despite the fact that the RAM chips operate at 12.5 MHz.

--

I mean about such a mechanism itself from the point of view of design, and not from the point of view of taking C64 now and doing this with it.

Maybe such methods were used in mainframes or supercomputers?

6
  • 11
    Nothing requires that the CPU 'do nothing' while awaiting memory response. Microcode is not a requirement for 'not doing nothing'.
    – dave
    May 31, 2023 at 0:54
  • Sounds pretty much like modern dual-channel memory systems, but those interleave at cache-line granularity because DDR SDRAM is designed around burst transfers of 32 or 64 bytes. Jun 1, 2023 at 23:49
  • 3
    It was common for the CPU to take many clock cycles to perform an instruction so although the clock may have been faster than memory the instruction execution time may not have been. Jun 2, 2023 at 0:57
  • Re: your description of microcode being made to be slow(?) - did you mean that packing more CISC complexity into microcode that you can access via compact machine-code instruction let the same program run with less code-fetch bandwidth? I've been debating with Raffzahn in comments that that's probably the idea behind what you wrote, and that the idea makes sense even though that's not a primary reason for choosing microcode. Jun 2, 2023 at 14:45
  • 1
    Your premise is incorrect, at least for the 70's. It wasn't uncommon to have "zero wait state" RAM, meaning the CPU was never delayed waiting for the RAM. Jun 3, 2023 at 2:44

3 Answers 3

21

You can take two identical RAM chips and run them by changing the frequency in the clock signal in one of chip. Pick up such a shift that. The 1st chip is being recharged, the 2nd chip is giving a command to the CPU. The 2nd chip is recharged, the 1st gives the command. It turns out that in RAM1 there are only even instructions, and in RAM2 only odd ones. That is, the CPU can receive commands at its own frequency (25 million times per second), despite the fact that the RAM chips operate at 12.5 MHz.

Yes. This is called interleaved memory and it was certainly found in the wild. From the linked Wikipedia article:

With interleaved memory, memory addresses are allocated to each memory bank in turn. For example, in an interleaved system with two memory banks (assuming word-addressable memory), if logical address 32 belongs to bank 0, then logical address 33 would belong to bank 1, logical address 34 would belong to bank 0, and so on. An interleaved memory is said to be n-way interleaved when there are n banks and memory location i resides in bank i mod n.

And, as with so much in computing, IBM gets the credit for inventing it:

Early research into interleaved memory was performed at IBM in the 60s and 70s in relation to the IBM 7030 Stretch computer,[4] but development went on for decades improving design, flexibility and performance to produce modern implementations.

2
  • 6
    This is part of the reason for the four-plane memory layout of IBM's early graphics cards (CGA/EGA) -- the electron guns in the CRT needed data faster than a single bank of RAM chips could deliver it, so they designed it to read across four separate banks in parallel.
    – smitelli
    Jun 1, 2023 at 18:31
  • 2
    The CGA is not planar because of read speed. The CGA uses banks of memory because of fundamental limitations in how many scan lines the 6845 CRTC controller can count. Jun 2, 2023 at 8:10
13

In the 70's and 80's RAM chips worked at a lower frequency than the CPU. That is, the processor worked at a frequency higher than the RAM.

Not really. At least with microprocessors, RAM was usually equal or faster than the CPU. RAM being slower is a development of the 1990s and later again, with micros. After all, the same cycle has been run through with mainframes.

We have that the CPU is idle while waiting for the next command.

Not really. A CPU waiting for data is a relatively new thing - again for micros.

One of it - make a CPU with microcode. While the CPU is waiting for a command from the RAM, the microcode is running at the CPU frequency (for example, doing a complex command on registers).

Nope. Microcode is not made to 'fill time' but to simplify CPU design (save on components) and/or run more complex operations.

Or you can add cache mem in CPU.

Well, yes, but it doesn't have to be in CPU. After all, Cache is nothing else than faster memory which usually is only affordable in comparably small quantities - otherwise it would be used for all memory.

Is it possible to do so (approximately)?

Only the second and only in part.

What to do?

In the end it's all about storage attachment and storage hierarchy(*1).

On a more detailed level there are four basic methods to improve average RAM access time:

  1. Using regions of faster RAM for critical data/code.
  2. Using interleaved memory regions.
  3. Using a wider memory interface.
  4. Using a cache.

#1 Faster Regions

The first method was very common at a time when vastly different technologies were used as RAM. A good example is a rather early machine such as Zuse Z23 where main memory was made from drum, but the first 256 words were core. Likewise the (way bigger) Univac 1105 whose base memory had 8 KiWords core plus 16 KiWords of drum (*2).

For program logic there was no difference between either type of memory. It was one continuous address space, but code - and especially data - stored in the first 8 Ki could be accessed without any waiting for the drum to rotate and deliver a random word (*3).

In a way, many modern micro processors support a similar working. They allow locking cache lines to a certain memory address. That is, those lines will be taken out of regular cache operation, loaded once with the desired content and never overwritten by other data, thus making sure that those code/data sections are always ready at maximum speed.

Another more modern example, though for a different reason, was the Commodore Amiga. While all its memory was semiconductor of equal speed, one portion (Fast RAM) could be accessed at full CPU speed, while another (Chip-RAM) was shared with I/O. Thus it was advised to store code and non I/O-related data whenever possible always in Fast RAM.

#2 Interleaved Memory Regions

If a memory device takes a certain time before it can be accessed again, why not use several memory devices, each with its own cool down, independently? Of course this would require an access scheme that (hopefully) allows predictable access patterns. Luckily reading code for execution is (mostly) exactly that: strictly sequential RAM access.

Having two RAM devices (banks) with interleaved addresses will give twice the RAM speed. As long as access is sequential. But even a random access might have a 50% chance for hitting the right (next) bank (*4). Having four quadruples RAM speed, and so on.

Interleaved memory blocks have been used since way back in core times - at least with mainframes where one had to have multiple core blocks anyway. It can be traced back to at least the 1961 IBM 7030, and was a common technique with /360(ish) Mainframes throughout the 60s and later.

It's all common with PCs supporting parallel banks since 286 times (*5).

Another modern analogue is RAID arrays.

#3 A Wider Memory Interface

There is no reason to tie the width of a memory interface to the internal word width of a CPU. A very common example are 8-bit devices on a 16-bit CPU. Only half the CPU width is used to access data. The same can be done by widening - like giving that 16-bit CPU a 32-bit memory interface. So whenever it accesses a 16-bit item from RAM, 32 bits are read at once. One half is directly forwarded to the CPU, the other half is latched and kept in case the following access needs it - which is again true for all sequential access.

Like before, doubling size doubles bandwidth. That method became quite popular with mainframes, by 1980 reaching memory interface widths of up to 1024 or 2048 bit (128/256 bytes) - all for a 32-bit CPU.

For microprocessors the Pentium may qualify as the first mainstream CPU utilizing this. While being a 32-bit CPU like the 486, it featured a 64-bit (8-byte) memory interface to double RAM bandwidth.

The method was (and is) quite popular with GPUs (graphic cards). Their access pattern is even more linear than for a standard CPU, so even the 1999 GForce 256 featured a 128-bit interface. By 2003 Nvidia reached 256 bits (NV42) which is more or less the standard up to today (*6).

Such wide memory interfaces are not only a precursor of cache in the sense that they prepare additional data for future access, but also by enabling fast cache loads. Which brings us to the last item:

#4 Cache

In some way a cache is the very same as item #1. A dedicated, faster storage area for most important data. Except now no longer the programmer decides (*7), but the CPU hardware/software does so. This takes some additional hardware, so it took some time for technology to be applied (for a more in depth history see here).

Caches do not obsolete #3..4, but rather extend thereupon.


*1 - Think of the basic hierarchy of

Disk
    -> Drum
        -> Core
            -> Semiconductor

each faster than the previous, but more expensive and smaller in capacity. In the /370 world this is the basic way to look at all storage. It goes in many more stages from cache all the way to tape libraries and even offline storage like card stacks :))

*2 - Fully expanded 16 Ki of Core and 32 Ki of Drum.

*3 - This is not entirely correct, as programs could be written (stored) in a way that data and code were spread out to the right way to eliminate any waiting. Of course, it was less effort if you could avoid needing such an arrangement.

*4 - With careful alignment, like back in the days of drum memory, this can be made 100% again :))

*5 - Most recent are putting it to the extreme by handling those blocks as independent memory channels, but that's a different story.

*6 - Further growth didn't stop for missing performance gains - there are chips with 384 and 512 or multiples of 256 - but number of pins and resulting board design will get exponentially more expensive, so such wide interfaces are only useful for extreme applications where money is of lesser concern.

*7 - Well, he still can, but that's very fine fine-tuning.

11
  • Note also that the OP's question is about fetching instructions, which do tend to have adjacent-address access patterns, at least until you get to a branch/jump/call. Thus: separate I- and D-caches; lookahead fetch of the target; branch prediction; speculative execution. All of these mechanisms help with keeping the CPU supplied with things to do.
    – dave
    May 31, 2023 at 12:10
  • 1
    @another-dave of course they do - and many more ways - but they are all fine tuning of caches. There are many more ways to improve memory speed way before adding the complexity of a cache and that's what this is about.
    – Raffzahn
    May 31, 2023 at 12:47
  • Caches and memory width/interleave are the crucial things here. Looking at mainstream micros rather than larger systems, it was really only the '386 that started off significantly faster than the attached memory (i.e. wait states would be the norm rather than being needed occasionally) and that was when Intel also introduces a cache controller chip (delivered late IIRC, which slowed '386 acceptance). So performance comes from caching, pipelining, multiple (i.e. superscalar) ALUs, instruction reordering and finally instruction decomposition: all of which are by now in wide use. Jun 1, 2023 at 7:55
  • 8088 was heavily bottlenecked on memory most of the time, because of its 8-bit bus. Even 8086 was fairly often when working with registers. Each byte (or aligned 2-byte word on 8086) takes about 4 cycles to access, but most of the instruction cycle-counts for things like add ax, bx (a 2-byte instruction) are less than 4 cycles. e.g. 2 or 3 cycles. www2.math.uni-wuppertal.de/~fpf/Uebungen/GdR-SS02/opcode_i.html Maybe 8088 was the exception, not the rule, among microprocessors, but it was very notably widespread. Jun 2, 2023 at 0:01
  • Microcode is not made to 'fill time' - I think what the OP was the CISC benefit of having a compact machine-code instruction trigger a bunch of work inside the CPU, e.g. x86 push 123 or stosw which stores and updates the stack pointer or DI, vs. a RISC would need a store and then a pointer increment. (Not a good comparison for push, since normally you'd just addiu once to change the stack pointer and store at different offsets, but consider appending to an array vs. stosw.) Or x86 rep movsb which is memcpy in microcode, avoiding any code-fetch memory traffic during it. Jun 2, 2023 at 0:13
5

It is possible, was done, and is still done.

While interleaved memory could be useful in early systems to speed up memory bandwidth, you are still running into a problem where the system needs to wait if you need to access even or odd addresses consecutively. Another way is to not use interleaving, but make the data bus twice as wide, such as the 80286 with 16-bit data bus and 80386 with 32-bit data bus.

But as you need double the memory banks it basically meant you need double the amount of memory chips, or memory modules. For example a standard PC with a 386DX CPU has 32-bit memory bus, so that alone required four 8-bit SIMM modules, and interleaving that would require eight modules.

To be fair, the problem was not so large on early x86 hardware, as the CPUs had a prefetch queue, so multiple bytes of executable code is already inside the CPU and more code is fetched into CPU queue while the bus would be otherwise unused while executing opcodes that takes multiple cycles.

Standard memory modules have chips that are already divided into multiple banks, and have had them for a long time.

For the C64 example you have, it's actually the other way around. The DRAM is used by the CPU and graphics chip in alternate fashion (with some exceptions where CPU is halted for some time to have more data loaded to graphics chip).

You must log in to answer this question.

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