Мне нужно оптимизировать код, чтобы освободить место для нового кода. У меня нет места для всех изменений. Я не могу использовать переключение банка кодов (80c31 с 64k).
Какие методы доступны для оптимизации памяти на языке ассемблера 8051?
Ответы (7)
Вы действительно не дали здесь многого, но есть два основных уровня оптимизации, которые вы можете рассмотреть:
Микрооптимизация: например. XOR A вместо MOV A,0 Адам хорошо рассмотрел некоторые из них ранее.
Макрооптимизация. Посмотрите на структуру вашей программы, используемые структуры данных и алгоритмы, выполняемые задачи и ОЧЕНЬ хорошенько подумайте, как их можно изменить или даже удалить. Есть ли целые куски кода, которые на самом деле не используются? Ваш код полон операторов вывода отладки, которые пользователь никогда не увидит? Есть ли функции, специфичные для одного клиента, которые вы могли бы исключить из общей версии?
Чтобы получить хорошее представление об этом, вам нужно выяснить, ГДЕ используется ваша память. Карта Linker — хорошее место для начала. Макрооптимизация — это то, где можно добиться БОЛЬШИХ побед.
Кроме того, вы можете серьезно попробовать переписать части своего кода с помощью хорошего оптимизирующего компилятора C. Вы можете быть поражены тем, насколько жестким может быть код. Настоящий ассемблер может улучшить его, но он легко может быть лучше, чем большинство программистов. Я использовал IAR около 20 лет назад, и это сдуло мои носки.
С языком ассемблера вам придется оптимизировать вручную. Вот несколько техник:
Примечание: IANA8051P (я не программист 8501, но я много занимался сборкой других 8-битных микросхем).
Просмотрите код в поисках любых дублирующихся битов, независимо от того, насколько они малы, и заставьте их работать.
Изучите некоторые из наиболее необычных инструкций и посмотрите, сможете ли вы использовать их для оптимизации, например. Хорошим трюком является использование XOR A для очистки аккумулятора вместо MOV A,0 - это сохраняет байт.
Еще один изящный трюк: если вы вызываете функцию перед возвратом, просто переходите к ней, например, вместо:
CALL otherfunc
RET
Просто сделать:
JMP otherfunc
Всегда убедитесь, что вы делаете относительные переходы и переходы везде, где это возможно, они используют меньше памяти, чем абсолютные переходы.
Это все, о чем я могу думать на данный момент.
PrImm: POP DPH / POP DPL / CALL PrintMsg / INC DPTR / PUSH DPL / PUSH DPH / RET
. Каждый вызов Primm будет занимать только 3 байта плюс фактические символы для вывода.
- person supercat; 24.02.2015
Извините, что я пришел к этому поздно, но у меня когда-то была точно такая же проблема, и она стала повторяющейся проблемой, которая продолжала возвращаться ко мне. В моем случае проектом был телефон на процессоре семейства 8051, и я полностью исчерпал ПЗУ (кодовую) память. Это постоянно возвращалось ко мне, потому что руководство продолжало запрашивать новые функции, поэтому каждая новая функция становилась двухэтапным процессом. 1) Оптимизировать старые вещи, чтобы освободить место. 2) Реализовать новую функцию, используя только что созданную комнату.
Существует два подхода к оптимизации. Тактические и стратегические. Тактическая оптимизация экономит несколько байтов за раз благодаря идее микрооптимизации. Я думаю, вам нужна стратегическая оптимизация, которая предполагает более радикальное переосмысление того, как вы делаете вещи.
Что-то, что я помню, сработало у меня и может сработать у вас;
Посмотрите на суть того, что должен делать ваш код, и попытайтесь выделить несколько действительно сильных гибких примитивных операций. Затем перестройте свой код верхнего уровня так, чтобы он вообще ничего не делал на низком уровне, кроме вызова примитивов. В идеале используйте подход, основанный на таблицах, ваша таблица содержит такие вещи, как; Состояние ввода, событие, состояние вывода, примитивы... Другими словами, когда происходит событие, найдите ячейку в таблице для этого события в текущем состоянии. Эта ячейка сообщает вам, в какое новое состояние перейти (необязательно) и какие примитивы (если есть) выполнить. Вам может понадобиться несколько наборов состояний/событий/таблиц/примитивов для разных слоев/подсистем.
Одним из многих преимуществ этого подхода является то, что вы можете думать о нем как о создании пользовательского языка для вашей конкретной задачи, в котором вы можете очень эффективно (т. е. с минимальным дополнительным кодом) создавать новые функции, просто изменяя таблицу.
Извините, я опоздал на несколько месяцев, и у вас, вероятно, все равно не было времени сделать что-то настолько радикальное. Насколько я знаю, вы уже использовали подобный подход! Но мой ответ может помочь кому-то еще, кто знает.
В отделе взломанных файлов вы также можете подумать о сжатии части вашего кода и сохранении распакованной только той части, которая активно используется в любой конкретный момент времени. Мне трудно поверить, что код, необходимый для системы сжатия/распаковки, будет достаточно небольшой частью крошечной памяти 8051, чтобы сделать это стоящим, но он творил чудеса на немного больших системах.
Еще один подход состоит в том, чтобы обратиться к формату байт-кода или коду, управляемому таблицами, который выводят некоторые инструменты конечного автомата. Когда машина понимает, что делает ваше приложение, и генерирует совершенно непонятную реализацию, это может стать отличным способом сэкономить. номер :)
Наконец, если код действительно скомпилирован на C, я бы предложил скомпилировать с рядом различных параметров, чтобы посмотреть, что произойдет. Кроме того, в 2001 году я написал статью о компактном программировании на C для ESC. это все еще довольно актуально. См. этот текст для других трюков для небольших машин.
1) По возможности сохраняйте свои переменные в Idata, а не в xdata
2) Посмотрите на свои операторы Jmp — используйте SJmp и AJmp
Я предполагаю, что вы знаете, что это не подходит, потому что вы написали / выполнили и получили ошибку «недостаточно памяти». :) Похоже, ответы довольно точно отвечают на ваш вопрос; если не считать примеров кода.
Я бы, однако, порекомендовал несколько дополнительных соображений;
- Убедитесь, что весь код действительно используется — проверка покрытия кода? Неиспользованный саб — это большая победа — это трудный шаг — если вы оригинальный автор, это может быть проще — (ну, может быть) :)
- Ensure the level of "verification"
and initialization -- sometimes we
have a tendency to be over zealous
in insuring we have initialized
variables/memory and sure enough
rightly so, how many times have we
been bitten by it. Not saying don't
initialize (duh), but if we're doing
a memory move, the destination
doesn't need to be zero'd first --
this dovetails with
1 --
- Оцените новые функции — можно ли улучшить существующую подсистему, чтобы она охватывала обе функции, или, возможно, заменить существующую функцию?
- Разбивайте большой код, если часть большого кода может сэкономить создание нового небольшого кода.
или, возможно, сейчас есть аргумент в пользу аппаратной версии 2.0 ... :)
С уважением
Помимо уже упомянутых (более или менее) очевидных оптимизаций, есть еще одна очень странная (и почти недостижимая) оптимизация: повторное использование кода. И под повторным использованием кода я имею в виду не обычное повторное использование, а а) повторное использование вашего кода в качестве данных или б) повторное использование вашего кода в качестве другого кода. Может быть, вы можете создать lut (или любые другие статические данные), которые могут быть представлены шестнадцатеричными кодами операций asm (здесь вам нужно посмотреть на архитектуру Гарварда и фон Неймана).
Другой будет повторно использовать код, придавая коду другое значение, когда вы обращаетесь к нему по-другому. Вот пример, чтобы было понятно, что я имею в виду. Если байты вашего кода выглядят так: AABCCCDDEEFFGGHH по адресу X, где каждая буква соответствует одному коду операции, представьте, что теперь вы перейдете к X+1. Возможно, вы получите совершенно другую функциональность, в которой байты, разделенные пробелом, образуют новые коды операций: ABC CCD DE EF GH.
Но будьте осторожны: этого не только сложно достичь (возможно, невозможно), но и ужасно поддерживать. Так что если вы не демо-код (или подобная экзотика), то я бы рекомендовал использовать уже другие упомянутые способы сохранения памяти.