RLC 0 16 октября, 2017 Опубликовано 16 октября, 2017 · Жалоба Добрый день. Есть задача, подскажите инструмент и технологию с помощью которой её можно решить. Описание существующей системы: Есть модуль с ПЛИС в которой реализован процессор NIOS II. К NIOS II подключена ОЗУ, контроллер UART, реализованный в ПЛИС и другая переферия, которая не относится к сути вопроса. UART через приёмопередатчик подключен к порту COM ПК. Через RS-232 и соответствующее ПО на ПК осуществляется чтение и запись данных в регистры адресного пространства модуля, получение текстовой информации в консоль, запись программ в ОЗУ и их запуск на выполнение. ОЗУ разделена в BSP на две части: HOST_PROGRAMM и LOAD_PROGRAMM. HOST_PROGRAMM - это часть ОЗУ в которой хранится и выполняется программа запускаемая при подаче питания на модуль и осуществляет связь с ПК по RS-232. LOAD_PROGRAMM - это часть ОЗУ в которой хранится и выполняется программа записываемая по интерфейсу RS-232. на данный момент программа загружаемая через RS-232 вызывается по адресу функции main(которая берётся из map-файла). Это сделано для того что бы пропустить автоматическую инициализацию стека и после выполнения функции main вернуться без перезагрузки модуля в HOST_PROGRAMM. Со стороны ПК, для пользователя, это выглядит как загрузка файла по определённому адресу в ОЗУ и ввода адреса jump на загруженную программу, по которому осуществляется вызов лежащей там функции. В связи с тем что таких загружаемых программ может быть несколько десятков и у каждой, естественно, свой адрес расположения функции main необходимо унифицировать адрес расположения этой функции, т.е. привести к одному для любой загружаесмой программы LOAD_PROGRAMM, хотя бы с точки зрения пользователя на ПК. Вопрос: как унифицировать адрес расположения функции main в ПО? Что в этом мне может помочь? Можно это сделать линковщиком? Спасибо за уделённое внимание. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Golikov 0 16 октября, 2017 Опубликовано 16 октября, 2017 · Жалоба Вы напишите более глобальную задачу который вы стараетесь решить таким "изысканным" способом... Строго говоря всегда можно вызывать функцию по указателю, например. Или переписать загрузчик и не инициализировать "стек" чтобы это не значило... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
iosifk 3 16 октября, 2017 Опубликовано 16 октября, 2017 · Жалоба Есть задача, подскажите инструмент и технологию с помощью которой её можно решить. В ПЛИС можно сделать страничную память. Для каждой загружаемой задачи - свою страницу. Тогда у них у всех будет один и тот же адрес. Ну а переключение страниц - это уже отдельный вопрос... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
RLC 0 16 октября, 2017 Опубликовано 16 октября, 2017 (изменено) · Жалоба Вы напишите более глобальную задачу который вы стараетесь решить таким "изысканным" способом... Строго говоря всегда можно вызывать функцию по указателю, например. Или переписать загрузчик и не инициализировать "стек" чтобы это не значило... Технология описанная мной это лишь реализация устоявшейся на фирме технологии проверки и тестирования аппаратуры. Тоесть программа HOST_PROGRAMM необходима для загрузки тестов для отладки и проверки работоспособности аппаратуры по ТУ. Соответственно LOAD_PROGRAMM это тесты различных аппаратно-программных контроллеров и программки для настройки и отладки при разработке. Соответственно с стеком ситуация следующая: HOST_PROGRAMM работает и при выполнении своих функций записывает адрес возврата из вызываемой функции. (pop, push). В какой то момент ей приходит команда о вызове функции по адресу(который приходит по RS-232 от пользователя) программы LOAD_PROGRAMM. Если это адрес main() LOAD_PROGRAMM то проблем нет и стек с адресом возврата сохраняется. После завершения main() происходит возврат в HOST_PROGRAMM. А если мы передаем адрес jump указывающий на crt0 LOAD_PROGRAMM то перед вызовом main() произойдёт запись другого адреса вершины стека и адрес возврата потеряется. Извините за описания возможно очевидных для вас вещей, просто хотел объяснить что я имею ввиду. Мне требуется для вызова main() всегда использовать один и тот же адрес и через стек возвращаться из LOAD_PROGRAMM в HOST_PROGRAMM. Последнее реализовано а вот как main() для любой программы-теста привязать к определённому адресу не знаю и поэтому спрашиваю у вас. В ПЛИС можно сделать страничную память. Для каждой загружаемой задачи - свою страницу. Тогда у них у всех будет один и тот же адрес. Ну а переключение страниц - это уже отдельный вопрос... Дело в том что необходимо что бы технология работала и на NIOS II эконом без всяких дополнительных аппаратных блоков в ПЛИС. А память зачастую будет использоваться SRAM (ONCHIP). Изменено 16 октября, 2017 пользователем RLC Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Golikov 0 16 октября, 2017 Опубликовано 16 октября, 2017 · Жалоба вроде бы вот здесь то что вам нужно... http://www.alteraforum.com/forum/archive/i...hp/t-15278.html Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
RLC 0 16 октября, 2017 Опубликовано 16 октября, 2017 · Жалоба вроде бы вот здесь то что вам нужно... http://www.alteraforum.com/forum/archive/i...hp/t-15278.html Вроде бы тепло. Читаю, разбираюсь. Понятно что нужно копать линковщик. Спасибо за ссылку. Если появятся вопросы - задам. Всего доброго. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
RLC 0 4 декабря, 2017 Опубликовано 4 декабря, 2017 · Жалоба Доброго всем дня. В процессе реализации данной задачи возник важный вопрос о передаче параметров (адреса возврата) в загружаемое приложение для возврата из него по окончании работы(по аналогии с возвратом из функции, но с использованием разного stack, heap, .rwdata, .rodata, .bss и тд). Пока что только одна идея-выделить в области памяти отдельную область для передачи параметров. Идея выглядит костыльной, хочется сделать через регистры процессора НО при загрузке нового загружаемого приложения вызывается код из файла crt0.s, который как раз устанавливает новую вершину стека. Вопрос: как можно самому поменять crt0.s, так что бы при перегенерации bsp он не возвращался к исходному,а всегда брался мною написанный? Есть конечно идея написать скрипт который будет генерировать bsp стандартным путём и потом подменять crt0.s, Но это опять же костыль. Кто может подсказать решение данной задачки? :1111493779: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
RLC 0 7 декабря, 2017 Опубликовано 7 декабря, 2017 · Жалоба Доброго всем дня. В процессе реализации данной задачи возник важный вопрос о передаче параметров (адреса возврата) в загружаемое приложение для возврата из него по окончании работы(по аналогии с возвратом из функции, но с использованием разного stack, heap, .rwdata, .rodata, .bss и тд). Пока что только одна идея-выделить в области памяти отдельную область для передачи параметров. Идея выглядит костыльной, хочется сделать через регистры процессора НО при загрузке нового загружаемого приложения вызывается код из файла crt0.s, который как раз устанавливает новую вершину стека. Вопрос: как можно самому поменять crt0.s, так что бы при перегенерации bsp он не возвращался к исходному,а всегда брался мною написанный? Есть конечно идея написать скрипт который будет генерировать bsp стандартным путём и потом подменять crt0.s, Но это опять же костыль. Кто может подсказать решение данной задачки? :1111493779: Путем чтения документации по процессу разработки, сборки, линковки ПО выяснил как можно создать и установить свой файл crt0.S. После прыжка на адрес загрузки, обозначенный как "_start" в map файле из регистров процессора можно взять необходимые адреса возврата и вершины стека. Делюсь с сообществом как это можно сделать. Самое главное это то что всё делается через makefile приложения(не bsp) и его можно менять, правда в ручную не рекомендует альтера. Для этого она создала свои утилиты настройки этого файла. В makefile определена переменная CRT0-путь к файлу crt0.S в которой по умолчанию не присваивается значение. После ее объявления проверяется значение этой переменной и если значение не определено(а по умолчанию так и есть) то устанавливается путь на файл в bsp. Значение можно ручками поменять и оно не меняется если не запускается утилита nios2-app-generate-makefile.exe. Собственно это всё что нужно знать. Если подробнее по шагам: -------------------------------------- Порядок действия для добавления своего файла crt0.S: 1) Скопировать файл в рабочую директорию 2) С помощью команды nios2-app-update-makefile.exe --app-dir . --add-src-files crt0.S добавить файл в makefile 3) С помощью команды nios2-app-update-makefile.exe –app-dir . - -list-src-files проверить что добавление файла произошло 4) Добавить скомпилированный файл crt0.o из директории "obj/default/" в переменную CRT0 Makefile с использованием команды "nios2-app-update-makefile.exe –app-dir . --set CRT0 crt0.o" 5) Выполнить clean 6) Выполнить make build Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Raven 8 7 декабря, 2017 Опубликовано 7 декабря, 2017 · Жалоба А почему с самого начала загружаемые программки/тесты/etc не рассматриваются как программы-приложения, рассчитанные на выполнение в среде, создаваемой HOST_PROGRAMM? Зачем вы LOAD_PROGRAMM компилируете со всеми ненужными им стартапными секциями и т.п. ? Т.е., в идеале в составе HOST_PROGRAMM должен быть ELF-Loader, которому из UART подается ELF-файл конкретного теста/программки, он его размещает по памяти согласно его же содержимому, а потом передает управление в указанную точку. По завершении - получает управление обратно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
RLC 0 12 декабря, 2017 Опубликовано 12 декабря, 2017 (изменено) · Жалоба А почему с самого начала загружаемые программки/тесты/etc не рассматриваются как программы-приложения, рассчитанные на выполнение в среде, создаваемой HOST_PROGRAMM? Зачем вы LOAD_PROGRAMM компилируете со всеми ненужными им стартапными секциями и т.п. ? Я так понимаю что в среде это с использованием stack и heap HOST_PROGRAMM? Если я вас правильно понял, то отвечаю: у меня идея с самого начала была такая что бы выполнять из LOAD_PROGRAMM только функцию main. Для унификации её прилинковывать к какому-нибудь красивому адресу(0x10000, 0x 20000 и т.п.).Но в случае если NIOS будет использоваться в модуле где будет отдельный DDRx SDRAM на выделенной микросхеме, а раскручиваться HOST_PROGRAMM будет из ONCHIP RAM и LOAD_PROGRAMM будет работать с большим массивом данных, имеет смысл иметь независимое адресное пространство и отработанную технологию. Дело в том что я работаю не под конкретный заказ, а прорабатываю технологию для использования в будущем, поэтому принимаются во внимание самые изощрённые варианты возможных событий. В таком случае логика есть. А сам алгоритм загрузки используется в конторе на разных процессорах. В связи с этим все стартапные секции нужны, тк необходимо обеспечить ПОЛНУЮ независимость LOAD_PROGRAMM. Надеюсь я ответил на ваш вопрос =) Т.е., в идеале в составе HOST_PROGRAMM должен быть ELF-Loader, которому из UART подается ELF-файл конкретного теста/программки, он его размещает по памяти согласно его же содержимому, а потом передает управление в указанную точку. По завершении - получает управление обратно. Да, именно так. Маленькая поправка: у нас используется файл в формате *.bin. поэтому до загрузки скомпилированной программы в виде elf-файла превращаю этот файл в bin и потом его загружаю через нашу прогу загрузки файлов по uart. В bin файле находятся данные такие же как и в jic-файле образа epcs(при размещении ПО в epcs. Длинна секции данных , адресс копирования данных, двоичные данные, длинна данных, адресс копирования данных, двоичные данные и т.д. для каждой секции + заголовок отличающий этот bin-файл от просто двоичных данных которые тоже могут грузится по UART(и грузятся в наших изделиях)Подробнее в an458 о структуре epcs файла ПО) Путь преобразования такой: elf->flash->hex->pof->rpd->(через собственную программку обрезая лишнее и добавляя заголовок) bin файл. С возвратом из этой LOAD_PROGRAMM дело обстоит сложнее тк у нас разный стек и полная инициализация процессора. Я сейчас доделываю такой вариант: После выдачи команды по UART совершаю из HOST_PROGRAMM программы на Си вызов функции по адресу старта LOAD_PROGRAMM, полученный при получении bin файла. В файле crt0.S LOAD_PROGRAMM перед инициализацией регистров, в самом начале, я в стек HOST_PROGRAMM(значение его вершины еще находится в регистре sp проца ) сохраняю все необходимые регистры(регистры общего назначения и служебные), в отдельный регистр сохраняю вершину стека HOST_PROGRAMM. После этого оставляю стандартный алгоритм инициализации процессора предложенный altera. После сохраняю в стек LOAD_PROGRAMM вершину стека HOST_PROGRAMM, вызываю alt_main, main. По завершению их работы восстанавливаю значение вершины стека HOST_PROGRAMM и возвращаю на место значение регистров процессора при HOST_PROGRAMM и выполняю ассемблерную команду ret. Вот такой путь. почти всё работает, еще не отладил до конца =) Изменено 12 декабря, 2017 пользователем RLC Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться