Компиляция кода для запуска из внешнего ОЗУ


13

Я рассматриваю проекты для минималистской игровой системы на основе PIC18F85J5. Частью моего дизайна является то, что игры можно загружать с SD-карты без перепрограммирования чипа или перепрограммирования памяти программы. Я выбрал этот чип, потому что он имеет интерфейс внешней памяти, который позволит мне запускать код из внешней SRAM.

Основная идея заключается в том, что внутренняя память программы будет содержать интерфейс для просмотра SD-карты, и, как только пользователь выберет программу, он скопирует шестнадцатеричный файл с SD-карты на внешний ОЗУ, а затем выполнит переход во внешнее ОЗУ. ,

Внутренняя программная память также будет иметь различные библиотеки для графики, ввода контроллера и других различных утилит.

Я вполне уверен, что знаю, как сделать так, чтобы внутренние части прошивки работали нормально. Проблема заключается в создании программ для запуска из внешней оперативной памяти. Это не то же самое, что нацеливание на обычную картинку, и ему нужно знать о функциях библиотеки, которые доступны во внутренней памяти, но не перекомпилировать их, а только ссылаться на них. Также необходимо начать использовать адреса сразу после 32 Кб внутренней флешки, а не с нуля. Есть ли хороший способ для компиляции программы с использованием этих типов ограничений?

Я использую MPLab IDE, но я не очень знаком с ним или с тем, как выполнить такую ​​настройку.


Один из лучших вопросов, которые я видел здесь ... Я с нетерпением жду возможности услышать идеи и ответы.
Джон Л

Некоторые интересные альтернативные подходы обсуждаются в electronics.stackexchange.com/questions/5386/…
Тоби Джаффи

Я видел это, но они в основном рекомендуют писать на флэш, чего я бы хотел избежать. Мой аппаратный дизайн будет напоминать рисунок 6 в примечании к приложению в принятом ответе.
captncraig

Ответы:


8

У вас есть две отдельные проблемы:

  1. Построение кода для диапазона адресов внешней памяти.

    Это на самом деле очень просто. Все, что вам нужно сделать, это создать файл компоновщика, который содержит только диапазоны адресов, которые вы хотите, чтобы код занимал. Обратите внимание, что вам нужно не только зарезервировать определенный диапазон адресов памяти программ для этих внешних приложений, но также и некоторое пространство ОЗУ. Это пространство ОЗУ, как и адреса памяти программ, должно быть фиксированным и известным. Просто сделайте только те фиксированные и известные диапазоны адресов доступными для использования в файле компоновщика. Не забудьте сделать их НЕ доступными в файле компоновщика базового кода.

    После того, как базовый код загрузит новое приложение во внешнюю память, оно должно знать, как его выполнить. Самое простое, вероятно, - запустить выполнение с первого места во внешней памяти. Это означает, что вашему коду потребуется один раздел CODE по этому абсолютному начальному адресу. Это содержит GOTO к правой метке в остальной части кода, который будет перемещаться.

  2. Связывание приложений с библиотечными процедурами в базовом коде.

    Не существует простого способа сделать это с помощью существующих инструментов Microchip, но это не так уж и плохо.

    Гораздо большая проблема заключается в том, как вы хотите справляться с изменениями базового кода. Упрощенная стратегия состоит в том, чтобы создать базовый код, запустить программу над полученным файлом карты для сбора глобальных адресов, а затем написать файл импорта с инструкциями EQU для всех глобально определенных символов. Этот файл импорта будет включен во весь код приложения. Связывать здесь нечего, поскольку исходный код приложения по существу содержит фиксированные адресные ссылки на точки входа базового кода.

    Это легко сделать и будет работать, но подумайте, что произойдет, когда вы измените базовый код. Даже незначительное исправление может привести к перемещению всех адресов, и тогда весь существующий код приложения окажется бесполезным и его придется перестраивать. Если вы никогда не планируете предоставлять обновления базового кода без обновления всех приложений, то, возможно, вам это сойдет с рук, но я думаю, что это плохая идея.

    Лучший способ - иметь определенную область интерфейса по выбранному фиксированному известному адресу в базовом коде. Для каждой подпрограммы, которую может вызвать код приложения, будет один GOTO. Эти GOTO будут размещаться по фиксированным известным адресам, а внешние приложения будут вызывать только те местоположения, которые затем будут переходить туда, где подпрограмма фактически окажется в этой сборке базового кода. Это стоит 2 слова памяти программы на экспортируемую подпрограмму и два дополнительных цикла во время выполнения, но я думаю, что оно того стоит.

    Чтобы сделать это правильно, вам нужно автоматизировать процесс генерации GOTO и результирующего файла экспорта, который будут импортированы внешними приложениями для получения адресов подпрограммы (фактически перенаправителя GOTO). Возможно, вам удастся сделать что-то разумное при использовании макросов MPASM, но если бы я делал это, я бы определенно использовал свой препроцессор, поскольку он может записывать во внешний файл во время предварительной обработки. Вы можете написать макрос препроцессора, чтобы каждый редиректор мог быть определен одной строкой исходного кода. Макрос делает все неприятные вещи под капотом, который генерирует GOTO, внешнюю ссылку на фактическую целевую подпрограмму, и добавляет соответствующую строку в файл экспорта с известным постоянным адресом этой подпрограммы, и все с соответствующими именами. Возможно, макрос просто создает кучу переменных препроцессора с обычными именами (вроде расширяемого массива во время выполнения), а затем файл экспорта записывается один раз после всех вызовов макроса. Одна из многих вещей, которые мой препроцессор может сделать, чего не могут макросы MPASM, - это манипулирование строками для создания новых имен символов из других имен.

    Мой препроцессор и куча других связанных вещей доступны бесплатно по адресу www.embedinc.com/pic/dload.htm .


