Перейти к содержанию
    

JUMP and RETURN на загружаемое приложение NIOS II

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

Описание существующей системы: Есть модуль с ПЛИС в которой реализован процессор 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 в ПО? Что в этом мне может помочь? Можно это сделать линковщиком?

Спасибо за уделённое внимание.

 

image.jpg

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вы напишите более глобальную задачу который вы стараетесь решить таким "изысканным" способом...

 

Строго говоря всегда можно вызывать функцию по указателю, например. Или переписать загрузчик и не инициализировать "стек" чтобы это не значило...

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Есть задача, подскажите инструмент и технологию с помощью которой её можно решить.

В ПЛИС можно сделать страничную память. Для каждой загружаемой задачи - свою страницу. Тогда у них у всех будет один и тот же адрес. Ну а переключение страниц - это уже отдельный вопрос...

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вы напишите более глобальную задачу который вы стараетесь решить таким "изысканным" способом...

 

Строго говоря всегда можно вызывать функцию по указателю, например. Или переписать загрузчик и не инициализировать "стек" чтобы это не значило...

Технология описанная мной это лишь реализация устоявшейся на фирме технологии проверки и тестирования аппаратуры. Тоесть программа 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).

Изменено пользователем RLC

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

вроде бы вот здесь то что вам нужно...

http://www.alteraforum.com/forum/archive/i...hp/t-15278.html

Вроде бы тепло. Читаю, разбираюсь. Понятно что нужно копать линковщик. Спасибо за ссылку. Если появятся вопросы - задам. Всего доброго.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Доброго всем дня. В процессе реализации данной задачи возник важный вопрос о передаче параметров (адреса возврата) в загружаемое приложение для возврата из него по окончании работы(по аналогии с возвратом из функции, но с использованием разного stack, heap, .rwdata, .rodata, .bss и тд). Пока что только одна идея-выделить в области памяти отдельную область для передачи параметров. Идея выглядит костыльной, хочется сделать через регистры процессора НО при загрузке нового загружаемого приложения вызывается код из файла crt0.s, который как раз устанавливает новую вершину стека. Вопрос: как можно самому поменять crt0.s, так что бы при перегенерации bsp он не возвращался к исходному,а всегда брался мною написанный?

Есть конечно идея написать скрипт который будет генерировать bsp стандартным путём и потом подменять crt0.s, Но это опять же костыль. Кто может подсказать решение данной задачки? :1111493779:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Доброго всем дня. В процессе реализации данной задачи возник важный вопрос о передаче параметров (адреса возврата) в загружаемое приложение для возврата из него по окончании работы(по аналогии с возвратом из функции, но с использованием разного 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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А почему с самого начала загружаемые программки/тесты/etc не рассматриваются как программы-приложения, рассчитанные на выполнение в среде, создаваемой HOST_PROGRAMM? Зачем вы LOAD_PROGRAMM компилируете со всеми ненужными им стартапными секциями и т.п. ?

 

Т.е., в идеале в составе HOST_PROGRAMM должен быть ELF-Loader, которому из UART подается ELF-файл конкретного теста/программки, он его размещает по памяти согласно его же содержимому, а потом передает управление в указанную точку. По завершении - получает управление обратно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А почему с самого начала загружаемые программки/тесты/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.

Вот такой путь. почти всё работает, еще не отладил до конца =)

Изменено пользователем RLC

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...