How to access the data from RAM and ROM(Flash)
It depends on the architecture -- there are two schools of thought on this, going back to the 1940's.

One is called Harvard architecture, and means that the addresses for flash program code, RAM storage, and I/O are all in separate address spaces.  That means there can be an address 0x100 for program, 0x100 for RAM, and 0x100 for I/O and they are all different.

The second type is called Von Neumann architecture, in which flash program code and RAM are in the same address space.  I/O may also be in the same address space, if it is "memory-mapped", or separate if it uses I/O port addressing.

Most microprocessors like the 0x86 in your desktop have a Von Neumann architecture.  Both program code and data are stored together in the same RAM.  There is also a separate read-only memory (ROM) that holds a bit of code that is executed when the processor first boots up, to load the OS (Windows, Linux, etc) off of the hard drive and into RAM.  This ROM is also in the same address space, typically at the very high end.

Most, but not all microcontrollers on the other hand use use Harvard architecture. 8 or 16-bit microcontrollers typically have up to 64K of flash program memory, and several thousands bytes of RAM.  (Flash may be extended beyond 64K using various paging schemes -- but the actual addresses are still 16-bit and stay in the same address space). I/O is addressed via internal I/O register addresses.

An exception to this, among others, are Freescale microcontrollers like the MC9S08 etc. which put flash program addresses, RAM, and memory-mapped I/O all in the same address space.



Note in this diagram, memory is shown with address 0x0000 at the top, and 0xFFFF (64K-1) at the bottom.  The low-order memory-mapped I/O addresses 0x0000 through 0x007F are allocated first, followed by RAM at 0x0080 to 0x17FF.  This is done so low addressed I/O and low addressed RAM (0x0080-0xFF) can use special instructions that target the first 256 bytes of the 64K address space -- those address below 0x00FF which only need one byte for the address field (known as "page 0 addressing").

The RAM segment is followed by more memory-mapped I/O, then more RAM, and then the first block of flash starting at 0x2180.  This is interrupted by 2K of EEPROM at 0x3C00, and then the rest of the program space up to 0xFFFF is flash.  There is a paging window at 0x8000 through 0xBFFF to provide for an additional 32K of flash.

In a Von Neumann machine, if you try to allocate at address 0x300, then that address will point to either RAM, or flash, but not both.  So there is no conflict.

In a Harvard architecture machine, address 0x300 could be either RAM or flash.  So how is that differentiated?  This is C-compiler specific, so it will be different for different microcontrollers.  But by default, all references to memory addresses will be for RAM.  However if a variable is preceded by the C keyword const, then that data is put into flash.  (And of course all other constants, such as strings, are automatically put into flash by  the compiler.)

If a program wants to read flash memory directly, it typically has to call a vendor supplied function and/or writing to a set of special registers to do so.  For example, on the Microchip PIC16F microcontrollers, it takes 13 machine instructions just to read one program word (14 bits) out of flash.  And this is certainly the case if a program wants to write to flash, since the MCU has to go through several steps to erase and then reprogram the bytes in flash that are to be changed.

For microcontrollers, memory protection is generally available only for flash memory -- and this protection simply means neither a program or external programmer can modify the flash area while protection is on.  This is usually done in pages, so some of the flash can be protected (e.g. a boot area) and the rest left unprotected so it can be updated in the field FOTA (firmware over the air).  Many microcontrollers also have the ability to make the flash memory unreadable by an external programmer after the microcontroller has been programmed.  This is to prevent a competitor from trying to read the binary program out of a company's products.

Microprocessors, like the 0x86, have much more complicated protection schemes, tied into their virtual address schemes, and at a basic level divide the RAM into kernel and user spaces.  (Remember, they are 99.99% RAM, and hardly any ROM).  Kernel space is where the core of the operating system lives, along with most device drivers.  Application programs are in the user space.  A memory protection fault occurs if a user program tries to execute a privileged kernel instruction, or access hardware directly.