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

Himmler

Участник
  • Постов

    17
  • Зарегистрирован

  • Посещение

Репутация

0 Обычный

Информация о Himmler

  • Звание
    Участник
    Участник
  1. Здравствуйте, товарищи. Не уверен, что правильно выбрал ветку, если это так - перенаправьте, пожалуйста. Имеется крайне нетривиальная задача - использовать браузер в качестве GUI для железяки. Нетривиальность в том, что железяка видится на машине как флешка с файлами. Да, по-хорошему нужно дополнительно поднять на железяке rndis + tcp стек + http сервер. Но сейчас это mass storage. Соответственно, работать можно только через локальные файлы. Самое простое и очевидное - перезагрузка файла чем-нибудь вроде <meta http-equiv="refresh" content="1"> но это даёт возможность только вывода информации из железяки. Для ввода параметров есть пара идей: Работа с файлами через HTML5 files API. Один на ввод, другой на вывод. Безумная идея: размещение в файловой структуре дерева папок (глубиной, допустим, 30 каталогов), каждый уровень папок содержит 16 папок с именами от 0 до F. Если нужно сообщить что-то железке, переадресовываемся на файл вида d\e\a\d\b\e\e\f\index.html, тем самым передавая железяке значение 0xdeadbeef. Может есть ещё варианты ?
  2. Точно, неплохая идея. Даже один сэкономленный регистр будет уже в плюс.
  3. Ну про перенос команды загрузки я ранее уже писал, это маленько прибавило скорости. А вот про хранение одного адреса на 2 таблицы - не удалось, потому как размер таблиц - 0x2000, а такое значение не влезет в код команды. Изначально у меня была идея разместить таблицы так: 0x3F00 (маленькая таблица на 256 байт) 0x4000 0x6000 При этом хранить только 0x4000, а из него получать сдвигом 0x6000 и вычитанием 0x3F00. Вот только LDRH не позволяет сдвинуть, в отличие от LDR.
  4. Дело в том, что у меня и так линейный код, без ветвлений, циклов и прочего. Только арифметические операции и загрузка из памяти. Параллелить его не получится, поскольку он идеологически последовательный. Весь параллелизм - это сложить что-нибудь, пока что-то другое загружается из памяти. Просто судя по времени выполнения, в приведённом мной коде в среднем к каждой команде добавляется ещё и штрафной NOP. Откуда берутся такие задержки - пока не знаю.
  5. Сегодня начал мерить производительность кода и познакомился с кучей неприятных сюрпризов архитектуры ARM. Во-первых блокировка при загрузке байт/слов составляет не один такт, а два. Во-вторых все сдвиги, прилепленные к командам, совсем не бесплатные, и тоже добавляют блокировку на использование сдвигаемого регистра на один такт. Возможно, есть что-то ещё, и в результате приведённый мной выше код работает правильно, но в два раза дольше, чем я ожидал. Единственное, что сразу пришло на ум и чуть-чуть ускорило выполнение - перенос одной команды загрузки слова на пораньше. Но особой погоды это не сделало. Поэтому актуален следующий вопрос: Как можно изменить код (в том числе с добавлением команд и расходованием доп. регистров), чтобы уменьшить именно количество тактов при выполнении ?
  6. Извиняюсь за задержку, сегодня проверил код, погонял на разных входных данных - работает именно так, как нужно ;R0 - используется другим куском кода ;R1 - используется другим куском кода ;R2 - здесь храним кусок (12 бит) :R3 - здесь храним второй кусок (12 бит) ;R4 = in_data ;R5 = table_0_pointer = 0x4000 ;R6 = table_1_pointer = 0x6000 ;R7 = table_2_pointer = 0x3F00 ;R8 = mask (0x1FFE) ;R9-R14 - используется другим куском кода AND R2, R8, R4, LSL #1 AND R3, R8, R4, LSR #11 LDRH R2, [R5, R2] LDRH R3, [R6, R3] LDRB R4, [R7, R4, LSR #24] ADD R2, R2, R3, LSL #12 ADD R2, R2, R4, LSL #24 Поглядел на весь код в целом - было бы очень хорошо сэкономить два регистра. Ну или хотя бы один. Предположительно, это можно как-нибудь сделать, не храня все три адреса в R5, R6 и R7, а храня один их них, а два других -вычисляя на лету. Но тут я столкнулся с тем, что LDRH не хочет делать сдвиги и суммирования, как это делают LDR и LDRB. Можно ли тут как-нибудь извернуться ? Разумеется, не увеличивая число инструкций.
  7. К сожалению прямо сейчас у меня железяки и полноценного ide под рукой нету, смогу только завтра проверить. Но ARMSim#.191, onlinedisassembler.com и ARM instruction evaluator прекрасно переварили такой код, взаимно понимая друг друга и отлично ассемблируя/дизассемблируя результаты друг друга. В частности LDRB R3, [R6, R0, LSR #24] (машинный код E7D63C20) делает именно то, что задумывалось.
  8. Опять же согласен, вгружать 32-битные слова неправильно. То есть на данный момент 7 тактов. Больше нигде и ничего не срезать ?
  9. В моём случае не принципиально 10 килобайт или 16, а дискреты в 4 бита мне удобнее для пересчёта таблиц из их первоначального вида (где было 8 таблиц по 16 4-битных значений в каждой) Насчёт не байты, а слова - да, лопухнулся, написал как было раньше, когда было 4 однобайтовых таблицы. Сдвигать нужно на 1 бит индексы у двух таблиц, третья осталась однобайтовой. Только вот не понял, откуда ещё 1 команда, вроде же достаточно поменять на код вида ldr r1, [r4, r1, LSL#1]; загружаем младшие 12 бит (r4 был предварительно загружен и будет ещё многократно использоваться) ldr r2, [r5, r2, LSR #11]; загружаем средние 12 бит (r5 был предварительно загружен и будет ещё многократно использоваться) ldr r3, [r6, r0, LSR #24]; загружаем старшие 8 бит (r6 был предварительно загружен и будет ещё многократно использоваться)
  10. Дело в том, что такие операции, как загрузка адресов таблиц, сохранение регистров в стек, загрузка входного и выгрузка выходного слов выполняются по одному разу, а вот основная часть крутится многократно. Примерно получается (если считать, что входное слово, 12-битная маска, адреса таблиц уже загружены,регистры сохранены, и таблиц всего 3 по 12/12/8 бит): and r1, r0, r7; получаем указатель в первой таблице (r7 = 0x00000fff) and r2, r0, r7, LSL #12; получаем указатель во второй таблице ldr r1, [r4, r1]; загружаем младшие 12 бит (r4 был предварительно загружен и будет ещё многократно использоваться) ldr r2, [r5, r2, LSR #12]; загружаем средние 12 бит (r5 был предварительно загружен и будет ещё многократно использоваться) ldr r3, [r6, r0, LSR #24]; загружаем старшие 8 бит (r6 был предварительно загружен и будет ещё многократно использоваться) add r1, r1, r2, LSL #12; собираем 3 куска в одно 32-битное слово add r1, r3, LSL #24; собрали
  11. Это не 4 8-битных числа, разбиение условное, можно побить как 12/12/8. Входной вектор - 32-битный, выходной - тоже 32-битный. Идеальный вариант однотактового преобразователя - таблица на 4 миллиарда состояний, по 32 бита в каждом. Но ввиду очевидной невозможности такого безумия приходится разбивать преобразование на куски. Можно преобразовывать по 4 бита 8 раз, а можно по 8 бит 4 раза, а можно по 16 бит 2 раза (но на это памяти уже не хватит). По доступной памяти уложусь максимум в 12/12/8.
  12. Действительно, я наверное некорректно в постановке вопроса употребил слово "команда". В моём случае все инструкции, кроме загрузки из памяти выполняются за 1 такт, а латентность, вызываемая загрузкой из памяти маскируется во-первых конвейерной загрузкой, а во-вторых использованием загруженных данных через 2 инструкции после команды загрузки. А борьба идёт, естественно, за количество тактов. И предложенное выше укрупнение таблиц + экономия одной операции с маской позволяет выполнить алгоритм за 7 тактов. На мой взгляд, гипотетически сэкономить можно на сложении трёх значений и на операциях с маской. Но как именно - пока не знаю. А именно ?
  13. В принципе да, я могу уместиться в память, если переделаю 4 таблицы по 8 бит в 3 таблицы по 12/12/8 бит. Тогда алгоритм получится следующий: -Выковыриваем из входного слова отдельно 12 байт, потом ещё 12, и последние 8. -Из таблицы 1 дёргаем 12 бит, позиция которых определяется первым выдернутым значением из входного слова -Из таблицы 2 дёргаем 12 бит, позиция которых определяется вторым выдернутым значением из входного слова -Из таблицы 3 дёргаем 8 бит, позиция которого определяется третьим выдернутым значением из входного слова -Из трёх надёрганных кусков формируем выходное 32-битное слово Итого: 3 логических И с маской, 3 загрузки из памяти в регистры, 2 суммирования. Экономия, несомненно есть. Хотелось бы услышать ещё предложения, возможно есть инструкции, позволяющие сложить три значения за такт, или опять же какая-либо хитрость с масками. P.S. Вот я тут подумал, при разбиении входного слова на куски можно ещё одну инструкцию сэкономить - не брать маску для старших бит, а передать входное слово с нужным сдвигом, получив тем самым нужное количество старших бит в качестве индекса внутри массива в третьей таблице.
  14. Дело в том, что расширить таблицы мне уже не удастся, так как если сделать их не 1-байтовыми, а 2-байтовыми, то они будут занимать уже не 1 килобайт (4*16*16*1), а 256 килобайт (2*256*256*2). А быстрой однотактовой памяти у меня всего 32 килобайта. Есть огромная ддр-ка, но она дико медленная, обращение к ней съест весь выигрыш. И прекешировать нужное не получится, потому как индексы прыгают хаотически согласно входному слову. Насчёт GPIO идеи не понял - как можно соединить входы с выходами так, чтобы такое соединение охватывало 2^32 состояний ? Я пока копаю в сторону именно удачно подходящих инструкций, например чтобы не выделять отдельно 4 байта четыремя командами, или например избавиться от тройного сложения и как-то иначе собрать выходное 32-битное слово из однобайтовых кусков.
  15. Здравствуйте, товарищи. Имеется старенький arm926, на нём потребовалось запилить определённый алгоритм. Основная тяжеловесная часть данного алгоритма делают следующее: На входе - 32-битное слово (лежит в регистре R0), в памяти (время доступа - 1 такт) лежат 4 таблицы по 256 однобайтовых элементов каждая. -Выковыриваем из входного слова отдельно все 4 байта -Из таблицы 1 дёргаем байт, позиция которого определяется первым выдернутым байтом входного слова -Из таблицы 2 дёргаем байт, позиция которого определяется вторым выдернутым байтом входного слова -Из таблицы 3 дёргаем байт, позиция которого определяется третьим выдернутым байтом входного слова -Из таблицы 4 дёргаем байт, позиция которого определяется четвёртым выдернутым байтом входного слова -Из четырёх надёрганных байтов формируем выходное 32-битное слово Реализация в лоб занимает у меня 11 команд (4 логических И с маской, затем 4 загрузки из таблиц в регистры, затем 3 сложения, чтобы получить выходное слово. Сдвиги не учитываю, так как они прилеплены к другим командам и даются "бесплатно") Есть ли предложения по сокращению количества команд, если алгоритмическая оптимизация недоступна (то есть только грамотным подбором ассемблерных инструкций) ? Очень надеюсь, что есть опытные сограждане.
×
×
  • Создать...