Embedded CPU simulators can generally be programmed to also simulate hardware. All the virtualization technologies other than Xen do that. But you need to write code that pretends to have some registers at some physical address or, on x86, an address on the I/O bus, and then you need to respond to reads and writes to these addresses as if your software was a physical chip whose control and status registers were being accessed.
If you want to do this, I would suggest modifying QEMU. But it would not be easy. This sort of thing is generally only done when you are designing a custom chip with a microcontroller and some other cores for your I/O.
The development system sold by ARM Holdings provides for this and is likely easier to work with than hacking on QEMU, but is very expensive.
There are several Open Source ARM emulators that run a single subroutine, which itself can call other subroutines, that you can use for debugging tuning the performance of subroutines that don't depend on hardware access. I used one of these to great success to optimize an AES encryptor for ARM7TDMI.
You could write a simple unit test harness in C or C++, link the class or subroutine under test to it, then run it in the simulator.
I've been pondering a similar problem for years, how to unit test Linux or Mac OS X kernel code. It should be possible, but I've never actually tried. One possibly is to build a full kernel rather than testing your code in isolation, with the unit test framework linked directly into your kernel. You would then fire off the unit tests from some kind of external interface.
Maybe it would be more productive to use a code coverage tool, then test your firmware as a complete package through its external interface. The coverage tool would find code paths that were not yet tested, so you could then add additional external tests in an attempt to get more coverage.