In contrast, MCUs/CPUs with a von Neumann architecture, such as ARM (or even x86), have a unified and contiguous address space. The code memory/RAM/CPU registers, and even the video memory of a PC, are all uniformly addressed. It's just that different types of memory occupy different address blocks and operate independently.
Okay, let's get back to the MCS-51.
Program memory consists of two parts: on-chip and off-chip. Both on-chip and off-chip program memory share the same address space. If there's a 4KB on-chip ROM, the address range is 0x0000-0x0FFF, while the address space from 0x1000-0xFFFF is the external ROM address space. Whether the 0x0000-0x0FFF portion of the external ROM is used depends on the voltage level of the microcontroller's EA pin. When EA=1, this portion of the internal ROM is used, and the external ROM portion is wasted; when EA=0, the external ROM portion is used, and the internal ROM portion is wasted. Reading data from the CODE segment requires the assembly instruction MOVC. The microcontroller automatically determines which memory location to retrieve data from based on the MOVC instruction, the EA status, and the address value to be read.
Data memory is divided into internal data memory (IDATA/RAM) and external data memory (XDATA), but these two memories do not share an address space like code memory. In a typical 8051 chip, the internal RAM is only 128 bytes, from 0x00 to 0x7F, while 0x80 to 0xFF is the SFR (CPU working registers and various peripheral registers) area. For the 8052, the internal RAM is 256 bytes, so 0x80-0xFF is the higher 128 bytes of RAM in use. Isn't this part dedicated to SFRs? Yes, it is, but note that SFR access can only use "direct addressing mode" (implemented using specific assembly instructions). The difference lies here. Only addresses accessed through direct addressing are SFRs; otherwise, it's ordinary RAM. As for the external RAM (XDATA), the address range is also from 0x0000 to 0xFFFF, and the 0x0000 address here is different from the 0x00 address in the internal RAM; they are two completely independent spaces. Their access methods are also different. The MCS-51 uses the MOVX instruction to read and write the XDATA area. Furthermore, accessing the XDATA area requires the assistance of the DPTR register, as only the DPTR can hold a 16-bit XDATA address.
Therefore, the MCS-51 has the fastest speed for reading and writing to the IDATA area, and also the most access methods. Accessing the XDATA area is relatively much slower. The MCS-51's stack should be allocated in the IDATA area first, and the stack allocated in the IDATA area can be controlled using the stack pointer register SP. If the stack is too large and can only be allocated in the XDATA area, then it is difficult to use the CPU's SP register, and we must construct the stack structure and stack pointer ourselves. Since the external program space and data space are both 0-64K (0x0000-0xFFFF), for reasons such as convenience/rewriting programs, the external CODE and DATA can actually share a single erasable and writable memory (such as various erasable and writable RAMs). For example, if the system has a 64K external memory, the lower 32K can be used to store the CODE and allow the microcontroller to read and run programs within this 32K, while the upper 32K can be used to store user data, which is perfectly acceptable. However, the originally completely independent CODE and DATA spaces now share a memory on the hardware chip, which means they can potentially influence each other, allowing the program to rewrite itself. For example, if there's an instruction at address 0x0020, and I modify address 0x0020 using MOVX, then when I read the data from address 0x0020 using MOVC, the data will be different from the original.
The crux of the confusion lies in the fact that microcontroller memory space is a logical concept, two artificially defined and independent spaces. The memory chip on the hardware circuitry, however, is a real-world concept; the microcontroller's memory space ultimately resides on the chip at the circuit level. Therefore, the logical memory spaces may overlap due to physical circuit connections. But logically, these two spaces remain completely independent.
Appendix: Definitions of various storage space names:
data: This refers to the 128 RAM bytes from 0x00 to 0x7f, which can be read and written directly using register a. This method is the fastest and generates the smallest amount of code.
`idata`: This refers to the first 256 bytes of RAM (0x00-0xff), with the first 128 bytes being identical to the first 128 bytes of `data`, differing only in the access method. `idata` is accessed using a pointer-like method similar to C. The assembly statement is: `mov ACC,@Rx`. (Minor note: In C, pointer-like access using `idata` works very well.) `xdata`: External extended RAM, generally referring to the external space 0x0000-0xffff, accessed using `DPTR`. `pdata`: The lower 256 bytes of external extended RAM, read and written when the address appears in A0-A7, using `movx ACC,@Rx`. This is somewhat special, and C51 seems to have a bug related to it, so it's recommended to use it sparingly. However, it also has its advantages; its specific usage is an intermediate-level issue, which I'm not familiar with, so I won't discuss it here.