По соотношению - такая же зависимость, как под Uno, т.е. накладные расходы в процентах - одинаковы. Всё, мозги размяли, можно выдыхать Ессно, задача написания полноценного (более-менее) интерпретатора байт-кода - дело непростое. Но, опять же - имею своё мнение о том, что - задачи надо решать по мере поступления, и не пытаться впихнуть невпихуемое сразу и везде. Да, архитектуру парсера и представления байт-кода - продумывать надо, безусловно, но: также стоит отталкиваться и от задачи; вполне вероятно, что для какой-то конкретной задачи - можно родить интерпретатор, который устроит, и не будет при этом обобщённым по самое не балуй. В приведённом примере - достаточно расширить поддерживаемые команды на ещё один блок, например, вывод в Serial - и будет щастье в виде вывода в Serial. Сейчас изображу...
Вот, собственно - новая команда: напечатать в Serial переданный текст: Код (C++): //-------------------------------------------------------------------------------------------------------------------------------- typedef enum { incrementForBlock, endForBlock, pinWriteBlock, serialPrintBlock, } BlockType; //-------------------------------------------------------------------------------------------------------------------------------- uint8_t block[] = { incrementForBlock, // это цикл for c инкрементом 0x03, 0xE8, // 1000 проходов 1, // шаг инкремента // тут тело цикла pinWriteBlock, // пишем в пин 13, // номер пина HIGH, // уровень serialPrintBlock, // выводим в Serial 'H', 'e', 'l', 'l', 'o', '\n', '\0', pinWriteBlock, // пишем в пин 13, // номер пина LOW, // уровень // конец тела цикла endForBlock // цикл for закончился }; //-------------------------------------------------------------------------------------------------------------------------------- uint16_t executePinWriteBlock(uint8_t* bytecode) { bytecode++; // пропустили идентификатор блока (pinWriteBlock) //Serial.println(*bytecode); //Serial.println(*(bytecode+1)); digitalWrite(*bytecode, *(bytecode+1)); return 3; // возвращаем длину блока } //-------------------------------------------------------------------------------------------------------------------------------- uint16_t executeSerialPrintBlock(uint8_t* bytecode) { bytecode++; // пропустили идентификатор блока (serialPrintBlock) uint16_t len = 2; while(*bytecode != '\0') { Serial.print((char)*bytecode++); len++; } return len; } //-------------------------------------------------------------------------------------------------------------------------------- void executeIncrementForBlock(uint8_t* bytecode) { bytecode++; // пропустили идентификатор блока (incrementForBlock) uint16_t passes = (*bytecode++ << 8) | (*bytecode++); uint8_t increment = *bytecode++; Serial.print(F("Passes: ")); Serial.println(passes); Serial.print(F("Increment: ")); Serial.println(increment); uint32_t start = millis(); uint8_t* startCode = bytecode; bool canExitWhile = false; for(uint16_t i=0;i<passes;i+=increment) { canExitWhile = false; while(!canExitWhile) // шаримся по блокам тела цикла { switch(*startCode) { case pinWriteBlock: startCode += executePinWriteBlock(startCode); break; case serialPrintBlock: startCode += executeSerialPrintBlock(startCode); break; case endForBlock: //Serial.println("BEGIN"); startCode = bytecode; canExitWhile = true; break; default: //Serial.println("!!!!!"); break; } // switch } // while } // for uint32_t end = millis(); uint32_t elapsed = end - start; Serial.print(F("Count passes: ")); Serial.println(passes); Serial.print(F("Elapsed time, ms: ")); Serial.println(elapsed); float hz = (1.0/elapsed)*1000*passes; Serial.print(F("Frequency: ")); Serial.println(hz); } //-------------------------------------------------------------------------------------------------------------------------------- void setup() { Serial.begin(57600); pinMode(13,OUTPUT); uint16_t passes = 1000; uint32_t start = millis(); for(uint16_t i=0;i<passes;i++) { digitalWrite(13,HIGH); digitalWrite(13,LOW); } uint32_t end = millis(); uint32_t elapsed = end - start; Serial.print(F("Count passes: ")); Serial.println(passes); Serial.print(F("Elapsed time, ms: ")); Serial.println(elapsed); float hz = (1.0/elapsed)*1000*passes; // сколько раз за секунду выполнится тело цикла Serial.print(F("Frequency: ")); Serial.println(hz); Serial.println(); Serial.println("BYTE CODE TEST: "); Serial.println(); executeIncrementForBlock(block); } //-------------------------------------------------------------------------------------------------------------------------------- void loop() { // put your main code here, to run repeatedly: } //-------------------------------------------------------------------------------------------------------------------------------- Так что - узкоспециализированный/не узкоспециализированный, но - под свои задачи всегда можно написать достаточно эффективный инструмент, в принципе.
Помню на третьем курсе писал курсовую, автоматический пререводчик с одного языка программирования на другой. Хоть с русского на с++. Требования для конвертации: наличие интерпретатора исходного языка на целевом. Конечно о оптимальности и быстродействии полученного кода речи не шло. Увы за давностью лет разработки утеряны.
А это вообще возможно? Контрпример: на си есть функция, обрабатывающая массив произвольной длины и нужно перевести ее на паскаль.
Виртуальная машина моего ПЛК не умеет работать с периферией микраша напрямую. Скрипт работает только с параметрами общей системы, состоящей из множества устройств и подключённых к общей информационной шине. Поэтому поиск в словаре устройства нужного параметра по его уникальному имени не так быстр. Каждый раз, после прогона скрипта, все параметры изменившие своё значения, автоматически уходят на сервер и записываются в базу данных. Скрипт может использовать как параметры собственного устройства, так и других устройств, подключенных к общей системе. ПЛК может отслеживать любые параметры системы и воздействовать на собственные параметры. Если бы я напрямую дрыгал ножкой микраша, то это было бы много быстрее. Но передо мной стояла другая задача, а именно, нужно было наладить взаимодействие различных устройств друг с другом через пользовательские скрипты.
Нет, хэширование не применяю, поэтому эта операция жутко дорогая. Да пока и не нужно было особого быстродействия, поэтому оптимизацию не делал. Когда я на реле подавал килогерцы, оно только еле слышно пищит, к сожалению, реле в sonoff не твердотельные.
С подобным проблем не было. Рекурсию не удалось побороть , поэтому в рамках модели пришлось исключить рекурсивные программы из рассмотрения. Увы подробностей мало помню. Прошло более 10 лет
Не дороже, чем каждый раз строки сравнивать Подготовили map, потом быренько раз - и тыркнулись туда, куда надо. Впрочем, дело хозяйское
А моя виртуалка не боится рекурсий. Вот скрипт вычисления факториала: А вот ассемблерный код этого скрипта для моей виртуалки. Код (Text): shift -1 ldi 10 call factorial, 1 print exit :factorial ld_arg 0 ldi 1 gt je 8 ld_arg 0 ld_arg 0 ldi 1 sub call factorial, 1 mul ret ldi 1 ret Сам байткод составил 49 байт. Могло бы быть и меньше при использовании целочисленной арифметики, но моя виртулка использует везде именно дробную арифметику. Безусловно так, у меня например указатели функций всех инструкций лежат в одной таблице, дабы не делать полную проходку в поисках нужной функции через switch(). Ведь у меня их сейчас аж 37 ассемблерных инструкций.
А как вашими байт-кодами настроить таймер? Или настроить периферию в стм32 не прибегая к таким старомодным вещам, как cubemx?
Щас паровоз затянется глубоко, и, шумно выдохнув и прищурив правый глаз, с видом побитого жизнью гуру ехидно спросит:
да вообще не угадал)) Мне кажется, вы все идете не туда. Для чего в MCU тянуть технологии, которые предназначены для MPU? Между AVR и ARM? Я правильно понял?