Shop OBEX P1 Docs P2 Docs Learn Events
FlexProp: a complete programming system for P2 (and P1) - Page 45 — Parallax Forums

FlexProp: a complete programming system for P2 (and P1)



  • You're obviously right. Sorry, I'll delete the post. :tired_face:

  • @deets said:
    I got myself used to working with an additional FTDI chip (e.g. the venerable proplug) when working with the Px. The biggest reason for me: I don't need to juggle flashing vs monitoring by terminating by screen command (which I'm usually using). That works nicely with all the handrolled stuff so far, but I want to leverage the stdio-library of flexspin/prop. However there the output pins are hard-wired. I'd be interested in making that more flexible, and would even put in the effort myself and create pull request. But of course only if this stands a chance of acceptance into the upstream.

    The idea would be to follow debug_baud and build a system that allows the exact same customisation. One critical point would be that I think I need a breaking change from _setbaud(baud) to something like _setserial(baud, tx, rx). Otherwise one could be in a weird state of not having defined one or the other. And that added complexity isn't worth it IMHO.

    How would you feel about that, Eric?

    I think what we really need is a way to fopen() serial devices. In principle this isn't hard, it's just the details that are awkward. Do we provide something like mount() for installing new devices (so something like adddevice("/dev/serial", serial_device()); f = fopen("/dev/serial", "w");) or do we add a new call like f = fopen_device(serial_device(), "w")? I go back and forth on this.

  • A new device by itself is absolutely useful. I'd still like to have a way to redirect default communication.

    Regarding your proposal - I do like the idea of standardised, posix-style APIs. But wonder how it interacts with possible multi core usage. I'f I'm not mistaken, there's quite a bit of locking going on in the io code. Understandably so when we want the abstraction to be robust. But there needs to be a way of spawning the usual suspects - UART, I2C, SPI - without these locks.

    If I take your example, I'd like to see something like

    adddevice("/dev/serial", serial_device());
    f = fopen("/dev/raw/serial", "wr"); // here be dragons, no critical sections!
  • pik33pik33 Posts: 2,350

    I don't know details of FlexC but in FlexBasic I simply reopen channels #0 and #1 with a send-receive device (in my case, a serial interfaced keyboard and a HDMI driver) and it works, printing on the HDMI screen and receiving data from the keyboard, so maybe something similar can be also done in FlexC.

  • I'm trying to use rogloh's hyperRAM drive in flexc following's instructions:

      //ext_memory_t ram; // This was my typedef, used the struct __using to avoid that being the cause
      struct __using("memory.spin2") ram;
      int error = ram.initHyperDriver(32, EXT_RAM_BASE, -1, 0, 0, -1);
      assert(error >= 0);
      char buffer[1024];
      memset(buffer, 0xaa, 1024);
      ram.write(buffer, EXT_RAM_BASE, 1024);
      memset(buffer, 0xff, 1024);, EXT_RAM_BASE, 1024);
      for(size_t i=0; i < 1024; ++i)
        assert(buffer[i] == 0xaa);
      printf("test done\r\n");

    My assert fails, it appears the data is either not written or read back. Now I'm early in this, so user-error is absolutely an option. The thing that I'm noticing though is a warning

    /Users/deets/Library/CloudStorage/Dropbox/projects/p2-fileio-test/src/iotest.c:120: warning: variable ram may be used before it is set in function test

    Is this a cause for concern? How do I avoid it? I prefer my code warn-free if possible.

  • You should not allocate ram driver on the stack, that just calls for problems. Make it a global a variable.

  • It does? I'm usually quite happy allocating things on the stack (being obviously aware that it needs to be kept alive). So in general C/C++ etc semantics, that would just be fine. But do you say this is not a good idea in flexspin?

    I just tried it. It does remove the warning. It doesn't make my code work :(

  • ersmithersmith Posts: 5,910
    edited 2023-04-23 19:39

    Allocating spin objects on the stack is a little dangerous because they expect their member variables to be initialized to 0, and stack allocation doesn't do that. If you add an explicit memset() it should be OK though.

    As for why your code is failing, is it possible there's a typo somewhere? Does it work when you use the exact same parameters in Spin2?

    ETA: @Wuerfel_21 uses @rogloh 's drivers in some of her programs, like Megayume, so I don't think there's any fundamental incompatibility between them and flexspin.

  • @ersmith said:
    Allocating spin objects on the stack is a little dangerous because they expect their member variables to be initialized to 0, and stack allocation doesn't do that. If you add an explicit memset() it should be OK though.

    Also because if you start a PASM driver and then de-allocate the related object, the cog will keep reading/writing unrelated stack cells. I think just using empty-braces initialization should also work (and be less obnoxious than a memset)? Anyways, just don't.

    Other than that, yea, double check the parameters and that your RAM board works correctly.

  • I’ve had it working with pure spin, and the previous release. I’ll try and see if that’s still working so I can rule out hardware issues.

  • Found an optimizer bug:

    #include <stdio.h>
    #include <stdlib.h>
    #include <propeller.h>
    #include <stdbool.h>
    #include <memory.h>
    int check(int);
    #define WTX 20
    #define WRX 21
    int led;
    int main(int argc, char** argv)
        int i;
       int z;
        z = 0;
        for (i=0;i<25;i++)
            if (check(z++) != 0)
        printf("Value: %d\n", i);
        while (1)
    int check(int c)
        if ((c & 0x08) != 0)
            return -1;
        return 0;

    I returns the wrong answer.
    It seems the code switches to a DJNZ function if I is not used in the loop which is wrong since I is used outside of the loop.


  • @iseries : Thanks for the bug report, Mike. Loop variables should be fixed in the github source code now. I hope to make a binary release soon.

  • RaymanRayman Posts: 13,860

    @ersmith Looking to update an ancient mixed signal scope code... Got the Spin2 version going. But, this C version gives a strange error, "error: Internal Error: emitting move to immediate"
    This is at the end of the video driver where there is an enumerated list of colors.
    It spans several lines, was doing this with brackets, but tried using "..." instead but still gives error.
    Main file is 2BT_Demo1.c

  • @Rayman : There was a bug in calculating the line number for some errors (and the errors themselves weren't as clear as they could be). I've fixed that and now the error reads:

    1080p_TileDriver_8c.spin2:457: error: assignment to constant value
    1080p_TileDriver_8c.spin2:475: error: assignment to constant value

    I think the offending lines both have expressions like value <-=4. Did you mean to write value <<=4 on those lines?

  • RaymanRayman Posts: 13,860

    @ersmith Thanks! that fixed it...

  • I've released a new binary package for FlexProp 6.1.2. The changes in this version are:

    - Added files included by FILE directive to .zip files
    - Fixed an optimizer bug around the P1 PHSx registers
    - Fixed incorrect constant optimization of inline assembly (caught by Ada Gottensträter)
    - Fixed some missing optimizations when -l was enabled
    - Fixed incorrect assembly output for files not ending in newline when -l is on
    - Fixed final value of loop variables after loop is transformed to djnz
    - Fixed PTRx offsetting in C inline asm
    - Fixed bugs in ELSE conditional assembly parsing.
    - Implemented __builtin_expect (thanks, Ada!)
    - Several additional optimizations contributed by Ada
    - Skip symbol resolution when outputting .o files, fixes some output bugs
    - Made object constant override expressions be evaluated in the parent object
    - Minor optimization for expressions like 2*x

    If you are still using a 5.x version of FlexProp I strongly urge you to upgrade, 5.x has a lot of bugs that are fixed in the 6.1.x series. Even if you're on 6.1.1 it's worth upgrading to 6.1.2, some of these bugfixes are important for the USB work that @Wuerfel_21 and others are doing.

  • RaymanRayman Posts: 13,860

    @ersmith Sounds good. What's with the .o files? Does FlexProp now compile to objects that are later linked?

  • @Rayman said:
    @ersmith Sounds good. What's with the .o files? Does FlexProp now compile to objects that are later linked?

    Flexcc has had the ability to produce .o files for a while now. They're just pre-processed C files, not real object files, but they can serve the function of .o files in a lot of places. They exist to make porting existing projects a bit easier.

  • RaymanRayman Posts: 13,860
    edited 2023-05-09 18:52

    @ersmith That sounds interesting, but I don't understand the use case... Is this explained somewhere? What kind of porting are you talking about?

    Also, I guess with "real" .o files, you avoid conflicts with global scope names. Is that true here too?

  • @Rayman said:
    @ersmith That sounds interesting, but I don't understand the use case... Is this explained somewhere? What kind of porting are you talking about?

    I'm talking about porting C programs with Makefiles from other platforms (like Arduino or RPi) to Propeller. They often have rules to compile from .c to .o, and flexcc has the option to kind of do that, although all it really does behind the scenes is to run the preprocessor and save the output into a .o. The final "link" step performed by flexcc will then be a full compile. From flexcc's perspective it's not much different from putting the .c files on the command line directly, but it saves the programmer the work of re-writing the Makefile.

    Also, I guess with "real" .o files, you avoid conflicts with global scope names. Is that true here too?

    Name scope issues are the same whether or not you're compiling to .o -- variables that are declared "static" are local to the file, other variables are global. That's true for all C compilers: symbols in a traditional object file can be either local or global.

  • RaymanRayman Posts: 13,860

    @ersmith Thanks! Think I get it now. Didn't know about "static", or maybe I forgot. I'll have to keep that in mind.

    I guess I knew that static was a way to preserve the value of a variable in a function between calls and also have it be initialized to zero.
    Didn't know it would have file scope...

  • The C keywords all mean like three different things depending on context.

  • pik33pik33 Posts: 2,350
    edited 2023-05-10 17:20

    I am trying to use C code in Basic. While experimenting, I did this:

    dim err as any pointer
    let err=mp3.mp3init()

    This code is wrong because mp3.mp3init() returns int. I simply forgot to change the type in the Basic code after editing C file

    I got this as a result:

    D:/programowanie/p2-retromachine/Propeller/mp3/mp3.c:4757: error: incompatible types in assignment: expected pointer to any unknown type but got integer

    While the error description is OK, as I tried to assign integer to any pointer, the place of the error is reported wrong. The error didn't occured in mp3.c. It occured in the Basic program.

    Line 4757 is this:

    sbi = (SubbandInfo*)(mp3DecInfo->SubbandInfoPS);

    and this is the last line in the C code which does x=(something*)(y);

    If I comment it out, the compiler finds the previous C line in this format and tells the error is there. The error was shown where it was, in Basic, when I commented out all lines contains (something*) casting in C

    Of course after I changed the line

    dim err as any pointer

    to correct one

    dim err as integer

    the program compiles without any errors.

  • pik33pik33 Posts: 2,350
    edited 2023-05-10 21:13

    Now I have another problem. Of course, all of this code is an experiment (how to make a big C project one-file and how to call it from Basic)

    But the result of compilation is now this:
    No optimization: cannot fit in cache
    O1, Os, O2 - segfault

    And the error reports while it still tried to compile still point to C code while the error is in Basic. This time I used undeclared variable "left" in the Basic part. The compiler told the truth (unknown symbol) but pointed to a line in C code instead of Basic one.

    Edit: I noticed I used outdated include path. I deleted the config and restarted the flexprop. Now the command line is

    "C:/Users/Piotr/Downloads/flexprop-6.1.2/flexprop/bin/flexspin" -2 -l --tabs=8 -D_BAUD=230400 -O1    --charset=utf8 -I "C:/Users/Piotr/Downloads/flexprop-6.1.2/flexprop/include"  "D:/programowanie/p2-retromachine/Propeller/mp3/mp3.bas"

    Still segfault

    "C:/Users/Piotr/Downloads/flexprop-6.1.2/flexprop/bin/flexspin" -2  --tabs=8 -D_BAUD=2000000 -Os    --charset=utf8 -I "C:/Users/Piotr/Downloads/flexprop-5.9.9/flexprop/include"  "D:/programowanie/p2-retromachine/Propeller/mp3/mp3.bas" -DFF_USE_LFN
    Propeller Spin/PASM Compiler 'FlexSpin' (c) 2011-2023 Total Spectrum Software Inc. and contributors
    Version 6.1.2 Compiled on: May  7 2023
    child killed: segmentation violation
    Finished at Wed May 10 20:39:57 2023 50.6K
  • It looks like the compiler is running out of registers. That should produce an error message rather than a segfault, and actually on LInux it does produce an error message (but then segfaults). I've checked in a fix for the crash, but your program still won't compile, unfortunately. You might try compiling for bytecode; the Adafruit mp3 decoder did work with bytecode, and that back end won't run out of registers.

    Thanks for the bug report about the wrong line numbers in error messages, I'll look into those too.

  • pik33pik33 Posts: 2,350

    That's the mp3 decoder you provided in another thread, so it should compile (after removing all bugs I introduced merging these files)...

  • pik33pik33 Posts: 2,350
    edited 2023-05-11 08:47

    No segfault now :)

    To not import all the C decoder as a class I am now trying

    DECLARE FUNCTION mp3init LIB "mp3.c" () AS integer
    DECLARE FUNCTION mp3decode1 LIB "mp3.c" (rawdata as any pointer, left as integer pointer, outbuf as any pointer) AS integer

    It still fails on lack of registers.
    To encounter where the compilation fails, I commented out near all of the MP3Decode function body, so it compiles, runs, inits and returns from the shortened MP3Decode(). Now I will uncomment it partially to find what causes the fail.

    I encountered some other problems.

    (1) Basic variable can not be named "time". It seems the compiler confuses it with some other thing called "time" and produces strange errors:

    let time=getct()-time1

    C:/Users/Piotr/Downloads/flexprop-6.1.1/flexprop/include/time.h:48: error: Redefining time as a function or subroutine

    The worse thing occured when I forgot to use 'let' (and now 'time' is not declared)


    D:/Programowanie/P2-retromachine-1/Propeller/mp3/mp3a.p2asm:304: error: Destination operand too big for mov
    D:/Programowanie/P2-retromachine-1/Propeller/mp3/mp3a.p2asm:307: error: mismatch in hub PC: expected 0x924 got 0x920

    (2) There is a function called MP3Decode in the mp3 decoder C. As I wanted to access it from Basic code, I wrote a wrapper:

    int mp3decode(unsigned char **inbuf, int *bytesLeft, short *outbuf)
    { return MP3Decode(mp3decoder, inbuf, bytesLeft, outbuf, 0);}

    The result is:

    D:/Programowanie/P2-retromachine-1/Propeller/mp3/mp3.c:3789: error: redefining function or subroutine MP3Decode
    D:/Programowanie/P2-retromachine-1/Propeller/mp3/mp3.c:3653: note: the previous definition is here
    D:/Programowanie/P2-retromachine-1/Propeller/mp3/mp3.c:3789: warning: Redefining function or subroutine MP3Decode with an incompatible type

    The workaround is simple:int mp3decode1(unsigned char **inbuf, int *bytesLeft, short *outbuf) but I thought C is case sensitive.

  • pik33pik33 Posts: 2,350
    edited 2023-05-11 10:12

    Another problem. The code is as simple as possible now.

    There is mp3a.bas:

    DECLARE FUNCTION mp3init LIB "mp3b.c" () AS integer
    dim rawdata1(4096) as ubyte 
    dim q as integer
    mount "/sd", _vfs_open_sdcard()
    chdir "/sd"
    close #7: open "/sd/test.mp3/" for input as #7  
    get #7,$415,rawdata1(0),4096,q 
    close #7
    print q, hex$(rawdata1(0),2), hex$(rawdata1(1),2)  
    dim err as integer
    let err=mp3init()

    and mp3b.c:

    #include <stdio.h>
    int mp3init(void)
            int result=0;
            return result;

    If I comment out thelet err=mp3init() line this works OK, returning correct values 4096 FF FB - it got 4 kB from the MP3 file where I set the offset to point to the start of the frame (FF FB)

    But if the line is uncommented and the function is called, the result is -1 0 0

    Also, the result is OK if I call the mp3init() but remove #include <stdio.h> from a C file.

  • @pik33 : There was a bug in an earlier flexspin which caused registers in inline assembly to be confused. In fixing that bug it seems I made inline functions use a lot more registers, which caused the MP3 decoder to stop compiling. I've gone back and re-worked the inline register fix to reduce this problem, and it should be possible to compile the decoder (plain C version) now.

    It does seem that there are some issues with mixing C and BASIC; I'll look into those. It's possible your original plan (putting the C code in an object) might be the easiest way forward for now.

  • Oh, and I did fix another bug in inter-language usage so that it's now at least possible to include .bas and .c files in the same .fpide project file. So you can make a .fpide project file something like:


    so that might be another way to approach this.

Sign In or Register to comment.