Shop OBEX P1 Docs P2 Docs Learn Events
Mixing languages C + Spin + pasm — Parallax Forums

Mixing languages C + Spin + pasm

Until now, I have written everything that has to run fast (hardware drivers) in pasm and evrything else (command interpreter, string processing) in Spin. The big performance gain of the P2 makes it possible to code more and more in highlevel language. Even control loops that have to run several 1000 times a second can be written in Spin (at least in fastspin), now.

Because C has better support for data types (struct and float) I'm currently experimenting with C. I saw that there are lots of include files in the FlexGui/include folder, some samples and documentastion in /sample and /doc. But unfortunatelly it doesn't answer all of my questions so I have to ask here.

How can I include C objects into Spin code? Declaring an OBJ doesn't work for a .c file. Do I have to use
PUB FILE "myfile.c" myfunction(arg)
for each function?

How can I declare a DAT section in a .c file to be used as assembler code to COGNEW()? I tried __pasm{} at the global scope but I fear it doesn't do exacly what I want. It doesn't allow ORG or RES.
«1

Comments

  • RaymanRayman Posts: 14,646
    I'd like to know too...

    Think I found how to do the other way and include spin in c:

    struct __using("PropSerial/SmartSerial.spin2") fds;
    ...
    fds.start(63, 62, 0, 23400);
  • RaymanRayman Posts: 14,646
    Wow, putting
    struct __using("
    
    into the search box gives a funny result...
  • Obj should work for including .c and .bas files in Spin. See the file server samples for an example (it uses .cc instead of .c for a technical reason involving the scope of enums, but in most cases it wont matter)

    And org and res should work in c pasm sections, if for some reason they dont thats a new bug.
  • Ok, thanks. I found out that for including .c files as OBjs in Spin you have to specify the filename including extension. For .spin and -spin2 files the extension is optional.

    The following file compiles with errors. It says "unexpected constant" in the line of the "ORG 0". If I remove the "0" the ORG seems OK but it complains "res not valid after orgh".
  • RaymanRayman Posts: 14,646
    documentation says to do it this way:
    ## Extensions to C
    
    ### Inline Assembly (C Style)
    
    The inline assembly syntax is similar to that of MSVC. Inline assembly blocks are marked with the keyword `__asm`. For example, a function to get the current cog id could be written as:
    ```
    int getcogid() {
       int x;
       __asm {
          cogid x
       };
       return x;
    }
    

    I think you have pasm instead of asm...
  • Inline assembly works perfecly. My problem is that I have a larger block of code which I want to start in an extra cog. Res is there to save memory so that the place holders for uninitilized longs at the end do not use hub ram and unnecesarily add to the program size. Not absolutely important theese days now we have 512kB. But it should work anyway I thought.
  • I found out that
    * I had to add a header file. Otherwise the including into the main (Spin) file doesn't work
    * I had to convert all function idetifiers to lowercase
    * I replaced RES by LONG

    But it still doesn't work. Somehow the assembler thinks that my assembler code is meant to go to hub ram, not cog ram.
    __pasm {
    ORG
    startEnc
    		drvl    #pinEncTe
    		fltl	#pinEncTx		' reset smartpin
    		wrpin	mode_stx,#pinEncTx	' synchronous serial transmit
    		wxpin	baud_bits,#pinEncTx	' 2.5MBd 16N1
    		drvl	#pinEncTx		' enable TX smartpin
    
    is compiled to
    	alignl
    _Sc3_SanyoEnc_dat_
    	byte	$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
    '-' ORG
    '-' startEnc
    '-' 		drvl # 3
    	byte	$58, $06, $64, $fd
    '-' 		fltl # 2
    	byte	$50, $04, $64, $fd
    '-' 		wrpin mode_stx,# 2
    	long	((@@@_Sc3_SanyoEnc_dat_ + 240)>>9) | $fc05e002
    	long	(((@@@_Sc3_SanyoEnc_dat_ + 240)&$1ff)<<9) | $fc15f002
    	byte	$58
    	byte	$04
    	byte	$64
    	byte	$fd
    
    which is complete nonsense. The ORG is ignored. It seems that I'm doing something fundamentally wrong. __pasm{} is probably not meant for code running in a cog.
  • I saw that the led_server_asm example does the same thing. And it compiles without errors. The only difference I see is that it has the __pasm{} at the begining and my code has it at the end.
  • RaymanRayman Posts: 14,646
    I think any inline assembly is going to be hubexec mode in HUB RAM with FastSpin, just like the rest of the code.
    Also, I think the documentation says that Spin can be mixed case, but you have to use the lowercase in C.

    If you really want the code to be in a cog, you need to do a coginit on it and start in another cog.
    At least, I think so.
  • RaymanRayman Posts: 14,646
    I guess this is one big difference between Spin2 and Fastspin...
    I think Spin2 inline assembly is in the cog...
  • __pasm outside of functions is intended to work the same as dat in spin. The code does have to be placed in hub memory initially, this is true of all code (everything starts in hub and gets loaded into cog or lut by coginit). The listing file generated by -l is a much better guide to where things are intended to run than the .pasm file
  • Ah, thanks Eric. Can you take a look at my code and tell what's the difference? I.E. why it works in led_server_asm and doesn't in mine?

    ... WOW, wait! I just moved the __pasm{} section to the beginning of the file right after the #include and #defines. And now it suddenly works, at least the compiler no longer complains.

    There must be some unintended mode change when __pasm{} is placed after variable or function definitions. I'm not good at finding problems in hexdumps or .lst files. I'm not sure if it's a compiler bug or if I did something wrong.
  • I did notice one potential issue: you used "ORG" instead of "org", and C is case sensitive, so it didn't recognize the directive. I'll add some code to work around this in the next version of the compiler.
  • RaymanRayman Posts: 14,646
    ersmith: Hope you're getting better!
  • I tried to port most of my code to C to get around that case sensitivity issues. But everything gets worse and I can't even inlcude a single header file successfully. I guess I'm missing some basic understanding of how things work in Fastspin.

    I always get error messages like "error: unknown identifier LoadParameters used in function call". I double checked that I've included "parameters.h" and the spelling of the identifier. If I add some garbage characters after the declaration of LoadParameters() I get a different error so I'm sure that the file is really included and the declaration is not commented out. However, the compiler seems to ignore it completely.

    Would be really nice if somebody could tell me what I'm doing wrong.
  • David BetzDavid Betz Posts: 14,516
    edited 2020-04-07 18:37
    Your problem might be with these lines from commands.h:
    #define errInvCmd  1 // invalid command
    #define errRange   2 // out of range
    #define errInvReg  3 // invalid register number
    #define errInvCrc  4 // invaid CRC during read or verify
    
    I think the comment at the end of these lines might be included in the macro definition causing a syntax error in lines like this where the macros are used:
        if (!LoadParameters ()) error= errInvCrc;
    
    I suspect that this looks like this to the compiler which means the semicolon is part of the comment:
        if (!LoadParameters ()) error= 4 // invaid CRC during read or verify;
    
    Try removing those comments and see if this gets rid of your error.
  • @ManAtWork: I'm afraid I haven't had time to look at the problem, but are you sure that the LoadParameters() function is actually defined and being included in the compile (not just declared in the header)? Fastspin's error messages are still not the best, and basically it ignores the header declarations and just looks at the code that's actually being compiled. If you're using FlexGUI only one file (the top level one) is passed to the compiler, so then all the header files will have to have explicit _IMPL() macro calls on their function declarations to cause the implementation files to be included in the compilation too. If you're using the command line or "make" you don't need this, you can pass the files to the compiler just like you would with gcc or any other C compiler.
  • ersmith wrote: »
    @ManAtWork: I'm afraid I haven't had time to look at the problem, but are you sure that the LoadParameters() function is actually defined and being included in the compile (not just declared in the header)? Fastspin's error messages are still not the best, and basically it ignores the header declarations and just looks at the code that's actually being compiled. If you're using FlexGUI only one file (the top level one) is passed to the compiler, so then all the header files will have to have explicit _IMPL() macro calls on their function declarations to cause the implementation files to be included in the compilation too. If you're using the command line or "make" you don't need this, you can pass the files to the compiler just like you would with gcc or any other C compiler.
    How do you build something like this? Do you just put all of the .c and .spin2 files on the same command line?

  • RaymanRayman Posts: 14,646
    edited 2020-04-07 19:43
    ersmith made a special _IMPL() thing so you don't have to put c source on command line...
    Just include the .h file...
  • Rayman wrote: »
    ersmith made a special _IMPL() thing so you don't have to put c source on command line...
    Just include the .h file...
    Ah, but ManAtWork doesn't have those annotations.

  • David Betz wrote: »
    ersmith wrote: »
    @ManAtWork: I'm afraid I haven't had time to look at the problem, but are you sure that the LoadParameters() function is actually defined and being included in the compile (not just declared in the header)? Fastspin's error messages are still not the best, and basically it ignores the header declarations and just looks at the code that's actually being compiled. If you're using FlexGUI only one file (the top level one) is passed to the compiler, so then all the header files will have to have explicit _IMPL() macro calls on their function declarations to cause the implementation files to be included in the compilation too. If you're using the command line or "make" you don't need this, you can pass the files to the compiler just like you would with gcc or any other C compiler.
    How do you build something like this? Do you just put all of the .c and .spin2 files on the same command line?

    Either that or build a "header file" with _IMPL statements for all of your functions. For example the libc.a that comes with fastspin is just that: it contains declarations for all of the standard C functions and a pointer to where they're implemented. You can put that libc.a on the command line, although generally it won't be necessary if you #include the appropriate header files.
  • Ah OK, I stumbled over that _IMPL thing when browsing the library files (strings.h for example). But I thought that was meant for internal functions and special libraries and not for normal user code where a .c file exists.

    Eric, I think you mentioned somewhere in the documentation that there is no real linker but as there are no explanations of the consequences I haven't drawn any conclusions about what I have to do. I thought the compiler would automatically search for a *.c file if I include the matching .h file the same way it does when I define an object in Spin.

    _IMPL is not mentioned at all in C.pdf. I urgently recommend that you extend the documentation so that anyone who is familiar with a standard C compiler but new to Fastspin is able to use it without always asking you. Sorry for complaining... I don't want to steal your time. But exactly for that reason it's important to have good documentation. Especially if more users start to use Fastspin answering all that questions over and over again will be surely more work than writing a detailed documentation once.

    In the long term I think the best solution would be to add some sort of "add file to project" feature to FlexGUI as it exists in many other IDEs.
  • Adding _IMPL to the function declarations int the header file doesn't work. Now I no longer get errors when compiling the top level file but I get errors ("unexpected identifier `_IMPL', expecting ',' or ';'") when the parameters.c file is compiled which includes the parameters.h file, of course.

    So I fear FlexGUI doesn't allow projects with more than one .c file, at least not without requiring substantial changes to the code. One solution was to split the headers into one separate include file for the importing (higher level) file and one for it's own body (.c source). But that is a mess for larger projects.

    Another solution is stop using FlexGUI for the compiler invokation and to manually write a makefile. I will try that next. If I can't use FlexGUI anymore I could probably take an editor that supports syntax highlighting.
  • ManAtWork,
    What you want is "__fromfile" instead of "_IMPL".

    _IMPL() is only defined if you include compiler.h, and all that does is "#define _IMPL(x) __fromfile(x)"

  • Ok, different idea: I modify the compile command in FlexGUI so that fastspin is not called directly but the makefile is executed. But I have to lookup some aspects of shell scripting as I feel like I wrote my last MSDOS script almost 30 years ago. Calling a .bat batchfile doesn't work because Windows7 thinks this is a security issue and denies access to the library path for the batch file. But this should be possible somehow...
  • You can just put all of the source files on the same command line and it should work. FastSpin is unlike most other compilers in that it has to compile the entire program in a single compilation. It doesn't support separate compilation, object files, and libraries. That's been one of the challenges in getting it to compile things like MicroPython.
  • Yes, if I put all filenames on the command line it works. The only problem is that I have to change the command line for every project and each time I add a new file to a project.

    I have no problem adding a filename to a list (makefile) each time I add a file to a project. That does not happen very often and it requires a lot of writing anyway.

    But I'd like to be able to press a single button to (re-)compile a project even if I changed the project. That should be possible to be automated somehow. I think I'm just to stupid figuring out the right MSDOS commands...

    Changing the command line in FlexGUI to
    "%D/bin/fastspin" -2 -l %O %I <makefile
    
    doesn't work because the filename arguments can't be fetched from std-input but must be present at the command line.

    Changing the command line to
    "%S.make.bat"
    
    and putting the actual command line into the batch file also doesnt work. The batch file is called but it can't do anything because W7 denies access to almost anything. I think I had to edit the access right policies but I don't know how.
  • RaymanRayman Posts: 14,646
    edited 2020-04-08 12:44
    I think Visual Studio solves this problem with a "project". I actually didn't think about the sausage making until this type of problem showed up here...
    I guess VS puts all the C++ files on the compile command line automatically. Or, maybe compiles and links them all. I don't actually know.

    Anyway... Some type of project file may be the only clean way of doing this...

    On the other hand, "__fromfile" seems like a nice workaround, once you know about it.
  • __fromfile ("...c") in the header seems to work! :smiley: No idea why it does and why _IMPL doesn't. Ok, this is an acceptable workaround, for now. However, IMHO in the long term there should be some mechanism like a list of files belonging to the project or a makefile should be implemented. Or the compiler could simply look if there's a .c file for every .h file included and add it to the list automatically.
  • As Ray mentioned, _IMPL is just a #define for __fromfile that's defined in <compiler.h> (so you need to include that file before you can use _IMPL). It's there so that the header files can be used in other compilers too (_IMPL(x) expands to __fromfile(x) in fastspin and to nothing at all in other compilers, so the headers don't cause syntax errors for them). Sorry, I'm so used to using the defined version that I forgot the original.

    The documentation and error messages of fastspin certainly need a lot of work. I'm always happy to get pull requests :).

    In general if you're comfortable with using the command line and makefiles, then you might as well use those. There's nothing special about FlexGUI, it's just something I threw together for the benefit of people who wanted an IDE. But all of the "interesting" language and loader stuff is in fastspin and loadp2, and you can invoke those from a makefile or directly from the command line.
Sign In or Register to comment.