If a 32-bit processor can handle approximately 4 GiB of RAM (i.e. \$2^{32} = 4 294 967 296\$) bytes, why does my Arduino Mega 2560 have 8 KiB of SRAM, if being a 8-bit processor allows it to handle just 256 bytes (\$2^8\$)? Or am I reading the following page wrong?


  • 6
    \$\begingroup\$ Surely any turing-complete machine is capable of addressing almost any size of ram, given enough time. \$\endgroup\$
    – John U
    Feb 14, 2013 at 10:00
  • 2
    \$\begingroup\$ Actually the number of bits in a processor name can only be used for an up-front estimation of the internal data width. The 8088 is a 16-bit processor because of its 16-bit registers but has an 8-bit data bus and a 20-bit address bus. The 68000 is a 32-bit processor mostly called 16/32-bit because of its 32-bit registers but has a 16-bit data bus and a 24-bit address bus. Small ARM implementations are 32-bit processors (32-bit registers and data-bus) but even if they use 32 bits for addresses they can't address a total of 4 GB. \$\endgroup\$ Dec 12, 2019 at 8:29
  • \$\begingroup\$ I've added the correct SI prefixes for these units. \$2^{30}\$ is gibi (Gi) and \$2^{10}\$ is kibi (Ki). \$\endgroup\$ Dec 12, 2019 at 13:22
  • \$\begingroup\$ It's worth mentioning that many 8 bitters (particularly Motorola derivatives) support a so-called zero-page, which was instruction set support for handling the first 256 addressable bytes in the memory map slightly faster. So the most time-critical hardware registers etc would be mapped into the first 256 bytes for this performance reason. This is the reason why you'll find hardware registers mapped from address zero on lots of architectures. \$\endgroup\$
    – Lundin
    Feb 14, 2020 at 15:01
  • \$\begingroup\$ calling something an 8-bit, 16-bit, 32-bit etc is lets say a marketing term, engineers use it to but understand that doesnt mean everything in that processor is that wide. some folks use the size of the instruction, very often the size of the general purpose registers is used, sometimes the bus. you have the program counter which isnt always accessible or usable in instructions so that can be as wide as they want. then as with many of the AVR type processors there is a multi register or paging scheme or both to get a wider load/store address for data transactions. \$\endgroup\$
    – old_timer
    Feb 14, 2020 at 16:23

9 Answers 9


Most 8 bit CPUs have 16 bit address buses allowing them to address 64kbytes, precisely because 256 bytes really isn't enough to do very much! It just means they need to load two bytes instead of one, each time they need to load an address. Slightly slower but tolerable considering their size.

