Then a CPU instruction reads something from memory, there's a special circuitry in the CPU and in the MMU in such a way that when the instruction is executed, the address is sent to the MMU, which informs via the BUS that is wants to read from memory and put the information into the destination register. I've also learned that some addresses which would normally correspond to RAM are mapped to some devices. So I guess that there's a way to first, tell at which addresses some devices are going to me mapped. Then, we fool the processor in trying to read from a memory address, and by some circuitry, it ends up reading the device instead.
Where can I find a better explanation for it? Specially for x86 architecture which deals with PCI and more well known devices.
There are no instructions1 that are responsible for the mapping of devices into memory.
A complete answer would be too broad, but we can make an example or two.
First of all, convince your self that a device can be configured by simply telling it to what address to listen to. At the hardware level this is nothing more that a comparison.
Some devices have fixed addresses.
These are the legacy devices, present at the first launch of the system and cloned by other competitors and successive versions for backward compatibility.
Configurable devices.
These devices have jumpers/switches to select the address range to listen to. It was the task of the user to avoid conflict and configure the software appropriately.
Plug and play devices.
The most famous PnP bus is PCI, but ISA and MCA where PnP too (ISA was "sort of" PnP).
These devices are like the one above, but are configurable in software, also the resources they need (IRQ, DMA, MMIO) are enumerable to let the firmware and OS allocated them without conflicts.
Now you wonder how the option 3 can be achieved. The answer is simple: with a meta address space.
In the case of PCI for example, the addresses 0cf8h and 0cfch2 where used to select a device, a register on the device configuration space, and to read or write that register.
The registers in the configuration space can be used to rebase the device.
Let's assume that the register 10h holds the address where the device listen to, then this pseudo code maps the device at 88888888h
As you can see, deferencing the pointers generates a write to the memory locations 0cf8h and 0cfch, but these locations are not routed, by the hardware, to the main memory, rather they go to the Host-to-PCI bridge controller that convert them into PCI configuration space accesses that will be picked up by the interested device.
When, later, an access to 88888888h is made, this is again not routed to be main memory3 but to the PCI bus (usually as the result of subtractive decoding) where the configured device is listening.
1 In the sense that there are no specially crafted CPU instructions. Everything is the result of some instructions being executed, so in a sense some "must be responsible" for the devices being mapped. I assume, for the rest of this answer, that you want to know how MMIO works.
2 Only for x86 in the IO address space, but let not this distract us.
3 The hardware knows where memory ends, if the software map a device where there actually is memory, the latter takes precedence and no access to the device is made.