Memory Assignment: PC vs. Microcontroller

Thread Starter

Kittu20

Joined Oct 12, 2022
482
I'm curious about the reasons why we typically can't directly assign memory addresses to variables when programming in C, especially on a PC. However, in microcontroller programming, direct memory addressing is possible.

Could someone help me on the technical and practical constraints that prevent us from directly assigning memory addresses on PC?
 

BobTPH

Joined Jun 5, 2013
9,130
PCs use a virtual memory scheme. That allows each program to have it’s own virtual address space. In 32 and 64 bit mode, it is as if each program uses memory starting at address 0.

The actual physical memory is allocated as needed as the programs run. It would be useless (and dangerous) to store a physical address, since it changes during the execution of the program.

This has many advantages in a multi-tasking system. Read up on virtual memory for more details.
 

MrChips

Joined Oct 2, 2009
30,931
Simple. On a PC you have no control on memory selection. Your code and data space is assigned by the OS.

Imagine that you walk into a very large hotel and ask to stay in room 1234. The hotel clerk will say, ”Sorry, that room is already occupied but I can let you have a different room”.
 

ApacheKid

Joined Jan 12, 2015
1,658
I'm curious about the reasons why we typically can't directly assign memory addresses to variables when programming in C, especially on a PC. However, in microcontroller programming, direct memory addressing is possible.

Could someone help me on the technical and practical constraints that prevent us from directly assigning memory addresses on PC?
On an OS that uses virtual memory, user mode code cannot access specific physical addresses, this is by design. One can access specific addresses if the code is executing in kernel mode though. So device drivers can do this without any problems.

A user mode process has an address space that is split into two parts, the lower part is shared across all processes and is where OS data resides, user mode code has almost no access that address range. The upper part is private to each process. Even so all of the address space is virtual meaning an address as seen by the CPU is not a true physical hardware address.

This article will explain this well.

Many ARM CPUs can also act this way but unless they are running an OS you'll never see it, there is no virtual memory.
 

nsaspook

Joined Aug 27, 2009
13,418
I'm curious about the reasons why we typically can't directly assign memory addresses to variables when programming in C, especially on a PC. However, in microcontroller programming, direct memory addressing is possible.

Could someone help me on the technical and practical constraints that prevent us from directly assigning memory addresses on PC?
It's not C the language that restricts, it's the hardware.
On a x86 PC the OS can/does directly assign memory addresses to variables in C but you must be in a 'kernel' privileged CPU mode to bypass normal user MMU address translation. Most controllers boot to a 'kernel' mode because that's the only mode they have but many 32-bit controllers will have at least some capabilities of memory translation and protection to allow for OS level VM (with address translation) and process protection from random application memory access.
https://developerhelp.microchip.com/xwiki/bin/view/products/mcu-mpu/32bit-mcu/PIC32/mz-arch-cpu-overview/memory-organization-overview/address-translation/#:~:text=Virtual addresses used by software,sent to the system bus.&text=For a typical PIC32MZ application,/KSEG1/KSEG2 are used.

https://developerhelp.microchip.com...u/32bit-mcu/PIC32/virtual-vs-physical-memory/

When the CPU is in Kernel mode (default after reset and during exceptions) there are two segments used to access internal memory:

  • KSEG0: Internal memory access - cacheable
  • KSEG1: Internal memory access - not cacheable
KSEG0 and KSEG1 share the same physical addresses and use Fixed Mapping Translation (FMT) to translate virtual to physical addresses. Every virtual address has its own constant corresponding physical address.

Your application can choose to use cache or not based on the segment used to address physical memory.

1713633002716.png
1713633226822.png
C:
/* This array is the offscreen frame buffer used for rendering.
** It isn't possible to read back frome the OLED display device,
** so display data is rendered into this offscreen buffer and then
** copied to the display.
*  must be in uncached memory for pic32 DMA so use __attribute__((coherent))
* DMA0 SPI TX transfers DATA, CMD
* DMA1 GLCD buffer transfers
* DMA2 SPI TX transfers CMD, NOT USED
*/
#ifdef __32MK0512MCJ048__    // NO bank 2 for this CPU so memory is in bank 1
uint8_t __attribute__((address(BANK1), coherent)) rgbOledBmp0[cbOledDispMax]; // two display buffers for page flipping
uint8_t __attribute__((address(BANK1 + cbOledDispMax), coherent)) rgbOledBmp1[cbOledDispMax];
#ifdef USE_DMA
static uint8_t __attribute__((address(BANK1 - 8), coherent)) rgbOledBmp_blank[4] = {0x00, 0x00, 0x00, 0x00}; // 32-bit frame-buffer clearing variable
#endif
volatile uint8_t __attribute__((address(BANK1 - 16), coherent)) rgbOledBmp_page[5];
#endif

#ifdef __32MZ1025W104132__    // bank 2 for this CPU
uint8_t __attribute__((address(BANK2), coherent)) rgbOledBmp0[cbOledDispMax]; // two display buffers for page flipping
uint8_t __attribute__((address(BANK2 + cbOledDispMax), coherent)) rgbOledBmp1[cbOledDispMax];
#ifdef USE_DMA
static uint8_t __attribute__((address(BANK2 - 8), coherent)) rgbOledBmp_blank[4] = {0x00, 0x00, 0x00, 0x00}; // 32-bit frame-buffer clearing variable
#endif
volatile uint8_t __attribute__((address(BANK2 - 16), coherent)) rgbOledBmp_page[5];
#endif
https://developerhelp.microchip.com...pu-overview/cache-defined/maintain-coherency/
Static Variables
Static variables can be created using the coherent attribute. This assigns a variable or array to the un-cached KSEG1 memory segment.

unsigned int __attribute__((coherent)) buffer[1024];
The coherent variable attribute causes the compiler/linker to place the variable into a unique section that is allocated to the KSEG1 region, rather than the KSEG0 region (which is the default on L1 cached devices). This means that the variable is accessed through the uncached address.
 
Last edited:
Top