In my first job after I received my engineering degree, I was designing hardware and writing software for embedded products for industrial applications. I had a simulator for the microcontroller. I would write the software while I waited for the target system to be constructed. I would write a portion of code, then walk it through using the simulator to exercise the code in the absence of the accoutrements that allow the microcontroller to accomplish the objectives of the product in real life. The simulator’s fidelity to the microcontroller was not perfect.
Eventually, we moved to using an in-circuit emulator (ICE). This tool made development easier. The fidelity of the ICE to the microcontroller was near ideal, and it provided tools that allowed exploration of the microcontroller while performing the action defined in the software (breakpoints, single stepping of instruction, explore registers and memory locations, etc.).