Мне очень нравится идея фиксированной таблицы прыжков. Я мог бы просто начать с конца флэш-памяти и иметь фиксированные места для каждого системного вызова. Я мог бы даже, вероятно, сойти с рук с поддерживаемым вручную заголовочным файлом с адресами всех подпрограмм, если бы я не смог выяснить все то вуду препроцессора, которое вы описываете.
captncraig

5

Вариант 1: устный перевод

Это не дает прямого ответа на вопрос (это отличный вопрос, кстати, и я надеюсь извлечь урок из ответа, который непосредственно к нему относится), но это очень часто встречается при выполнении проектов, которые могут загружать внешние программы для записи внешних программ в интерпретируемый язык. Если ресурсы ограничены (какими они будут на этом процессоре, вы думали об использовании PIC32 или небольшого процессора ARM для этого?), Обычно ограничивают язык подмножеством полной спецификации. Еще дальше в цепочку входят предметно-ориентированные языки, которые делают только несколько вещей.

Например, проект elua является примером интерпретируемого языка с низким ресурсом (64 КБ ОЗУ). Вы можете сжать это до 32 КБ ОЗУ, если удалите некоторые функции (Примечание: он не будет работать на вашем текущем процессоре, который является 8-битной архитектурой. Использование внешней ОЗУ, вероятно, будет слишком медленным для графики). Он обеспечивает быстрый и гибкий язык, на котором новые пользователи могут легко программировать игры, если вы предоставите минимальный API. Для этого языка доступно множество документов. Существуют и другие языки (например, Forth и Basic), которые вы можете использовать аналогичным образом, но я думаю, что Lua - лучший вариант на данный момент.

Аналогичным образом вы можете создать свой собственный предметно-ориентированный язык. Вам нужно будет предоставить более полнофункциональный API и внешнюю документацию, но если бы все игры были похожи, то это было бы не слишком сложно.

В любом случае, PIC18, вероятно, не тот процессор, который я бы использовал для чего-то, что включает в себя пользовательское программирование / скриптинг и графику. Возможно, вы знакомы с этим классом процессоров, но я бы предположил, что сейчас самое время использовать что-нибудь с драйвером дисплея и большим объемом памяти.

Вариант 2: просто перепрограммируйте все