(And yes there are many exceptions, mostly developed when 64k became too small, but we're talking about the basic idea here).

  • \$\begingroup\$ In fact most of the 8-bit microcontrollers I've encountered don't have 16-bit address \$\endgroup\$
    – phuclv
    May 7, 2014 at 1:27
  • \$\begingroup\$ @Brian Drummond Am I correct: Controller will write lower 8 bits first then upper 8 bits and then Latch the address bus. This is how it will access 16bit address bus! \$\endgroup\$
    – Swanand
    May 7, 2014 at 3:42
  • \$\begingroup\$ Or upper 8 bits then lower 8 bits, but basically yes, that's the idea. \$\endgroup\$
    – user16324
    May 7, 2014 at 11:09
  • \$\begingroup\$ Some Micro-controllers like the PIC18 have a segment register that allows them to expand their address space beyond what can be encoded in the 16-bit instruction set. Additionally the use of IO pins as chip selects on external RAM banks can be used to expand memory. \$\endgroup\$
    – user4574
    Aug 4, 2020 at 21:03

The address bus and data bus are separated so they may have different sizes. For any specific address bus sizes there are a lot of techniques to address more memory than the register bit width

  • The most common way is increasing the address bus width somehow by

    • using multiple registers for the address

      • AVR has R26..R31 that can be paired into 16-bit X, Y and Z data addressing registers to allow maximum 64KB of RAM. Those in turn can be paired with RAMPX, RAMPY, RAMPZ to access higher RAM addresses in even bigger versions. It also has SPH for the high bytes of the stack pointer in addition to SPL in variants with more than 256 bytes of RAM1
      • Intel 8080 and Zilog Z80 are 8-bit CPUs, but they have register pairs like H & L, B & C, D & E that can be used together as a 16-bit address register
    • using a single big special register bigger than the natural size for addressing

      • Intel 8051 is an 8-bit microcontroller, i.e. it has 8-bit data address. However it uses 16-bit instruction address and has 2 16-bit registers: PC and DPTR for addressing in instruction space.
      • AVR has a 16 or 22-bit PC register
    • using a special register for the high part of the address. When addressing some memory, by default the 8 low bits of the address will be taken from the 8-bit immediate or 8-bit register on an 8-bit microcontroller, whereas the high bits will be replaced by the other address register's value.

      • A special case of this is segmented memory, which is used by the 16-bit x86. In this technique the memory is divided into multiple segments of size 64KB (216 bytes). Normal access is inside a single segment by default so they can use 16-bit address for near data. Data that are further apart must be addressed specifically by segment value, therefore 2 registers must be used for far addressing.
      • The PIC microcontroller, whose baseline and mid-range series may have 13 or 14-bit address, is another example. When using call or goto instruction, 8 or 9 low bits of the address is indicated by the immediate and the remaining is taken from the current program counter. So accessing anything not far around the current segment uses only 1 instruction, while further addresses will need 2 instructions (to set the high bits).
      • Another example is the MIPS architecture which also combines the lower 26-bit immediate address with the high 6 bits from PC while unconditionally jumping.
  • Another way to achieve this is memory banking. This is a useful method still being used in some architectures nowadays. In this model, memory is divided into multiple banks. Each time you can only address a specific bank. There are often a global bank or address range that are always visible at anytime, but for other parts you must switch bank when needed.

    • Intel 8051 uses memory banking for the registers. It has 32 registers but only 8 of them are visible at a time.
    • x86 PAE and ARM LPAE, with bigger physical address space mapped to a small virtual address space
    • Another application for this is the Address Windowing Extensions on Windows which can be used by 32-bit x86 apps in PAE mode in order to access more than 2/3GB of memory. It's not exactly like a memory bank on microcontrollers but can be seen as such, because the big address range can be think of small windows/banks that is small enough to fit in the app's address space. If the app needs to use data in some window it will map that window into its current address space.
    • DOS also has some types of bank switching like expanded memory or extended memory due to its limited range of addressable memory.
  • There is also a not quite common technique but can be found in the Intel 8051. As a microcontroller with 8-bit data address, it can have at most 256 addresses. Half of the space (the high part) is used for special function registers (SFR), limiting the real RAM addressable to only 128 bytes. However modern 8051 series' manufacturers found a clever way to overcome this by seperating memory access. Direct addressing will access the SFR while indirect addressing though the registers will access the high part of RAM which means now you have 256 + 128 = 384 addressable bytes.

1 https://en.wikipedia.org/wiki/Atmel_AVR_instruction_set#Memory_addressing_instructions

The smallest cores have ≤256 bytes of data address space (meaning ≤128 bytes of RAM after I/O ports and other reserved addresses are removed) and ≤8192 bytes (8 KiB) of program ROM. These have only an 8-bit stack pointer (in SPL), and only support the 12-bit relative jump/call instructions RJMP/RCALL. (Because the AVR program counter counts 16-bit words, not bytes, a 12-bit offset is sufficient to address 213 bytes of ROM.)

Additional memory addressing capabilities are present as required to access available resources:

  1. Models with >256 bytes of data address space (≥256 bytes of RAM) have a 16-bit stack pointer, with the high half in the SPH register.
  2. Models with >8 KiB of ROM add the 2-word (22-bit) JUMP and CALL instructions. (Some early models suffer an erratum if a skip instruction is followed by a 2-word instruction.)
  3. Models with >64 KiB of ROM add the ELPM instruction and corresponding RAMPZ register. LPM instructions zero-extend the ROM address in Z; ELPM instructions prepend the RAMPZ register for high bits. This is not the same thing as the more general LPM instruction; there exist "classic" models with only the zero-operand form of ELPM (ATmega103 and at43usb320). When auto-increment is available (most models), it updates the entire 24-bit address including RAMPZ.
  4. (Rare) models with >128 KiB of ROM have a 3-byte program counter. Subroutine calls and returns use an additional byte of stack space, there is a new EIND register to provide additional high bits for indireect jumps and calls, and there are new extended instructions EIJMP and EICALL which use EIND:Z as the destination address. (The previous IJMP and ICALL instructions use zero-extended Z.)
  5. (Rare) models with >64 KiB of RAM address space extend the 16-bit RAM addressing limits with RAMPX, RAMPY, RAMPZ and RAMPD registers. These provide additional high bits for addressing modes which use the X, Y, or Z register pairs, respectively, or the direct addressing instructions LDS/STS. Unlike ROM access, there are no distinct "extended" instructions; instead the RAMP registers are used unconditionally.

Databus lines (pins) and address lines (pins) are completely separate. Simply put, databus lines determine maximum number of bits that can be transferred one at a time (and stored on the memory) whereas address lines determine maximum number of memory "cells" that can be selected.

It was mostly a marketing thing that 32-bit x86 CPUs couldn't address more than 4GB of RAM. I remember somewhere that there were A33-34 pins on Pentium 4 CPUs.

  • 1
    \$\begingroup\$ You are correct - PAE allowed the use of more RAM, but as it wasn't available on desktop Windows not many people ever used it. \$\endgroup\$
    – pjc50
    Feb 13, 2013 at 23:05
  • \$\begingroup\$ PAE is the name of the feature. Also, 64-bit processors can't address 64 exabytes, as \$2^{64}\$ would suggest. \$\endgroup\$
    – Phil Frost
    Feb 13, 2013 at 23:06
  • \$\begingroup\$ x86 CPU's cannot address more than 4GB without significant complications in the operating system which do not port to other architectures. \$\endgroup\$
    – Kaz
    Feb 14, 2013 at 0:51
  • 1
    \$\begingroup\$ @Kaz ARM 32-bit has a similar feature called LPAE, which allows the operating system to address more than 32 bits of address \$\endgroup\$
    – phuclv
    May 7, 2014 at 1:26

Nearly all 8-bit processors have some ability to form a 16-bit address from a low-order part and a high-order part. On some processors including the original 8080, there are registers dedicated to holding the upper and lower part of an address (although from a programmer's standpoint there may be some registers like the 8080's stack pointer which don't offer instructions to address them separately). In some other processors, there aren't registers devoted to the upper or lower half of an address, but addresses are assembled "on the fly". For example, on the 6502, the instruction "LDA $1234,X" loads the accumulator with the address formed by adding $1234 to the 8-bit X register [suppose it contains $F0]. The execution of that instruction would proceed in 4 or 5 steps:

  1. Finish up register write from previous instruction (if any) and load opcode ($BD)
  2. Fetch first operand byte following opcode ($34) while decoding instruction
  3. Fetch second operand byte ($12) while adding previously-fetched byte to X register
  4. Read memory at address formed by concatenating second operand byte to ALU result [i.e. $1224]. Feed second operand byte into ALU to add zero or one depending upon whether previous add generated a carry
  5. Read memory at address formed by replacing upper half with ALU result [$1334]

The transfer of the read byte to the accumulator will overlap the fetching of the next instruction. Additionally, for many operations, if step 3 didn't generate a carry, step 4 would have read the correct address and execution could skip directly from step 4 to the next instruction, bypassing step 5.

If one examines the sequence of operations, one will notice that a little-endian architecture has a definite advantage over a big-endian one, in that in most cases (albeit not the one shown), even though the ALU takes a cycle to perform an addition, it's possible to read a byte from the computed address without waiting for the ALU result, since normally the high byte that was fetched will be the high byte of the target operand. On a big-endian machine with an 8-bit ALU, an indexed load would take at least 5 cycles (since the the lower half of the address wouldn't be read until step 3, and would thus be computed in step 4).

  • \$\begingroup\$ I remember seeing some ads for computers with 8-bit processors and 1 megabyte of memory. This was done by using two 8-bit registers on the CPU plus one 8-bit register not on the CPU to form the entire address. \$\endgroup\$
    – user6030
    Jun 22, 2017 at 21:55
  • \$\begingroup\$ @user6030: There are many ways of accomplishing such things. Typically parts of the address space will be "fixed" and others will be bank-selectable. Some devices work out nicely for programmers; many others, not so much. \$\endgroup\$
    – supercat
    Jun 22, 2017 at 22:04

I will answer this question specifically for the AVR controllers you mentioned. The basic principle also holds true for many other 8-bit architectures.

AVRs are 8-bit cores. This means they have 8-bit Registers. However, 8 bits are not enough to access a usable amount of memory. Therefore, the AVR core is able to use a specific set of registers combined as 16 bit pointer registers. The registers r30 and r31 (also aliased as ZL and ZH) are an example for this. Together they form the Z Pointer.

In assembly reading a byte at address 0x1234 would looks like this:

ldi ZL, 0x34 ; Load r30 (ZL) with low byte of address
ldi ZH, 0x12 ; Load r31 (ZH) with high byte of address
ld r16, Z    ; Load byte to r16

The AVR family has 3 register pairs that can be used for this. They are specifically designed in hardware to allow such operations.

When programming in a higher level language like C, the compiler handles this stuff.

Note: Some AVRs even support bigger memory sizes than 64k. These controllers have a special function register in which additional bits of the address are written before the access. The address therefore consists of following bits (MSB to LSB):

Special function register (usually only 1 bit is used), ZH (8bit), ZL (8bit). This results in a total address of 17 bit and allows accessing 128 kiB of RAM.


It's often true that there is some relationship between addressable memory size and internal register size, though the relationship varies for different reasons. 256 bytes of address space was considered too small even in the very early days of microprocessors, so most eight bit processors produced 16 bit (two byte) addresses, which addressed 64 kilobytes. With bank switching, though (essentially using certain I/O lines to produce even more address lines), it was possible to have much more.

In the first 16 and 32 bit processors, there weren't always enough pins on the device to reach all the space that their internal address registers could address. For example, on the Motorola 68000, there were only enough address pins (24) to address 16 megabytes of RAM, though the internal address registers were 32 bits wide.


Wikipedia explains it pretty well:

Eight-bit CPUs use an 8-bit data bus and can therefore access 8 bits of data in a single machine instruction. The address bus is typically a double octet wide (i.e. 16-bit), due to practical and economical considerations. This implies a direct address space of only 64 KB on most 8-bit processors.


Atmel's 8 bit AVR's actually use a 16 bit data address. The have numerous other 16 bit registers and even some 16 bit timers. Since it is only an 8 bit processor, it usually uses two clock cycles to load a 16 bit register.


The notion that the "bit width" of a processor establishes the maximum amount of RAM the processor can address is one of the most pervasive myths in computing. In fact the industry history is just littered with CPUs for which this relationship did not hold.

HP 21MX, HP 1000: 16-bit CPU, memory to 16 MB

PDP-11: 16-bit CPU, memory to 4 MB

VAX-11/780: 32-bit CPU, memory to 512 MB

etc., etc.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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