Встроенный sdcc asm() не работает
Я использую GCC (исправление) SDCC с Eclipse IDE для компиляции кода C для встроенной цели архитектуры 8051. Мне нужно вставить несколько NOP для синхронизации, и я не могу заставить компилятор принимать встроенный код сборки.
С __asm__ ("; This is a comment\nlabel:\n\tnop");
(как предложено ниже) или варианты я получаю предупреждение 112: неявное объявление функции '__asm__' и затем ошибка 101: слишком много параметров, как будто я пытаюсь вызвать необъявленную функцию. Я пробовал все другие опции в разделе 3.14 руководства SDCC. __asm ... __endasm
дает синтаксическую ошибку на __asm
То же самое с одним подчеркиванием, и комбинации пробелов, переносов или той же строки не помогают.
Если я правильно соединяю командную строку из Makefile (без пути #include), CFLAGS в командной строке SDCC:
-Wp,-MD,$(@:%.rel=%.d),-MT,$@,-MP --disable-warning 110 -Wa,-p --model-medium
2 ответа
Перемещено из комментария
В источниках лексера SDCC 3.1.0 я вижу, что оба _asm/_endasm
а также __asm/__endasm
поддерживаются. Я еще не заметил поддержку __asm("string")
в парсере пока нет.
Также в коде лексера тип лексинга встроенного токена "blob" токена изменяется на CPP_ASM
только если свойство называется preproc_asm
установлен в 0
как видно из sdcc/support/cpp/libcpp/lex.c:1900
,
result->type = CPP_NAME;
{
struct normalize_state nst = INITIAL_NORMALIZE_STATE;
result->val.node.node = lex_identifier (pfile, buffer->cur - 1, false,
&nst);
warn_about_normalization (pfile, result, &nst);
}
/* SDCC _asm specific */
/* handle _asm ... _endasm ; */
if (result->val.node.node == pfile->spec_nodes.n__asm || result->val.node.node == pfile->spec_nodes.n__asm1)
{
if (CPP_OPTION (pfile, preproc_asm) == 0)
{
comment_start = buffer->cur;
result->type = CPP_ASM;
_sdcpp_skip_asm_block (pfile);
/* Save the _asm block as a token in its own right. */
_sdcpp_save_asm (pfile, result, comment_start, result->val.node.node == pfile->spec_nodes.n__asm);
}
result->flags |= ENTER_ASM;
}
else if (result->val.node.node == pfile->spec_nodes.n__endasm || result->val.node.node == pfile->spec_nodes.n__endasm1)
{
result->flags |= EXIT_ASM;
}
/* Convert named operators to their proper types. */
else if (result->val.node.node->flags & NODE_OPERATOR)
{
result->flags |= NAMED_OP;
result->type = (enum cpp_ttype) result->val.node.node->directive_index;
}
break;
Решение было добавить #pragma preproc_asm -
(или же +
) в верхней части файла и использовать мультилинию __asm
/__endasm
блоки.
Эта ссылка: http://www.crossware.com/smanuals/c8051/_t243.html
имеет это сказать о встроенном коде сборки
Код на ассемблере может быть встроен в ваш исходный код на C двумя способами:
using the #asm/#endasm preprocessor directives
using the _asm keyword
Директивы препроцессора #asm и #endasm позволяют включать ассемблерный код в любом месте файла исходного кода C, единственное ограничение заключается в том, что он не может быть расположен в выражении. Все строки между #asm и #endasm передаются напрямую через неизмененный в промежуточный файл, обрабатываемый ассемблером, и поэтому поддерживаются все правила для исходного кода кросс-ассемблера.
Директивы препроцессора #if, #ifdef, #ifndef, #else, #elif и #endif действительны между #asm и #endasm и поэтому могут использоваться для поддержки кода ассемблера, если это необходимо.
Ключевое слово _asm может использоваться только внутри функций. Он используется со следующим синтаксисом:
_как м();
Строковая константа передается напрямую через неизмененную как единственная строка в промежуточный файл, обрабатываемый ассемблером. Поэтому каждый должен быть верной строкой кода ассемблера.
Одним из преимуществ синтаксиса _asm является то, что он подлежит замене токена препроцессором Си. Следовательно, оператор может быть сгенерирован серией макросов.
Также с синтаксисом _asm компилятор поддерживает специальную конструкцию, обеспечивающую легкий доступ к переменным Си. Если имя переменной помещается в строковую константу в фигурных скобках, компилятор заменяет имя переменной (и фигурные скобки) соответствующей подстрокой в зависимости от расположения переменной. Смотрите следующие разделы для более подробной информации.
Компилятор генерирует мнемонику в верхнем регистре, поэтому, если для встроенного кода ассемблера выбран нижний регистр, его можно четко отличить от кода, сгенерированного компилятором, в файле списка.
тем не менее, правильный формат: '_asm(" nop");' потому что мнемоническая инструкция по сборке не может быть первой строкой (эта привилегия для меток)