8

I've been reading about CPUs and how they are implemented, and some big complex architectures (looking at you x86) have instructions that load from memory during one clock cycle. Since one address points to a single byte, how is it possible that I can write:

mov eax, DWORD PTR ds:[esi]

where I'm loading a double word (4 bytes!) from memory and chucking it into eax. How does this work with only one clock cycle? Wouldn't it have to access 4 addresses? The DWORD starts from ds:[esi] and ends up at [ds:[esi] - 3] meaning it has to compute 4 effective address, but it does it in one cycle.

How?

Thanks

7
  • Possible duplicate of How Do Computers Work? – gnat Jan 3 '18 at 17:56
  • 1
    What makes you think that when you ask the CPU to load a single byte it actually requests and loads a single byte from memory (or that the memory bus is even capable of that), and not, say, load 64 bits or some other amount and then discard all the stuff it doesn't need? – Ordous Jan 3 '18 at 18:05
  • What about 8-bit processors (8086, Z80) that had 8-bit data busses? – DylanG Jan 3 '18 at 18:08
  • 8-bit processors, such as the 8080 or Z80, will make several memory fetches to load a double-word. Both the architecture and implementation affect how and when data is fetched. – BobDalgleish Jan 3 '18 at 18:32
  • @gnat this is a very specific question and not a duplicate of the very general question you're referring to. – Christophe Jan 3 '18 at 18:54
10

Because the width of the data bus and the size of the smallest addressable unit are two separate things.

Just because you can specify addresses at the byte level, does not mean you have to have an 8 bit data bus. Most (possibly all) modern x86 processors use a 64 bit data bus and every time they read from memory, they read 64 bits. If you only requested 8 bits, the excess is simply discarded.

If you request more than 64 bits (for example, if loading 128 bit SSE registers), then there will be multiple memory accesses.

Many processors also have a concept of alignment, which basically means that every memory access is on a address divisible by the data bus width. Most can still fetch unaligned memory, but if it crosses an alignment boundary (for example, requesting 32 bits at address 0xFC on a 64 bit aligned system), you'll get multiple memory accesses, even if it would otherwise fit in the data bus.


Here's a few other notes regarding some aspects of your question:

  • A single memory access takes longer than one cpu clock cycle. Much, MUCH longer if it's not in L1 cache. See this post for rough orders of magnitude, and keep in mind that 1 nanosecond = 1 clock cycle at 1 GHz. Many desktop and laptop CPUs these days can run upwards of 3 GHz, or less than 0.333... nanoseconds per cycle.
  • One clock cycle does not equal one instruction. Instructions (even those that stay entirely within the CPU, not accessing any memory or peripherals) can take multiple cycles to complete. Additionally, multiple instructions can be executing at the same time (and I'm not referring to multiple cores or hyperthreading here, I mean multiple instructions simultaneously executing on a single core, without hyperthreading).
5
  • If you had a c++ char type that has an address that starts in the 16th bit of the bus, and you read the memory it is in, is the data shifted so that it occupies the least significant bits in the register? – Matias Chara Jul 14 '20 at 20:22
  • 1
    @MatiasChara Probably, but it will depend on the implementation. And specifically for x86 or x86_64 targets, it may vary even within one specific implementation due to how certain registers can be accessed. The A register, for example, can be accessed as RAX for all 64 bits, as EAX for the low 32 bits, as AX for the low 16 bits, as AL for the low 8 bits, or as AH for bits 8-15. Whether any major x86 C++ compilers actually make use of AH, I do not know, but the possibility does exist. – 8bittree Jul 14 '20 at 20:44
  • if you would like to answer a question of mine regarding this, go here: stackoverflow.com/q/62903677/4416169 – Matias Chara Jul 14 '20 at 20:47
  • Modern x86 CPUs have caches. On a cache miss, the CPU will pull in the whole line. A 128-bit SSE load can grab 16 bytes from L1d cache, regardless of the various narrow and wide busses data had to go through on its journey to get from DRAM to L1 data cache. (Assuming a CPU with full-width load/store units, otherwise it only pulls from cache in 8-byte chunks and has to split up wide SIMD loads/stores, like Pentium III / Pentium M for SSE, and like Sandybridge for AVX.) How can cache be that fast? – Peter Cordes Apr 15 at 21:08
  • Even a 128-bit load from an uncacheable memory region would only make the DDR4 memory controller send one read-burst command to the DIMMs. It might chop the burst if that's supported, after 2 or 4 cycles of 8-byte transfers (en.wikipedia.org/wiki/DDR4_SDRAM#Command_encoding) instead of letting the burst run for a full 64-byte transfer, but the data coming back to the CPU core will come as one "message" over the CPUs internal busses between memory controllers and cores (e.g. the ring bus in Sandybridge-family), or across sockets for non-local memory (e.g. Hypertransport in old AMD). – Peter Cordes Apr 15 at 21:13
3

As an example to illustrate the workings, let's first talk about a classic 32-bit processor like the good old 68020.

For various reasons (compatibility, usability for ASCII characters, ...), even 32-bit and 64-bit CPUs have names (called "addresses") for individual bytes. If the CPU needs to name a bigger chunk of memory, e.g. 4 bytes, it uses the name for the first byte, and implicitly the following bytes are the ones with the immediately following address numbers.

On the other hand, the bus can transfer 32 bits at once, because the CPU has 32 data lines D0...D32. So, of the 32 bit of an address, the lower 2 bits select a group of data lines (bits 00 select D0...D7, 01 selects D8...D15, 10 selects D16...D23, and 11 selects D24...D31). Only the higher 30 address bits exist as real address lines A2...A32. Instead of the lower 2 bits, the CPU has four distinct byte-select signals that it can use individually in different combinations.

Now, if the CPU wants to read 32 bits from address 0x1000, it can use all 32 data lines in parallel. It places the higher 30 bits on the address bus, and sets all four byte-select signals, so it transfers 4 bytes.

Let's get some overview:

  • read byte from 0x1000: Address bus = 0x1000, Byte-Select 0
  • read byte from 0x1001: Address bus = 0x1000, Byte-Select 1
  • read byte from 0x1002: Address bus = 0x1000, Byte-Select 2
  • read byte from 0x1003: Address bus = 0x1000, Byte-Select 3
  • read byte from 0x1004: Address bus = 0x1004, Byte-Select 0
  • read short from 0x1000: Address bus = 0x1000, Byte-Select 0+1
  • read short from 0x1002: Address bus = 0x1000, Byte-Select 2+3
  • read int from 0x1000: Address bus = 0x1000, Byte-Select 0+1+2+3
  • read (unaligned) int from 0x1002: (first cycle) Address bus = 0x1000, Byte-Select 2+3, then (second cycle) Address bus = 0x1004, Byte-Select 0+1

With current CPUs the principle stays the same, but with internal cache memory you can no longer observe the individual byte transfers of the CPU core from the outside. They happen between the CPU core and the cache (both on-chip). The memory only talks with the cache now, and that transfer is always done in bigger chunks than a byte.

2
  • All modern processors have byte-addressable memory. But back in the day when your 68020 was a hot new thing, byte-addressability was not a universal feature. E.g., PDP-10 computers, could only fetch 18 or 36 bits at a time. – Solomon Slow Jan 3 '18 at 19:55
  • @jameslarge Yes, there have even been machines (a Data General one, if I remeber correctly) where the byte-address of one memory location differed from the longword-address of the same location by a factor of 4. C programs had to make heavy use of pointer casting when using malloc()-style dynamic memory. – Ralf Kleberhoff Jan 4 '18 at 9:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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