fastspin compiler for P2: Assembly, Spin, BASIC, and C in one compiler

1353638404143

Comments

  • evanhevanh Posts: 9,030
    edited 2020-02-01 - 01:02:54
    Hmm, maybe I'm breaking something. Just tried to get the address of a single int and I get the message:
    error: Internal error: tried to use memory directly
  • evanhevanh Posts: 9,030
    edited 2020-02-01 - 04:23:31
    In Fastspin C, how to force some assembly to cogexec? I'm guessing best way is make a callable function.

    Is there any C documentation? I've not found any.

  • evanh wrote: »
    I'm trying to pass a small auto array to inline assembly. But the pointer still seems to be a hub address.
    {
    	long data[10] = {1,2,3,4,5,6,7,8,9,10};
    	long *addr = data;
    	int len = sizeof(data) / 4 - 1;
    	
    	printf( "addr = %lx, len = %d\n", addr, len );
    
    	__asm { ... }
    }
    
    The print is giving me values above 0x1000. What's wrong?

    Pointers are always hub addresses. The hub and cog address spaces are disjoint for data (for code the COG and LUT address space is mapped to 0x000-0x400
    evanh wrote: »
    In Fastspin C, how to force some assembly to cogexec? I'm guessing best way is make a callable function.

    There's no way to do that yet. The closest you can come is to enable FCACHE and wrap the inline assembly in code to load it into FCACHE. At some point I'd like to implement attributes to force functions into cog or lut memory, but I haven't had time to do that yet.
    Is there any C documentation? I've not found any.

    doc/c.md is all there is (in FlexGUI it's compiled to a .pdf and a .html).

  • Thanks for the clarifications Eric. It was dawning on me that I was expecting a bit much metal. :)

  • evanhevanh Posts: 9,030
    edited 2020-02-02 - 00:50:48
    -O2 optimisation probably should leave the instructions as is inside of __asm {} blocks. Further reading https://forums.parallax.com/discussion/comment/1488672/#Comment_1488672

    Or have a way to signal not to optimise a particular block.

  • getqx has a side effect (clearing an internal register), which the optimizer hasn't been told about, I missed that.

    It might not be a bad idea to add a "volatile" option to __asm (like GCC does) to tell the optimizer not to touch anything in it. The bad part of this is that a lot of people will use "__asm volatile" when they really should just use "__asm" :(. Unfortunately I think people are likely to overuse __asm in general; using the macros from propeller2.h and/or limiting asm use to just a few key functions will make the code more readable and more portable to other P2 C compilers.
  • @ersmith Does FlexBASIC attempt any optimizations in ASM...END ASM blocks? Or is what you enter exactly what you get?
  • Wuerfel_21Wuerfel_21 Posts: 609
    edited 2020-02-02 - 01:30:05
    ersmith wrote: »
    getqx has a side effect (clearing an internal register), which the optimizer hasn't been told about, I missed that.

    It might not be a bad idea to add a "volatile" option to __asm (like GCC does) to tell the optimizer not to touch anything in it. The bad part of this is that a lot of people will use "__asm volatile" when they really should just use "__asm" :(. Unfortunately I think people are likely to overuse __asm in general; using the macros from propeller2.h and/or limiting asm use to just a few key functions will make the code more readable and more portable to other P2 C compilers.
    "__asm volatile" in GCC means something very different - it tells the compiler that the asm has side effects (and thus, it can not eliminated or moved outside a loop). This of course only makes sense when using GCC's nice extended inline ASM syntax with defined inputs and outputs.
    GCC never actually touches your inline ASM, except for replacing certain escape sequences. It just pastes it right into the output ASM, including inconsistent indentation.
  • Eric,
    That last case, where I used GETQX in a precautionary way, isn't as effective as I'd first thought. If there is nothing in-progress in the pipeline when a new op is issued, then the hardware discards any dead results anyway.

    So, that use of GETQX is only effective if there is a cordic op actually still making its way through the pipeline at the time.

  • JRoark wrote: »
    @ersmith Does FlexBASIC attempt any optimizations in ASM...END ASM blocks? Or is what you enter exactly what you get?

    All the languages use the same output routines, and those optimize inline assembly along with everything else. Usually this is what you want: it improves both the generated code and (potentially) your code, e.g. if you write:
    function sum(a, b)
      asm
        add a, b
      end asm
      return a
    end function
    function sum1(a)
      return sum(a, 1)
    end function
    
    the optimizer can turn calls to "sum1(x)" into "x+1", because it knows what the "add" instruction does. It can also do the basic transformations (like turning "xor reg, ##(1<<n)" into "bitnot reg, #n") on your code that it does on the generated code.

    The next version of fastspin will allow you to type "asm const" to suppress optimization on asm blocks. It's usually a bad idea to use this; the only time it's useful, I think, is to work around an optimizer bug or when timing is critical (and you for some reason cannot use waitct or waitx to synchronize the timing; the optimizer does know about those).
    Wuerfel_21 wrote: »
    "__asm volatile" in GCC means something very different - it tells the compiler that the asm has side effects (and thus, it can not eliminated or moved outside a loop).
    I wouldn't say it's "very" different; without volatile the asm block does participate in the optimization, it's just that GCC treats the whole block as a single instruction, whereas fastspin knows about what the individual instructions within the block mean.
  • JRoarkJRoark Posts: 376
    edited 2020-02-05 - 13:43:43
    @ersmith While coding in FlexBASIC on Win10 using FlexGUI V4.1.2:

    I have a puzzlement about array declarations and assignments in FlexBASIC. There are several syntaxes to declare a SHARED array variable in FlexBASIC, and I find myself using them interchangably:
    dim shared as ulong a		'works
    dim shared as ulong b(10)	'works
    
    dim shared c as ulong		'works
    dim shared d(10) as ulong	'works
    
    dim shared as ulong e(10) = { 1,2,3,4,5,6,7,8,9,10 }	'works
    dim shared f(10) as ulong = { 1,2,3,4,5,6,7,8,9,10 }	'does NOT work
    
    dim shared as ulong g = 100    'works
    dim shared h as ulong = 100    'does NOT work
    
    print "done"
    

    But it seems that when using an initializer with a SHARED var, only one of the syntaxes works (see above). The other throws the error: "error: syntax error, unexpected '=', expecting $end or end of line or end or ':'

    Bug or feature? Or is this one of those "loose nut behind the user keyboard" things? :)
  • JRoark wrote: »
    @ersmith While coding in FlexBASIC on Win10 using FlexGUI V4.1.2:

    I have a puzzlement about array declarations and assignments in FlexBASIC. There are several syntaxes to declare a SHARED array variable in FlexBASIC, and I find myself using them interchangably:
    dim shared as ulong g = 100    'works
    dim shared h as ulong = 100    'does NOT work
    
    

    But it seems that when using an initializer with a SHARED var, only one of the syntaxes works (see above). The other throws the error: "error: syntax error, unexpected '=', expecting $end or end of line or end or ':'

    Bug or feature? Or is this one of those "loose nut behind the user keyboard" things? :)

    The initialization has to go next to the variable, as if it were an assignment statement, since more than one variable may be declared in a dim:
    dim shared as ulong g=100, h=200
    dim shared x=100, y=200 as ulong
    

    Do other BASICs allow it to go after the "as ulong" clause? I guess freebasic does, but it also only allows one variable to be declared at a time when the "as type" comes after the variable
  • Given that bit of context, this now makes perfect sense to me. Thanks!
  • I've released fastspin 4.1.3 (and flexgui 4.1.3). The only fastspin change is the "const" attribute for inline assembly blocks, to prevent the optimizer from changing them. I do urge people to use "asm const" sparingly; there are a lot of useful optimizations (like constant propagation and folding) that can be applied to inline assembly and which are suppressed by "asm const".
  • RaymanRayman Posts: 10,484
    edited 2020-02-08 - 00:05:48
    I think I was able to trick fastspin into checking my assembly driver code...
    It wasn't checking it before because Spin code started with "Stop" routine that didn't do anything.
    I had to compile the main Spin file for it to check for errors...

    But, I did this and now it checks everything:
    PUB Stop
        repeat
        start(pTiles, pColors)
    
  • Rayman wrote: »
    I think I was able to trick fastspin into checking my assembly driver code...
    It wasn't checking it before because Spin code started with "Stop" routine that didn't do anything.
    I had to compile the main Spin file for it to check for errors...

    But, I did this and now it checks everything:
    PUB Stop
        repeat
        start(pTiles, pColors)
    

    Even better than that is to make the first method a test harness for the rest of them. Then you can compile the object stand-alone to test it, or if it's used as an object the compiler will just remove the unused test method.
  • Maybe this is more of a loader question... But, anyway...

    With P1, you can modify your code in eeprom very easily by just writing to the location where variable data is stored...
    Can we do this with the flash on P2?

    Is there a way to figure out where the code is actually stored in flash?
  • Flash loader source has it all. You'll find Brian's modified source in the loadp2 "board" directory that Eric is now maintaining. https://github.com/totalspectrum/loadp2/tree/master/board

    Of course, Brian's EEPROM programming code uses different placement to Chip's new one.

  • cgraceycgracey Posts: 12,673
    edited 2020-02-10 - 22:26:41
    Rayman wrote: »
    Maybe this is more of a loader question... But, anyway...

    With P1, you can modify your code in eeprom very easily by just writing to the location where variable data is stored...
    Can we do this with the flash on P2?

    Is there a way to figure out where the code is actually stored in flash?

    For PNut.exe, you can compile flash_loader.spin2 and get this in the list (via Ctrl-L):

    TYPE: 49 VALUE: 024001C8 NAME: APP_START

    The $024 is the long-index offset to the start of user code. So, you should be able to do "@dat_asset + $024 << 2" to get the address in flash of where the data of interest is. Remember, though, that is a flash, and not an EEPROM, so you would have to erase the pertinent block and rewrite it with changed data. That's not practical, so it would be better to wait for (or develop) a file system that uses the upper part (past the first 1MB, perhaps) of the 16MB flash for general file use. Then, you could do whatever you want. Gosh, this needs to exist. If we just develop the object to handle it, the upper 15MB of the flash can become a persistent file system that survives flash reprogramming of the application code.
  • I already have P1 code for this type of flash. I guess just reserving the lower 1 MB is the way to go...
  • RaymanRayman Posts: 10,484
    edited 2020-02-11 - 17:23:11
    Does Fastspin now use same operators as Spin2?

    Seems the fastspin I have now (4.0.5) still uses things like "=>" instead of ">="...

    Edit: ENCOD is another one...
  • Rayman wrote: »
    Does Fastspin now use same operators as Spin2?

    Seems the fastspin I have now (4.0.5) still uses things like "=>" instead of ">="...

    Not yet. Spin2 just got released, so fastspin still has some catching up to do.
  • ersmith,
    I am a dummy, trying to get flexgui up and running in the latest linux mint 19.3. can you offer an assist?
    Jim
  • RS_Jim wrote: »
    ersmith,
    I am a dummy, trying to get flexgui up and running in the latest linux mint 19.3. can you offer an assist?
    Jim

    Probably easiest to do this by building from source. You'll need git, the build-essentials package, bison, tcl, and tk to be installed (at least). To build do:
    git clone --recursive https://github.com/totalspectrum/flexgui.git
    cd flexgui
    make install
    
    You may get some warnings about pandoc and/or latex being missing; those will affect the documentation build (it'll prevent the doc/*.md files from being converted to .html and .pdf) but won't otherwise affect the functionality. Install pandoc and pdflatex if you want the docs converted (the .md files are plain text, so conversion isn't strictly necessary).

    The procedure above will install flexgui to $HOME/flexgui; to run it do:
    cd ~/flexgui
    ./flexgui.tcl
    

    I think probably using the flexgui.zip Windows binary and running under wine will work too, but I haven't tried that.
  • RaymanRayman Posts: 10,484
    edited 2020-02-12 - 14:19:03
    This is odd...
    When switching back from Spin2 to Fastspin, this section gives an error:
      repeat 1
        asm'org'asm
          testp eventa wc
          if_c rdpin event, eventa
          if_nc mov event, #NO_EVENT
        endasm'end'endasm
    

    It looks like the comments after "asm" mess it up.
    When I remove the comments, it works...

    Wait, I may be wrong about that...

    Hmm... Seems that even a space character after ASM, makes it not work...
  • Rayman wrote: »
    This is odd...
    When switching back from Spin2 to Fastspin, this section gives an error:
      repeat 1
        asm'org'asm
          testp eventa wc
          if_c rdpin event, eventa
          if_nc mov event, #NO_EVENT
        endasm'end'endasm
    

    It looks like the comments after "asm" mess it up.
    When I remove the comments, it works...

    Wait, I may be wrong about that...

    Hmm... Seems that even a space character after ASM, makes it not work...

    Yes, unfortunately there's a bug that causes anything after an ASM to mess things up. That'll be fixed in the next release (and is fixed in github) but for now the ASM has to be alone on a line.
  • Has anybody already reported this issue? fastspin doesn't report any missing symbols (or any syntax errors at all?) in a PUB or PRI function if that function is not called in the current file. So if I write an object that is to be used as library for other objects and press "compile" to check if I've made any typos then nothing is checked at all because nothing except the first (main) function is called.

    I know, this is not really a bug. When I compile the main object that calls the library functions every error is found. It's just a bit surprising. I think syntax should be checked even for functions that are currently unused and are optimized away (dead code).
  • ManAtWork wrote: »
    Has anybody already reported this issue? fastspin doesn't report any missing symbols (or any syntax errors at all?) in a PUB or PRI function if that function is not called in the current file. So if I write an object that is to be used as library for other objects and press "compile" to check if I've made any typos then nothing is checked at all because nothing except the first (main) function is called.

    I know, this is not really a bug. When I compile the main object that calls the library functions every error is found. It's just a bit surprising. I think syntax should be checked even for functions that are currently unused and are optimized away (dead code).

    If you don't want the compiler to optimize away unused functions, then turn off optimization (at least for fastspin 4.1.3 and later).

  • ersmith wrote: »
    ManAtWork wrote: »
    Has anybody already reported this issue? fastspin doesn't report any missing symbols (or any syntax errors at all?) in a PUB or PRI function if that function is not called in the current file. So if I write an object that is to be used as library for other objects and press "compile" to check if I've made any typos then nothing is checked at all because nothing except the first (main) function is called.

    I know, this is not really a bug. When I compile the main object that calls the library functions every error is found. It's just a bit surprising. I think syntax should be checked even for functions that are currently unused and are optimized away (dead code).

    If you don't want the compiler to optimize away unused functions, then turn off optimization (at least for fastspin 4.1.3 and later).
    I agree that the compiler ought to parse all of the source code even if it eventually decides not to include code in the final executable. Is there a reason not to do this?

  • David Betz wrote: »
    ersmith wrote: »
    ManAtWork wrote: »
    Has anybody already reported this issue? fastspin doesn't report any missing symbols (or any syntax errors at all?) in a PUB or PRI function if that function is not called in the current file. So if I write an object that is to be used as library for other objects and press "compile" to check if I've made any typos then nothing is checked at all because nothing except the first (main) function is called.

    I know, this is not really a bug. When I compile the main object that calls the library functions every error is found. It's just a bit surprising. I think syntax should be checked even for functions that are currently unused and are optimized away (dead code).

    If you don't want the compiler to optimize away unused functions, then turn off optimization (at least for fastspin 4.1.3 and later).
    I agree that the compiler ought to parse all of the source code even if it eventually decides not to include code in the final executable. Is there a reason not to do this?

    It does parse all of the source code and creates an abstract syntax tree for all methods, so syntax errors are definitely caught. However, some other errors (e.g. undefined symbols, in many cases) are not detected until the compilation phase, and the compiler never even tries to compile unused methods. To be more explicit, "x := 1" is (usually) valid syntax in a Spin method, but if "x" isn't defined then it may not produce an error if the code is never compiled.

    Changing this behavior is possible, obviously, but it's work. I'd be happy to accept pull requests (or payment) to do it. In the meantime, either use -O0 or else actually use the methods that you want to test.
Sign In or Register to comment.