Однако, если вы уже планируете программировать все игры самостоятельно на C, не стоит загружать только игровую логику с SD-карты. Для перепрограммирования у вас есть всего 32 КБ флэш-памяти, и вы можете легко получить карту памяти microSD емкостью 4 ГБ. (Примечание: карты большего размера часто являются SDHC, с которыми сложнее взаимодействовать). Предполагая, что вы используете каждый последний байт из 32 КБ, это оставляет место на SD-карте для 131 072 копий вашей прошивки с любой игровой логикой, которая вам нужна.

Существует множество приложений для написания загрузчиков для PIC, таких как AN851 . Вам необходимо спроектировать загрузчик так, чтобы он занимал определенную область памяти (вероятно, верхнюю часть области памяти, вы должны указать это в компоновщике), и указать, что полные проекты встроенного ПО не достигают этой области. Приложение разъясняет это более подробно. Просто замените «Загрузочный раздел PIC18F452» на «Загрузочный раздел, который я указываю в компоновщике», и все это будет иметь смысл.

Затем ваш загрузчик просто должен позволить пользователю выбрать программу для запуска с SD-карты и полностью скопировать ее. Пользовательский интерфейс может состоять в том, что пользователь должен удерживать нажатой кнопку, чтобы войти в режим выбора. Обычно загрузчик просто проверяет состояние этой кнопки при перезагрузке и, если она не удерживается, загружается в игру. Если он удерживается, ему нужно будет разрешить пользователю выбрать файл на SD-карте, скопировать программу и продолжить загрузку [новой] игры.

Это моя текущая рекомендация.

Вариант 3: Глубокая магия, включающая хранение только части шестнадцатеричного файла

Проблема с вашим предполагаемым механизмом состоит в том, что процессор не имеет дело с API-интерфейсами и вызовами функций, он имеет дело с числами - адресами, на которые может перейти указатель инструкции, и ожидать наличия кода, который выполняет вызов функции в соответствии со спецификацией API. Если вы попытаетесь скомпилировать только часть программы, компоновщик не будет знать, что делать, когда вы звоните check_button_status()или toggle_led(). Возможно, вы знаете, что эти функции существуют в шестнадцатеричном файле на процессоре, но ему нужно точно знать, по какому адресу они находятся.

Компоновщик уже разбивает ваш код на несколько разделов; Вы можете теоретически разбить это на дополнительные разделы с некоторыми -sectionи #pragmaзаклинаниями. Я никогда не делал этого и не знаю как. До тех пор, пока вышеупомянутые два метода не подведут меня (или кто-то не отправит здесь удивительный ответ), я, вероятно, не изучу этот механизм, и поэтому я не могу научить его вам.


Мое возражение против числа 2 состоит в том, что у флэш-памяти есть ограниченное число циклов стирания в течение срока службы чипа. Я не хочу использовать более мощную MCU, потому что я иду на 8-битный минимализм.
captncraig

@CMP - имеет не менее 10 000 циклов стирания. Если кто-то играет в разные игры каждый день, это продлится до 2039 года. Flash почти наверняка переживет весь остальной круг. Я не думаю, что вам нужно беспокоиться об этом, если только это не происходит в аркаде, в которую можно играть десятки раз каждый день.
Кевин Вермеер

1
Во-вторых, 8-битный минимализм может выглядеть круто, но это плохо для программирования. Гораздо проще получить надежный микроконтроллер и заставить его выглядеть ретро, ​​чем заставлять его выглядеть ретро, ​​потому что вы раздвигаете границы своего процессора.
Кевин Вермеер

1
Оба очень справедливые моменты. Даже при низком количестве деталей pic32 не так уж отличается по стоимости или внешним компонентам, как это, и если он имеет 512 КБ внутренней вспышки, он даже выигрывает.
captncraig

Похоже, что практическим решением было бы использовать pic32 и написать загрузчик для перепрошивки с SD-карты. Мне было бы трудно повторно использовать функции, которые понадобятся как загрузчику, так и пользовательскому коду, но, пока я держу его в загрузочной флеш-памяти 12 КБ, он должен давать пользователю весь код, и они могут включать в себя любые библиотеки, которые им нужны в исходном коде. уровень.
captncraig
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.