3

I'm using GCC (correction) SDCC with the Eclipse IDE to compile C code for an 8051 architecture embedded target. I need to insert a few NOPs for timing, and I can't get the compiler to accept inline assembly code.

With __asm__ ("; This is a comment\nlabel:\n\tnop"); (as suggested below) or variations I get warning 112: function '__asm__' implicit declaration and then error 101: too many parameters, as if I'm trying to call an undeclared function. I've tried all other options in the SDCC manual section 3.14 also. __asm ... __endasm gives a syntax error on __asm, same with a single underbar, and combinations of whitespace, newlines, or the same line don't help.

If I'm piecing together the command line from the Makefile correctly (without the #include path), the CFLAGS on the SDCC command line are:

-Wp,-MD,$(@:%.rel=%.d),-MT,$@,-MP --disable-warning 110 -Wa,-p --model-medium

CarpeCimex
  • 135
  • 2
  • 10
  • 2
    Please show your whole function and the command line you're using to compile this code. – Carl Norum Dec 31 '14 at 04:06
  • 2
    You say you compile for 8051, and you say GCC. To me this doesn't really make sense - or is there a port of GCC for 8051 now? Which compiler do you really use? Do you use mcs51gcc? BTW what do you mean by "standard syntax"? C89/C99/C11 do not define a syntax for inline assembly. – Christian Hujer Dec 31 '14 at 04:19
  • 1
    AFAIK: For gcc to detect asm keyword, you need to pass `-std=gnu99` as the flag to gcc during compilation – Santosh A Dec 31 '14 at 04:34
  • If what you're using is really SDCC, then [the correct syntax is (Section 3.14.1.2)](http://sdcc.sourceforge.net/doc/sdccman.pdf) `__asm__ ("; This is a comment\nlabel:\n\tnop");`. Note the use of `;` and `\n\t`, this may be important in closing the previous statement. – Iwillnotexist Idonotexist Dec 31 '14 at 04:39
  • I looked at what Eclipse SDCC plugins exist and only found EclipseSDCC-1.0.0, which uses an SDCC from 2006. By looking at the [sources of SDCC 2.6.0](http://softlayer-dal.dl.sourceforge.net/project/sdcc/sdcc/2.6.0/sdcc-src-2.6.0.tar.gz), which date from about that time, I see that the only valid inline assembly markers are `_asm`/`_endasm`, note the single underscores. Especially look at `support/cpp2/cpplex.c`. – Iwillnotexist Idonotexist Dec 31 '14 at 21:09
  • 1
    @Iwillnotexist_Idonotexist -- thanks for the excellent digging! `_asm` says it's deprecated, use `__asm` instead, still doesn't work. SDCC help says it's v3.1.0. I don't see any inline assembly flags in the compiler options. – CarpeCimex Dec 31 '14 at 21:23
  • @CarpeCimex [In the sources of SDCC 3.1.0](http://colocrossing.dl.sourceforge.net/project/sdcc/sdcc/3.1.0/sdcc-src-3.1.0.tar.bz2)'s lexer, I see that both `_asm/_endasm` and `__asm/__endasm` are supported, but I haven't noticed yet support for `__asm("string")` yet. Also in the lexer's code, the lexing type of the object gets changed to `CPP_ASM` _only if_ a property called `preproc_asm` is set to `0`. Can you try adding `#pragma preproc_asm -` (or `+`) in the line before the `_asm` and inline chunk? – Iwillnotexist Idonotexist Dec 31 '14 at 22:15
  • 1
    @Iwillnotexist_Idonotexist -- That did it! I found the `preproc_asm` description in the manual. It's supposed to default 'on', but doesn't seem to. Either a `+` or a `-` seems to work, too. Please put this in an answer and I'll up-vote it. There's no way in the world I would have figured this out without your help! – CarpeCimex Dec 31 '14 at 23:42

2 Answers2

1

Moved from comment

In the sources of SDCC 3.1.0's lexer, I see that both _asm/_endasm and __asm/__endasm are supported. I haven't noticed yet support for __asm("string") in the parser yet.

Also in the lexer's code, the lexing type of the inline assembly token "blob" gets changed to CPP_ASM only if a property called preproc_asm is set to 0, as can be seen in 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;

The solution was to add #pragma preproc_asm - (or +) at the top of the file and to use the multiline __asm/__endasm blocks.

Community
  • 1
  • 1
Iwillnotexist Idonotexist
  • 13,297
  • 4
  • 43
  • 66
  • @CarpeCimex I took the liberty of including the relevant lexer source code, the one that made me realize the relevance of `#pragma preproc_asm (+|-)`. – Iwillnotexist Idonotexist Dec 31 '14 at 23:57
  • 1
    @Iwillnotexist_Idonotexist `#pragma preproc_asm +` at the top of the file and a multiline `__asm ... __endasm` assembly block like at the top of page 51 in the [manual](http://sdcc.sourceforge.net/doc/sdccman.pdf) did it. Many thanks! – CarpeCimex Jan 01 '15 at 00:14
  • @CarpeCimex On second thought: Does the code merely _compile_ or are the `nop`s actually present in the binary output? – Iwillnotexist Idonotexist Jan 01 '15 at 00:34
  • 1
    @Iwillnotexist_Idonotexist :-) I was worried about that too, and indeed the assembly code appears in the assembly listing. – CarpeCimex Jan 01 '15 at 01:49
0

this link: http://www.crossware.com/smanuals/c8051/_t243.html

has this to say about inline assembly code

Assembler code can be embedded into your C source code in two ways:

using the #asm/#endasm preprocessor directives
using the _asm keyword

The pre-processor directives #asm and #endasm allow assembler code to be included anywhere within the C source code file, the only restriction being that it cannot be positioned within an expression. All lines between #asm and #endasm are passed straight through unmodified to the intermediate file processed by the assembler and so all of the rules for the cross assembler source code are supported.

The pre-processor directives #if, #ifdef, #ifndef, #else, #elif and #endif are valid between #asm and #endasm and so can be used to maintain the assembler code if required.

The _asm keyword can only be used within functions. It is used with following syntax:

_asm();

The string constant is passed straight through unmodified as a single line to the intermediate file processed by the assembler. Each should therefore be a valid line of assembler code.

One advantage of the _asm syntax is that it is subject to token replacement by the C preprocessor. Therefore the statement can be generated by a series of macros.

Also with the _asm syntax, the compiler supports a special construct to enable easy access to C variables. If the variable name is placed in the string contant within curly braces, the compiler replaces the variable name (and the curly braces) with the appropriate substring depending upon the location of the variable. See the following sections for more details.

The compiler generates upper case mnemonics and so if lower case is chosen for the in-line assembler code it can be clearly distinguished from the compiler generated code in the list file.

however, the correct format is: '_asm(" nop");' because a mnemonic assembly instruction cannot be the first thing on a line (that privilege is for labels)

user3629249
  • 16,402
  • 1
  • 16
  • 17