adnega 11 29 июня, 2018 Опубликовано 29 июня, 2018 · Жалоба Как заработает - напишу. Проверил в железе - работает (Cortex-M0). #include "stdafx.h" #include "conio.h" #include "windows.h" #define IS_ALIGN (1) #define VAR_NUM (32) //----------------------------------------------------------------------------- // enum eVAR_TYPE //----------------------------------------------------------------------------- enum eVAR_TYPE { VAR_NONE = 0, VAR_DWORD, VAR_WORD, VAR_BYTE, }; //----------------------------------------------------------------------------- // typedef struct sVAR //----------------------------------------------------------------------------- typedef struct sVAR { union { DWORD data_dw; WORD data_w; BYTE data_b; }; enum eVAR_TYPE type; } sVAR; volatile sVAR var[VAR_NUM] = { {0x12345678, VAR_DWORD}, {0xABCD, VAR_WORD}, {0x11223344, VAR_DWORD}, {0x55, VAR_BYTE}, {0x00, VAR_BYTE}, {0x66, VAR_BYTE}, {0x77, VAR_BYTE}, {0x88, VAR_BYTE}, {0x99, VAR_BYTE}, {0xAA, VAR_BYTE}, {0xBB, VAR_BYTE}, {0xCC, VAR_BYTE}, {0xDD, VAR_BYTE}, {0xEE, VAR_BYTE}, {0xFF, VAR_BYTE}, {0x98765432, VAR_DWORD}, }; BYTE exec_ram[1024]; //----------------------------------------------------------------------------- // void set_new_mask(const DWORD mask) //----------------------------------------------------------------------------- void set_new_mask(const DWORD mask) { int offset; int last_var = 0; int s_pos = 0; int exec_ram_pos = 0; printf("// r0 = *s, r1 = var\n"); // PUSH {r2, lr} exec_ram[exec_ram_pos++] = 0x04; exec_ram[exec_ram_pos++] = 0xB5; printf("B5 04 - push {r2, pc}\n"); for(int i = 0; i < VAR_NUM; i++) { if(mask & (1 << i)) { switch(var[i].type) { case VAR_DWORD: printf("// DWORD[%d]\n", i); offset = (i - last_var) * 8; last_var = i; while(offset > 128) { offset -= 128; // ADD r1, #128 exec_ram[exec_ram_pos++] = 128; exec_ram[exec_ram_pos++] = 0x31; printf("31 80 - add r1, #128\n"); } if(offset) { // ADD r1, #offset exec_ram[exec_ram_pos++] = offset; exec_ram[exec_ram_pos++] = 0x31; printf("31 %02X - add r1, #%d\n", offset, offset); } if(IS_ALIGN && (s_pos & 1)) { // byte align // LDRB r2, [r1, #0] exec_ram[exec_ram_pos++] = 0x0A; exec_ram[exec_ram_pos++] = 0x78; printf("78 0A - ldrb r2, [r1, #0]\n"); // STRB r2, [r0, #0] exec_ram[exec_ram_pos++] = 0x02; exec_ram[exec_ram_pos++] = 0x70; printf("70 02 - strb r2, [r0, #0]\n"); // LDRB r2, [r1, #1] exec_ram[exec_ram_pos++] = 0x4A; exec_ram[exec_ram_pos++] = 0x78; printf("78 4A - ldrb r2, [r1, #1]\n"); // STRB r2, [r0, #1] exec_ram[exec_ram_pos++] = 0x42; exec_ram[exec_ram_pos++] = 0x70; printf("70 42 - strb r2, [r0, #1]\n"); // LDRB r2, [r1, #2] exec_ram[exec_ram_pos++] = 0x8A; exec_ram[exec_ram_pos++] = 0x78; printf("78 8A - ldrb r2, [r1, #2]\n"); // STRB r2, [r0, #2] exec_ram[exec_ram_pos++] = 0x82; exec_ram[exec_ram_pos++] = 0x70; printf("70 82 - strb r2, [r0, #2]\n"); // LDRB r2, [r1, #3] exec_ram[exec_ram_pos++] = 0xCA; exec_ram[exec_ram_pos++] = 0x78; printf("78 CA - ldrb r2, [r1, #3]\n"); // STRB r2, [r0, #3] exec_ram[exec_ram_pos++] = 0xC2; exec_ram[exec_ram_pos++] = 0x70; printf("70 C2 - strb r2, [r0, #3]\n"); } else if(IS_ALIGN && (s_pos & 2)) { // word align // LDRH r2, [r1, #0] exec_ram[exec_ram_pos++] = 0x0A; exec_ram[exec_ram_pos++] = 0x88; printf("88 0A - ldrh r2, [r1, #0]\n"); // STRH r2, [r0, #0] exec_ram[exec_ram_pos++] = 0x02; exec_ram[exec_ram_pos++] = 0x80; printf("80 02 - strh r2, [r0, #0]\n"); // LDRH r2, [r1, #2] exec_ram[exec_ram_pos++] = 0x4A; exec_ram[exec_ram_pos++] = 0x88; printf("88 4A - ldrh r2, [r1, #2]\n"); // STRH r2, [r0, #2] exec_ram[exec_ram_pos++] = 0x42; exec_ram[exec_ram_pos++] = 0x80; printf("80 42 - strh r2, [r0, #2]\n"); } else { // dword align // LDR r2, [r1, #0] exec_ram[exec_ram_pos++] = 0x0A; exec_ram[exec_ram_pos++] = 0x68; printf("68 0A - ldr r2, [r1, #0]\n"); // STR r2, [r0, #0] exec_ram[exec_ram_pos++] = 0x02; exec_ram[exec_ram_pos++] = 0x60; printf("60 02 - str r2, [r0, #0]\n"); } // ADDS r0, #4 exec_ram[exec_ram_pos++] = 0x04; exec_ram[exec_ram_pos++] = 0x30; printf("30 04 - adds r0, #4\n"); s_pos += 4; break; case VAR_WORD: printf("// WORD[%d]\n", i); offset = (i - last_var) * 8; last_var = i; while(offset > 128) { offset -= 128; // ADD r1, #128 exec_ram[exec_ram_pos++] = 128; exec_ram[exec_ram_pos++] = 0x31; printf("31 80 - add r1, #128\n"); } if(offset) { // ADD r1, #offset exec_ram[exec_ram_pos++] = offset; exec_ram[exec_ram_pos++] = 0x31; printf("31 %02X - add r1, #%d\n", offset, offset); } if(IS_ALIGN && (s_pos & 1)) { // byte align // LDRB r2, [r1, #0] exec_ram[exec_ram_pos++] = 0x0A; exec_ram[exec_ram_pos++] = 0x78; printf("78 0A - ldrb r2, [r1, #0]\n"); // STRB r2, [r0, #0] exec_ram[exec_ram_pos++] = 0x02; exec_ram[exec_ram_pos++] = 0x70; printf("70 02 - strb r2, [r0, #0]\n"); // LDRB r2, [r1, #1] exec_ram[exec_ram_pos++] = 0x4A; exec_ram[exec_ram_pos++] = 0x78; printf("78 4A - ldrb r2, [r1, #1]\n"); // STRB r2, [r0, #1] exec_ram[exec_ram_pos++] = 0x42; exec_ram[exec_ram_pos++] = 0x70; printf("70 42 - strb r2, [r0, #1]\n"); } else { // word align // LDRH r2, [r1, #0] exec_ram[exec_ram_pos++] = 0x0A; exec_ram[exec_ram_pos++] = 0x88; printf("88 0A - ldrh r2, [r1, #0]\n"); // STRH r2, [r0, #0] exec_ram[exec_ram_pos++] = 0x02; exec_ram[exec_ram_pos++] = 0x80; printf("80 02 - strh r2, [r0, #0]\n"); } // ADDS r0, #2 exec_ram[exec_ram_pos++] = 0x02; exec_ram[exec_ram_pos++] = 0x30; printf("30 02 - adds r0, #2\n"); s_pos += 2; break; case VAR_BYTE: printf("// BYTE[%d]\n", i); offset = (i - last_var) * 8; last_var = i; while(offset > 128) { offset -= 128; // ADD r1, #128 exec_ram[exec_ram_pos++] = 128; exec_ram[exec_ram_pos++] = 0x31; printf("31 80 - add r1, #128\n\r"); } if(offset) { // ADD r1, #offset exec_ram[exec_ram_pos++] = offset; exec_ram[exec_ram_pos++] = 0x31; printf("31 %02X - add r1, #%d\n", offset, offset); } // LDRB r2, [r1, #0] exec_ram[exec_ram_pos++] = 0x0A; exec_ram[exec_ram_pos++] = 0x78; printf("78 0A - ldrb r2, [r1, #0]\n"); // STRB r2, [r0, #0] exec_ram[exec_ram_pos++] = 0x02; exec_ram[exec_ram_pos++] = 0x70; printf("70 02 - strb r2, [r0, #0]\n"); // ADDS r0, #1 exec_ram[exec_ram_pos++] = 0x01; exec_ram[exec_ram_pos++] = 0x30; printf("30 01 - adds r0, #1\n"); s_pos += 1; break; } } } printf("// EXIT\n"); // POP {r2, pc} exec_ram[exec_ram_pos++] = 0x04; exec_ram[exec_ram_pos++] = 0xBD; printf("BD 04 - pop {r2, pc}\n"); #if 0 printf("SMC:\n"); for(int i = 0; i < exec_ram_pos / 2; i++) printf("%02X %02X\n", exec_ram[i * 2 + 1], exec_ram[i * 2 + 0]); #endif } int _tmain(int argc, _TCHAR* argv[]) { set_new_mask(0xc7); _getch(); return 0; } СМК: // r0 = *s, r1 = var B5 04 - push {r2, pc} // DWORD[0] 68 0A - ldr r2, [r1, #0] 60 02 - str r2, [r0, #0] 30 04 - adds r0, #4 // WORD[1] 31 08 - add r1, #8 88 0A - ldrh r2, [r1, #0] 80 02 - strh r2, [r0, #0] 30 02 - adds r0, #2 // DWORD[2] 31 08 - add r1, #8 88 0A - ldrh r2, [r1, #0] 80 02 - strh r2, [r0, #0] 88 4A - ldrh r2, [r1, #2] 80 42 - strh r2, [r0, #2] 30 04 - adds r0, #4 // BYTE[6] 31 20 - add r1, #32 78 0A - ldrb r2, [r1, #0] 70 02 - strb r2, [r0, #0] 30 01 - adds r0, #1 // BYTE[7] 31 08 - add r1, #8 78 0A - ldrb r2, [r1, #0] 70 02 - strb r2, [r0, #0] 30 01 - adds r0, #1 // EXIT BD 04 - pop {r2, pc} Результат на Cortex-M0 RESULT[20000F44]: 78 56 34 12 CD AB 44 33 22 11 77 88 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 236 30 июня, 2018 Опубликовано 30 июня, 2018 · Жалоба Проверил в железе - работает (Cortex-M0). мммм... неправильно :laughing: См. моё сообщение #39 - какой должен быть результат работы. К тому же: a) const в аргументе set_new_mask() - лишнее; б) R2,LR в вашей функции - не нужно сохранять, см. соглашения вызова компилятора; в) даже по Вашему алгоритму копирования - очень неоптимально, количество команд в 2 раза больше, чем можно было бы (для Cortex-M4). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
adnega 11 30 июня, 2018 Опубликовано 30 июня, 2018 · Жалоба мммм... неправильно А что именно неправильно? Есть таблица переменных состоящая из значений и типов. Есть маска, где каждый бит связан с соответствующим элементом таблицы. Есть функция-генератор, создающая в рантайме код, при выполнении которого в выходной поток копируются данные из таблицы с учетом длины и заданной маски. Для заданного var, RESULT (отработал СМК) такой ожидаете? Если нет, то где ошибка? a) const в аргументе set_new_mask() - лишнее; Ну, функция set_new_mask не должна менять mask, поэтому и const. Или я вас не понял. б) R2,LR в вашей функции - не нужно сохранять, см. соглашения вызова компилятора; Вы же супер-скорость хотели. Выкидывайте push и pop - и вот вам готовый участок кода, дающий результат, но не забудьте проинициализировать r0 и r1. Если нужна именно как функция, то достаточно одного "bx lr" в конце. в) даже по Вашему алгоритму копирования - очень неоптимально, количество команд в 2 раза больше, чем можно было бы (для Cortex-M4). Какие именно команды лишние? Можно IS_ALIGN обнулить, тогда генератор будет работать с невыровненными данными. Попробую сегодня избавиться от лишних adds. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 236 30 июня, 2018 Опубликовано 30 июня, 2018 · Жалоба А что именно неправильно? Есть таблица переменных состоящая из значений и типов. Вы же ассемблер понимаете? Тогда посмотрите на требуемый результат (код) в сообщении #39 и поймёте в чём разница. Нет таблицы переменных, есть таблица указателей на переменные. Так как эти переменные разбросаны по всей программе и объединить их в одну область памяти (структуру) нельзя. Они находятся в разных обособленных службах программы, и там и должны оставаться. А адресация их идёт через таблицу указателей. Я писал об этом. И в примере результата это чётко видно. Если си-исходник будет понятней, то: enum {N = <максимум 64>}; enum {TYP_s16, TYP_u16, TYP_s32, TYP_u32, TYP_float, TYP_n}; struct { u8 main:3; u8 misc:5; } const isTyp[N] = {{TYP_s32, ...}, {TYP_u16, ...}, ...}; u8 isTypSize[TYP_n] = {2, 2, 4, 4, 4}; char *psrc; char *pdst; if (map & 1 << 0) { psrc = varPtrs[0]; if (isTypSize[isTyp[0].main]) == 4) { *(u32 *)pdst = *(u32 *)psrc; pdst += 4; } else { *(u16 *)pdst = *(u16 *)psrc; pdst += 2; } } if (map & 1 << 1) { psrc = varPtrs[1]; if (isTypSize[isTyp[1].main]) == 4) { *(u32 *)pdst = *(u32 *)psrc; pdst += 4; } else { *(u16 *)pdst = *(u16 *)psrc; pdst += 2; } } //и так далее... так сейчас в си-исходнике сделано. Цель СМК - построить оптимальный код выкинув кучу ненужных операций из этого алгоритма по текущей карте map, до следующего её изменения. Какие именно команды лишние? Можно IS_ALIGN обнулить, тогда генератор будет работать с невыровненными данными. Попробую сегодня избавиться от лишних adds. У меня Cortex-M4. Он поддерживает команды с пост- и пре- модификациями адреса. Например: LDR R0, [R1], #4 тогда ваш код сократится в 2 раза. Да я уже вчера всё сделал. И даже больше. Мой генератор ещё и перемежение команд поддерживает для исключения штрафов между командами LDR. :rolleyes: И я его на асме написал. Хотя это просто из спортивного интереса. B) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
adnega 11 30 июня, 2018 Опубликовано 30 июня, 2018 · Жалоба Да я уже вчера всё сделал Покажите пожалуйста выход генератора для случая DWORD, WORD, DWORD, BYTE, BYTE в виде asm-инструкций. У меня с таблицей переменных и невыровненными данным получилось так // r0 = *s, r1 = var // DWORD[0] 68 0A - ldr r2, [r1, #0] 60 02 - str r2, [r0, #0] // WORD[1] 89 0A - ldrh r2, [r1, #8] 80 82 - strh r2, [r0, #4] // DWORD[2] 8A 0A - ldrh r2, [r1, #16] 80 C2 - strh r2, [r0, #6] 8A 4A - ldrh r2, [r1, #18] 81 02 - strh r2, [r0, #8] // BYTE[6] 31 30 - add r1, #48 78 0A - ldrb r2, [r1, #0] 72 82 - strb r2, [r0, #10] // BYTE[7] 7A 0A - ldrb r2, [r1, #8] 72 C2 - strb r2, [r0, #11] 30 0C - adds r0, #12 47 70 - bx lr Кста, а есть у кого-нить справочник машинных кодов для Cortex-M всех семейств? Не путать со справочником asm-команд, который найти не составляет труда. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AlexandrY 3 30 июня, 2018 Опубликовано 30 июня, 2018 · Жалоба Кста, а есть у кого-нить справочник машинных кодов для Cortex-M всех семейств? ARM®v7-M Architecture Reference Manual Господа, вы тут явно пытаетесь эмулировать DMA. :biggrin: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AVI-crak 0 30 июня, 2018 Опубликовано 30 июня, 2018 · Жалоба Есть мысль использовать самомодифицирующийся код для оптимизации решения одной задачи. Если "модификация" происходит под внешним управлением - то это называется эмуляцией. Доказательство очень простое: информация от том что и как необходимо изменить - остаётся без изменений. Место хранения этой информации не важно, важно то что эта информация является избыточной. Самомодифицирующийся код в явном виде делится на два типа поведения: модификация себя любимого под внешним управлением, и автономное поведение. Оба случая утрачивают начальное состояние кода. Более простое название этого процесса - полиморфный код. Используется вирусами, защитой лицензии, и как не странно - антивирусами. Насколько я верно понял, вам нужно выполнять внешний код из текстового ввода. То-есть все те-же команды ассемблера arm - записанные в текстовом массиве. Без разметки границ, без легирования меток, и без чёткой локализации хранения данных. Поздравляю - это называется парсер. Имеет смысл посмотреть блочную реализацию парсера бэйсика. На него кстати есть с десяток активных проектов на гите, в том числе и под арм. Или реализацию джавы для арм, хотя там без тяжёлых наркотиков очень трудно разобраться. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 236 30 июня, 2018 Опубликовано 30 июня, 2018 · Жалоба Покажите пожалуйста выход генератора для случая DWORD, WORD, DWORD, BYTE, BYTE в виде asm-инструкций. Да, как только поборю IAR. Если у Вас IAR, то как Вы ему сказали, чтобы он массив объявленный в программе как массив, показывал в окне дизасма как код? А то у меня он, собака, как только видит что это массив, показывает просто как кучу констант DC32 как этот массив не объявляй. Не могу заставить его дизассемблировать :(((( И мне не нужны байтовые операции - переменные только 16 и 32 бита. Кста, а есть у кого-нить справочник машинных кодов для Cortex-M всех семейств? Мне тоже хотелось-бы. Не нашёл в инете. Только если правильно выражаться: таблица маш.кодов набора инструкций Thumb-2. Господа, вы тут явно пытаетесь эмулировать DMA. :biggrin: Да причём тут DMA??? Каким боком он поможет в этой задаче? Разве чтобы только затормозить процедуру в несколько раз? Более простое название этого процесса - полиморфный код. Мне без разницы как это называть. Пускай будет полиморфный. А что именно требуется - мне кажется уже каждый должен был понять, хоть немного почитав тред. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
adnega 11 30 июня, 2018 Опубликовано 30 июня, 2018 · Жалоба Да, как только поборю IAR. gcc-шный objdump легко превращает бинарник в s-файл. Можете скинуть бинарь - я его конвертну, если у вас нет gcc. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AlexandrY 3 30 июня, 2018 Опубликовано 30 июня, 2018 · Жалоба Да причём тут DMA??? Каким боком он поможет в этой задаче? Разве чтобы только затормозить процедуру в несколько раз? Скопирует все переменные в одну область и вышлет куда надо. Или даже без копирования вышлет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 236 30 июня, 2018 Опубликовано 30 июня, 2018 · Жалоба Можете скинуть бинарь - я его конвертну, если у вас нет gcc. Спасибо, уже не надо - просто копировал из массива результат в неиспользуемую память МК, а для такой памяти IAR позволяет делать дизасм. Так и отладил. Вобщем: всё ок работает алгоритм. :rolleyes: Ниже прикладываю результат его работы для 64-битного слова: 0000.002A.1003.0006. При таких весах битов карты (см. установленные биты в бит-карте выше): бит1=2 байта, бит2=2 байта, бит16=4 байта, бит17=2 байта, бит28=4 байта, бит33=4 байта, бит35=4 байта, бит37=2 байта. Результат картинкой (не знаю как в IAR сохранить текстовое содержимое окна дизасма, а InqSoft Scaner не захватывает текст из этого окна): А здесь результат в бинарнике: smk00.zip Итого - время выполнения этого кода думаю будет == примерно 31 такт (не измерял), при условии что dst на входе - выровнен на 4. Как можно догадаться: функция строится таким образом, чтобы она была определена как: extern "C" void * Func(void *dst, u32 *table); где: dst - буфер для записи (передаётся в R0); table - массив из 64-х указателей на захватываемые переменные. Скопирует все переменные в одну область и вышлет куда надо. Или даже без копирования вышлет. Ну-ну. А теперь объясните как он это скопирует, когда переменные разбросаны по всей памяти МК кусочками по 2 и по 4 байта? :smile3009: Про передачу свЯзными списками я в курсе. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AlexandrY 3 30 июня, 2018 Опубликовано 30 июня, 2018 · Жалоба Ну-ну. А теперь объясните как он это скопирует, когда переменные разбросаны по всей памяти МК кусочками по 2 и по 4 байта? :smile3009: Про передачу свЯзными списками я в курсе. И чем не подошла передача связными списками? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 236 30 июня, 2018 Опубликовано 30 июня, 2018 · Жалоба И чем не подошла передача связными списками? Тем что при программировании каждого сегмента списка, DMA-контроллер читает из памяти следующий блок-описатель сегмента, который в моём МК насколько помню == 5 слов. Это кроме собственно пересылки потом. И так - на каждую переменную. В итоге количество обращений к памяти в разы больше, и скорость выполнения в разы меньше чем с СМК. Уже не говоря о манипуляциях с IO-регистрами DMA. Да и ОЗУ для описания такого связного списка нужно больше. В то время как время выполнения результата генератора СМК приведённого выше, думаю должно быть == ~31 такт. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AlexandrY 3 30 июня, 2018 Опубликовано 30 июня, 2018 · Жалоба В то время как время выполнения результата генератора СМК приведённого выше, думаю должно быть == ~31 такт. Что-то непонятная мне логика. В управлении мотором или SMPS самые приоритетные прерывания и процедуры - это токовые контуры. Они безальтернативно самые приоритетные и прервут любую пересылку или еще что-там. Т.е. ваша программная пересылка гарантировано будет прервана и задержана как минимум на время прерываний в токовом контуре. Таким образом теряете детерминизм и гарантированность времени окончания пересылки, так какой прок экономить такты? DMA же этой проблемы не имеет. Для справки, прерываний в токовом контуре у самых навороченных DSP от TI заточенных на это длится не менее 1 мкс, это 140 тактов в чипе с частотой 140 МГц. Вот плюс минус сотня тактов и будет погрешностью. Так чего экономить 30 если погрешность больше 100? Я честно думал, что речь идет об оптимизации именно алгоритмов в токовых контурах или алгоритмов модуляции. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 180 30 июня, 2018 Опубликовано 30 июня, 2018 · Жалоба jcxz, а зачем тут это? Вы сначала загружаете адрес интересуемой переменной из таблицы, потом загружаете значение переменной по этому адресу, и сохраняете в dst с постинкрементом, это понятно. А выделенное то зачем? Вы что-то говорили про перемежение инструкций для удаления штрафов LDR/STR. Могли бы озвучить, в чем там проблема? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться