Я работаю над проектом, который предполагает подключение нескольких устройств, каждое из которых имеет встроенный (ARM) процессор.Одним из подходов к разработке, который я нашел полезным в прошлом для проектов, в которых использовался только один встроенный процессор, была разработка кода с использованием Visual Studio, разделенного на три части:
- Основной код приложения (в неуправляемом C /C ++ [см. Примечание])
- Код, имитирующий ввод / вывод (C / C ++), который выполняется в Visual Studio
- Встроенный код ввода / вывода (C), который Visual Studio не должен создавать, выполняется на целисистема.Ранее этот код был для PIC;для большинства будущих проектов я перехожу на ARM.
Подача встроенного компилятора / компоновщика кода из частей 1 и 3 приводит к получению шестнадцатеричного файла, который может работать в целевой системе.Совместное выполнение частей 1 и 2 дает код, который может выполняться на ПК, с преимуществами более совершенных средств отладки и более точного контроля за поведением ввода-вывода (например, я могу сделать так, чтобы код моделирования вводил некоторые типы случайных отклонений более легко, чем я могу)вызывать управляемые икоты на реальном оборудовании).
Целевой код написан на C, но среда моделирования использует C ++ для моделирования регистров ввода-вывода.Например, у меня есть структура данных PortArray;файл заголовка для встроенного компилятора содержит строку типа unsigned char LATA @ 0xF89;
, а мой файл заголовка для моделирования включает #define LATA _IOBIT(f89,1)
, который, в свою очередь, вызывает макрос, который обращается к подходящему свойству объекта ввода / вывода, поэтому такой оператор, как LATA |= 4;
, будетпрочитайте смоделированную защелку "или" прочитанное значение с помощью 4 и запишите новое значение.Чтобы это работало, целевой код должен компилироваться как в C ++, так и в C, но в большинстве случаев это не проблема.Наибольшее раздражение, вероятно, вызывают типы enum
(которые ведут себя как целые числа в C, но для этого их необходимо уговорить в C ++).
Ранее я использовал два подхода для создания интерактивной симуляции:
- Скомпилируйте и свяжите DLL с целевым приложением и кодом моделирования, и получите VB-код в том же проекте, который взаимодействует с ним.
- Скомпилируйте код целевого приложения и некоторый код моделирования в EXE-файл с экземпляром Visual Studio и используйте второй экземпляр Visual Studio для пользовательского интерфейса моделирования.Пусть две программы обмениваются данными через TCP, так что почти вся «реальная» логика ввода / вывода находится в программе симуляции.Например, вышеупомянутая `LATA | = 4;` будет отправлять команду «read port 0xF89» на порт TCP, получать ответ, обрабатывать полученное значение и отправлять команду «write port 0xF89» с результатом.
Я обнаружил, что последний подход в некоторых случаях работает чуть медленнее, чем первый, но он кажется гораздо более удобным для отладки, так как я могу приостановить выполнение неуправляемого кода моделирования, пока пользовательский интерфейс моделирования остается отзывчивым.Действительно, для моделирования одного целевого устройства за раз, я думаю, что последний подход работает очень хорошо.Мой вопрос заключается в том, как мне лучше всего симулировать множество целевых устройств (например, 16 из них).
Сложность состоит в том, чтобы выяснить, как заставить каждый моделируемый экземпляр получать свой собственный набор глобальных переменных.Если бы я должен был скомпилировать в EXE и запустить один экземпляр EXE для каждого имитируемого целевого устройства, это работало бы, но я не знаю практического способа поддерживать поддержку отладчика при этом.Другой подход заключается в том, чтобы расположить целевой код так, чтобы все компилировалось как один модуль, объединенный через #include
.В целях моделирования все можно затем обернуть в один класс C ++, в котором глобальные переменные превращаются в переменные экземпляра класса.Это было бы немного более объектно-ориентированным, но мне действительно не нравится идея заставить весь код приложения жить в одном скомпилированном и связанном модуле.
Возможно, было бы идеально, если бы код мог загружать несколько экземпляров DLL, каждый со своим собственным набором глобальных переменных.Однако я не знаю, как это сделать, и не знаю, как заставить вещи взаимодействовать с отладчиком.Я не думаю, что действительно необходимо, чтобы все моделируемые целевые устройства выполняли код одновременно;было бы вполне приемлемо для примеров моделирования использовать совместную многозадачность.Если бы был какой-то способ выяснить, в каком диапазоне памяти хранятся глобальные переменные, можно было бы сделать так, чтобы метод 'task-switch' выменял все глобальные переменные, использованные ранее запущенным экземпляром, и менял содержимое, которое применимо.к включаемому экземпляру. Хотя я бы знал, как это сделать во встроенном контексте, я бы не знал, как это сделать на ПК.
Редактировать
Мои вопросы будут такими:
- Есть ли более приятный способ сделать паузу и проверить логику симуляции в отладчике VS2010, сохраняя отзывчивый пользовательский интерфейс для внешнего интерфейса симулятора, чем запускать внешний интерфейс симулятора и логику симулятора в отдельных экземплярах VS2010, если логика моделирования должна быть записана на C, а внешний интерфейс симуляции в управляемом коде?Например, есть ли способ сообщить отладчику, что при достижении точки останова некоторым или всем другим потокам должно быть разрешено продолжать работу, пока поток, достигший точки останова, приостановлен?
- Если основная часть логики моделирования должна быть совместима с исходным кодом со встроенной системой, написанной на C (так, чтобы одни и те же исходные файлы могли быть скомпилированы и запущены для целей моделирования под VS2010, а затем скомпилированы компилятором встроенных системдля использования в реальном оборудовании), есть ли способ отладчика VS2010 взаимодействовать с несколькими имитированными экземплярами встроенного устройства?Предположим, что производительность вряд ли будет проблемой, но количество экземпляров будет достаточно большим, так что создание отдельного проекта для каждого экземпляра, вероятно, будет раздражать в отсутствие какого-либо способа автоматизации процесса.Я могу думать о трех несколько подходящих подходах, но не знаю, как заставить любой из них работать действительно хорошо.Есть также подход, который был бы лучше, если это возможно, но я не знаю, как заставить его работать.
- Оберните весь код моделирования в один класс C ++, чтобы члены класса стали глобальными переменными в целевой системе.Я склоняюсь к этому подходу, но, по-видимому, для его компиляции необходимо, чтобы все было скомпилировано как единый модуль, что раздражающе сказалось бы на разработке кода целевой системы.Есть ли хороший способ иметь члены экземпляра класса доступа к коду, как если бы они были глобальными, не требуя, чтобы все функции, использующие такие экземпляры, были членами одного и того же модуля?
- Скомпилируйте отдельную DLL для каждого имитируемого экземпляра (так что, например, если я хочу запустить до 16 экземпляров, я включу в проект 16 DLL, все из которых используют одни и те же исходные файлы).Это может сработать, но каждое изменение конфигурации проекта должно быть повторено 16 раз.Действительно некрасиво.
- Скомпилируйте логику симуляции в EXE и запустите соответствующее количество экземпляров этого EXE.Это может сработать, но я не знаю ни одного удобного способа сделать такие вещи, как установить точку останова, общую для всех экземпляров.Возможно ли иметь несколько запущенных экземпляров EXE, прикрепленных к одному экземпляру отладчика?
- Загружать несколько экземпляров DLL таким образом, чтобы каждый экземпляр получал свои собственные глобальные переменные, оставаясь при этом доступным в отладчике.Это было бы лучше, если бы это было возможно, но я не знаю, как это сделать.Является ли это возможным?Как?Я никогда не использовал AppDomains, но моя интуиция подсказала бы, что это может быть полезно здесь.
- Если я использую один экземпляр VS2010 для внешнего интерфейса, а другой - для логики симуляции, есть ли способ упорядочить вещи так, чтобы запуск кода в одном автоматически запускал код в другом?
Я не особо привержен какому-либо подходу к симуляции;хотя было бы неплохо узнать, есть ли какой-то способ немного улучшить вышесказанное, я также хотел бы знать о любых других альтернативных подходах, которые могли бы работать еще лучше.