Realize I didn't mention x86 or any more details to make this non-specific to any platform, but to just get a general idea of how this is done(this is also a long question with a lot of details).
I know most PC motherboards for desktop (if not all) computers have two sections; north and south bridge, and a chipset connects them together between the CPU's implementation and the buses carrying data around the board.
The x86 CPU has a register, I think, called the accumulator, which has eight bit AL, sixteen bit AX, and thirty-two bit EAX. Data for these registers are typically used for arithmetic operations, general purpose machine instruction, etc.
Also, supposedly for I/O access, such as with Port I/O. There is Port I/O and MMIO (memory-mapped input/output), which are two methods of accessing data outside the CPU.
I have inspected memory maps, but I'm still unclear on whether or not it's part of an instruction fetched from memory (i.e., MOV AL, 0FF) or from some other instruction to actually access hardware.
My basic question is, what specific instructions are used to write and read data from hardware, from a bare machine perspective; no device drivers, no operating system, and no firmware interrupts. This is the very essence of how system software must be made, and there's little complete coverage on how this works from the CPU's register to the hardware itself. I have seen BIOS interrupts, but that abstracts away details. Also, the developer had no idea what happens beyond INT 13.
So, despite my broad question, is there some specific way this is accomplished, either by instruction, correct value set in a register, etc.?
Example: Say I want to make a few beep noises. The sound hardware is responsible for making any noise at all, so I would, from a bare machine perspective, once again, have to directly access the hardware and its components, circuitry, or otherwise internal hardware registers or such to make noise. Is there a complimentary way of doing this that is specifically outlined or guidelined per-platform, or does it vary based on every specific piece of hardware and CPU?
If so, what would help me unravel that mystery to program for it this way? Would the card be, let's say, mapped a special address you write to? Then I would just set a register and the CPU will just send it there with whatever value it contains?
I am confused, and nothing makes clarity of this, because abstractions exist even at the low-level that create a barrier of the unknown.