Я согласен с вышеизложенным. Стандартным решением этого является определение непрозрачного абстрагированного набора вызовов функций, которые являются «драйвером» для hw, а затем вызов этого в основной программе. Затем предоставьте две разные реализации драйвера, одну для hw, одну для sw. Вариант sw будет соответствующим образом имитировать IO-эффект hw.
Обратите внимание, что если цель находится на более низком уровне, т. Е. Написание кода, в котором должен быть смоделирован каждый аппаратный доступ, а не целые функции, это может быть немного сложнее. Но здесь могут быть определены разные функции «write_to_memory» и «read_from_memory» (или макросы, если скорость на цели важна).
В любом случае нет необходимости изменять имена функций, достаточно иметь два разных пакетных файла, создавать файлы или целевые объекты сборки IDE (в зависимости от того, какие инструменты вы используете).
Наконец, во многих случаях лучшим техническим решением является использование полнофункционального симулятора целевой системы, такого как Qemu , Simics , SystemC , CoWare , VaST или аналогичные. Это позволяет вам постоянно выполнять один и тот же код, а вместо этого вы строите модель аппаратного обеспечения, которая работает как фактическое аппаратное обеспечение с точки зрения программного обеспечения. Это требует гораздо больших первоначальных инвестиций, но для многих проектов оно того стоит. Это в основном избавляет от неприятной проблемы наличия разных сборок для цели и хоста и гарантирует, что вы всегда будете использовать свой кросс-компилятор с опциями сборки развертывания. Обратите внимание, что многие встроенные компиляторы поставляются с некоторыми базовыми встроенными возможностями симуляции.