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

1181921232429

Comments

  • I am using a slightly older version, so this might be fixed already, but

    case 1..9

    just does 1..8

    and CASE "A".."Z"

    does not work at all.

    Mike
    I am just another Code Monkey.
    A determined coder can write COBOL programs in any language. -- Author unknown.
    Press any key to continue, any other key to quit

    The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this post are to be interpreted as described in RFC 2119.
  • JRoarkJRoark Posts: 90
    edited 2019-09-10 - 20:20:04
    Another day, another opportunity to make some more compiler mischief for @ERSmith to noodle on!

    I'm working with a stock FLIP module, a Dell laptop running Win10, and Fastspin Version 3.9.29

    Access to the BASIC getcnt() function isn't being allowed by the compiler even though getcnt() appears in the docs as a supported feature (and is used in several examples).
    x = getcnt()   '<-- compiler doesn't like this
    
    The error thown is "error: Symbol getcnt is of a type not handled by PASM output yet". There is a second part of this bug too. The above warning message is issued without a line number.

    Edit #1
    A "phantom" variable named cnt is apparently already defined somewhere. In other words, there is no need to define it before you use it. This even occurs with OPTION EXPLICIT enabled. The variable seems to be global in scope, and references to this variable can be made anywhere (main body, functions, subs, etc). That being said, you can explicitly define it and the compiler seems fine with it. None of these DIMs cause any problem even though it seems "pre-defined as a phantom" somewhere else:
    dim cnt as integer  <-- no problem
    dim cnt as long     <-- no problem
    dim cnt as string   <-- no problem
    

    Edit #2
    This isn't a bug, but it was interesting so I'm posting it. If you are trying to toggle pins, there is a huge speed difference depending on the methodology. The PINTOGGLE() function is *really* slow compared to direct programmatic manipulation of the pin. Check this out:
    const pin = 17
    direction(pin) = output
    do
       pintoggle(pin)   '<--- 192.310 Khz
    loop
    
    The code above results in a toggle speed of 192.310 Khz on the scope. The code below results in a 5 Mhz toggle speed, ie, a 26x speed improvement.
    const pin = 17
    direction(pin) = output
    do
       output(pin) = not output(pin)   '<-- 5.000 Mhz
    loop
    

    Edit #3
    There seems to be some mischief happening with versioning. I thought I was using the most recent version of Fastspin (3.9.30), but the editor (Help -> About) says I'm actually using 3.9.29. When I downloaded this from ERSmith's Patreon page (https://www.patreon.com/totalspectrum) a couple of days ago, the download link said "3.9.30" with a release date of Sept 6, but it seems like it is the 3.9.29 code. To eliminate any DFO error, I just went to Github and downloaded it from there, but the editor (Help -> About) still shows it as version 3.9.29.
    UPDATE: The compiler reports its version as 3.9.30, but the editor (Help -> About) reports 3.9.29. Looks like the (Help -> About) text just needs to be changed.

    Edit #4
    String handling definitely has some monkey-business happening. In addition to the failure mode that @Whicker posted on the previous page, this code below fails after the 6th iteration of the loop:
    for a = 1 to 10
       print "This is line " + str$(a)
       pausems(500)
    next a
    
    Here is the output on the serial terminal:
    [ Entering terminal mode. Type ESC or Control-C to exit. ]
    This is line 1
    This is line 2
    This is line 3
    This is line 4
    This is line 5
    This is line 6
     !!! out of memory !!!  !!! out of memory !!!
     !!! out of memory !!!  !!! out of memory !!!  !!! out of memory !!!  !!! out of memory !!!
    
    The failure happens at the same point regardless of the value of the HEAPSIZE constant. BTW: I put the 500 mS delay in there because I wondered if this was a garbage collection timing issue. No such luck. The timing seems to have nothing to do with the "out of memory" error.

  • yetiyeti Posts: 584
    edited 2019-09-10 - 17:18:54
    ◁ propeller-wiki ▷ ◁ FastSpin ▷ ◁ Help Spin at RosettaCode.org ▷ ◁ No Source – No Go! ▷ ◁ DK-E ▷ ◁ :-D ▷ ◁ Stay OmmmmmmPtimistic! ▷ ◁ Why Asimov's Laws of Robotics Don't Work ▷ ◁ DNA is a four letter word. ▷ ◁ Stop slavery! Free all mitochondria! ▷
  • whicker wrote: »
    okay, so I tried the HEAPSIZE suggestion:
    const HEAPSIZE = 8192
    dim R$ as string
    dim A as integer
    
    print "Hi"
    
    HERE:
    INPUT "Enter a string"; R$
    PRINT "You typed:"; R$
    GOTO HERE
    


    That's 240 A's. It only takes 2 of these to cause the weirdness (printing only the 1st character).
    At the bottom, it's only printing "Y" instead of "You typed:", and only "A" instead of the 240 A's, and then "E" instead of "Enter a string".

    Hmmm, I'm not seeing that. I can force an "!!! out of memory !!!" message if I type enough characters, but I don't see the printing of just the first character of the prompts. Do you get "!!! out of memory !!!" after a while? If not, then probably you have an older version of fastspin -- versions before 3.9.30 have some very nasty memory management bugs which could definitely produce weird errors like this.

    Thanks for testing this!
    Eric
  • JRoark wrote: »
    One other thing, and I think it was previously reported and you fixed it, but it seems to be back: in an IF THEN ELSE construct, if all you have is a comment between the IF and ELSE, the compiler it throws an error. I’ll post sample code and the actual error when I get home tonight.
    Actually it used to be the other way around, I think -- it would sometimes lose track of the first statement after the IF THEN. But trying to fix that I seem to have introduced another bug :(. Ugh. Anyway, thanks for the bug report, I'll look into it.


    EDIT #4:
    There is an odd bug in the "Commodore C64 Compatibility Feature". :smile: (ducking!)
    dim a$ as string   '<-- works fine
    dim b% as integer  '<-- works fine
    dim c! as single   '<-- throws "error: syntax error, unexpected !, expecting $end or end of line or end or ':'"
    
    [/quote]

    The character for a float is "#" rather than "!"; "!" isn't recognized at all. Is that a QBasic thing? I could probably make it a synonym for "#".
  • ersmith wrote: »
    The character for a float is "#" rather than "!"; "!" isn't recognized at all. Is that a QBasic thing? I could probably make it a synonym for "#".
    IIRC "#" was double and "!" single...
    ◁ propeller-wiki ▷ ◁ FastSpin ▷ ◁ Help Spin at RosettaCode.org ▷ ◁ No Source – No Go! ▷ ◁ DK-E ▷ ◁ :-D ▷ ◁ Stay OmmmmmmPtimistic! ▷ ◁ Why Asimov's Laws of Robotics Don't Work ▷ ◁ DNA is a four letter word. ▷ ◁ Stop slavery! Free all mitochondria! ▷
  • msrobots wrote: »
    I am using a slightly older version, so this might be fixed already, but

    case 1..9

    just does 1..8

    and CASE "A".."Z"

    does not work at all.

    The CASE "A" TO "Z" issue was fixed a while back (you are referring to BASIC, aren't you?). There does seem to still be an off-by-one bug in the case ranges, though... thanks for reporting this!

  • JRoark wrote: »
    Access to the BASIC getcnt() function isn't being allowed by the compiler even though getcnt() appears in the docs as a supported feature (and is used in several examples).
    Yes, that accidentally got broken in the last release. It should be fixed in github now. In the meantime you can use _getcnt() instead.
    UPDATE: The compiler reports its version as 3.9.30, but the editor (Help -> About) reports 3.9.29. Looks like the (Help -> About) text just needs to be changed.
    Yes, this is exactly it. Conceptually spin2gui and fastspin could have independent version numbers, but I try to keep them in sync. I failed this time :(.
    Edit #4
    String handling definitely has some monkey-business happening. In addition to the failure mode that @Whicker posted on the previous page, this code below fails after the 6th iteration of the loop:
    for a = 1 to 10
       print "This is line " + str$(a)
       pausems(500)
    next a
    
    Here is the output on the serial terminal:
    [ Entering terminal mode. Type ESC or Control-C to exit. ]
    This is line 1
    This is line 2
    This is line 3
    This is line 4
    This is line 5
    This is line 6
     !!! out of memory !!!  !!! out of memory !!!
     !!! out of memory !!!  !!! out of memory !!!  !!! out of memory !!!  !!! out of memory !!!
    
    The failure happens at the same point regardless of the value of the HEAPSIZE constant. BTW: I put the 500 mS delay in there because I wondered if this was a garbage collection timing issue. No such luck. The timing seems to have nothing to do with the "out of memory" error.

    I can't reproduce this -- with the default HEAPSIZE I get out of memory after two iterations, with "const HEAPSIZE=8192" all 10 iterations work fine. Are you sure it was recompiled correctly with the HEAPSIZE change?

    Thanks for your bug reports and suggestions!

    Eric
  • @ersmith When you attempt to replicate these is the compiler set for Propeller 2 code output? (I’m goofing with a FLIP).
  • JRoark wrote: »
    @ersmith When you attempt to replicate these is the compiler set for Propeller 2 code output? (I’m goofing with a FLIP).

    No, I was building for Propeller 1.
  • Ok. We’re on the same page. :)
  • @JRoark: If you're feeling adventurous I've attached an updated GUI for spin2gui. To use it just replace the src/gui.tcl file in your spin2gui folder with this one. It's got a right click menu, adjustable command output window size, and improved font selector.
  • ersmith wrote: »
    @JRoark: If you're feeling adventurous I've attached an updated GUI for spin2gui. To use it just replace the src/gui.tcl file in your spin2gui folder with this one. It's got a right click menu, adjustable command output window size, and improved font selector.

    Sweet!!! I’ll tee this up just as soon as I can get rid of a couple of clients. Thanks!
  • JRoarkJRoark Posts: 90
    edited 2019-09-11 - 17:49:14
    @ersmith Boy... those editor changes make all the difference in the world. Very nice! And you wedged the compile date/time/machine id in the compiler output too.

    Was the bottom pane (compiler msg output) supposed to be adjustable vertically? If so, it seems stuck on my machine... or I’m being obtuse. I’ll put odds on the latter. Lol.

    BTW: ALL of the font dialogue box issues are now resolved.

    Good stuff!!!
  • JRoarkJRoark Posts: 90
    edited 2019-09-11 - 20:02:52
    Here I go again making mischief with the new & improved FastSpin. Same dev environment except for the new gui.tcl file that Eric posted on this thread a couple of post ago. The target language is BASIC.

    MID$
    This function is present and works just fine, but it isnt listed in the doc. (I found this out by accident when I went to write my own MID$ function and the compiler got grumpy at me).

    PRAGMA
    It appears that the preprocessor directive PRAGMA is supported, but it isn't listed in the doc.

    TRUE and FALSE
    It appears the predefined constants TRUE and FALSE are present, but they are not listed in the doc. You can use TRUE and FALSE in statements without defining them, but at the same time if you want to explicitly define TRUE and/or FALSE to any legal value, the compiler seems fine with that.
  • JRoark wrote: »
    Was the bottom pane (compiler msg output) supposed to be adjustable vertically? If so, it seems stuck on my machine... or I’m being obtuse. I’ll put odds on the latter. Lol.
    Just above the grey "Compiler Output" bar there's a slightly darker line. The cursor should change when you mouse over that (at least it does on my machine) and you can drag to resize.

  • JRoark wrote: »
    MID$
    This function is present and works just fine, but it isnt listed in the doc. (I found this out by accident when I went to write my own MID$ function and the compiler got grumpy at me).

    Whoops, missed that one. Thanks.
    PRAGMA
    It appears that the preprocessor directive PRAGMA is supported, but it isn't listed in the doc.
    PRAGMA doesn't do anything yet, it's just ignored.
    TRUE and FALSE
    It appears the predefined constants TRUE and FALSE are present, but they are not listed in the doc. You can use TRUE and FALSE in statements without defining them, but at the same time if you want to explicitly define TRUE and/or FALSE to any legal value, the compiler seems fine with that.

    Hmmm, yes, I forgot to document those. For many of the built in variables (like these and CNT) it's OK to redefine them if you want, since they're just ordinary variables. But it's probably not always a good idea -- it'll be confusing to the reader.
  • ersmith wrote: »
    JRoark wrote: »
    Was the bottom pane (compiler msg output) supposed to be adjustable vertically? If so, it seems stuck on my machine... or I’m being obtuse. I’ll put odds on the latter. Lol.
    Just above the grey "Compiler Output" bar there's a slightly darker line. The cursor should change when you mouse over that (at least it does on my machine) and you can drag to resize.

    Laptops with small, high resolution screens, when combined with tri-focals, truly are the "Instant Breakfast" of self-humiliation.

    It works flawlessly. :)

  • JRoarkJRoark Posts: 90
    edited 2019-09-11 - 23:01:16
    DIM
    The process of creating a variable with DIM and attempting to simultaneously cast it as a type and assigning a value seems to be a bit wonky. If you use DIM with the SHARED attribute, it works fine as shown in the first two lines. But if you don't want a SHARED variable, you're out of luck.
    dim shared as integer r(5) = { 1, 2, 3, 4, 5 }    '<-- works fine
    dim shared as integer r = 100                     '<-- works fine
    dim as integer r = 100                            '<-- "error: initialization is not supported for member variable r"
    dim as integer ptr r = __builtin_alloca(256)      '<-- "error: initialization is not supported for member variable r"
    
    That last line is a cut-and-copy from the manual, so I suspect this used to work and got bumped somewhere along the way.

    CONST
    Apparently declaring a CONST within a SUB or FUNCTION isn't supported.
    FUNCTION DoStuff(x as integer) as integer
       const outPin = 17    '<-- "error: syntax error, unexpected identifier `outPin'"
       return x
    END FUNCTION
    
    It would be really handy to be able to define a CONST from within a SUB or FUNCTION that has scope that is local to the SUB or FUNCTION in which it is defined.

    SUB and FUNCTION
    Apparently, creating a SUB or FUNCTION without any code in it isn't supported.
    FUNCTION DoStuff(x as integer) as integer
       ' I will put something here in the future.     '<-- "error: syntax error, unexpected end"
    END FUNCTION
    
    Allowing empty SUBs and FUNCTIONs would be handy. I tend to map-out my code by initially defining "stubs" for SUBs and FUNCTIONs, and then I go back and fill-in the blanks with code to flesh it out. This keeps the program structured and keeps me on task. I also recommend this approach to students.
  • yetiyeti Posts: 584
    edited 2019-09-11 - 22:56:45
    $ cat asdds.bas 
    dim shared as integer r = 100
    dim shared as integer ptr p = __builtin_alloca(256)
    
    sub notMainProgram
      dim as integer rr = 100
      dim as integer ptr pp = __builtin_alloca(256)
    end sub
    
    notMainProgram
    
    $ fastspin asdds.bas 
    Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
    Version 3.9.31-beta-362be4d7 Compiled on: Sep 11 2019
    asdds.bas
    asdds.pasm
    Done.
    Program size is 576 bytes
    

    Probably this still applies:
    —▷ https://forums.parallax.com/discussion/comment/1457711/#Comment_1457711
    ersmith wrote: »
    The reason is a little obscure: an ordinary "dim" declares a member variable, which will be different in each instance of a class (even the top level program is really embedded in a class). These cannot be initialized because they're not in a fixed place in memory and there are many copies. "shared" variables though *can* be initialized because there is only one copy.

    ◁ propeller-wiki ▷ ◁ FastSpin ▷ ◁ Help Spin at RosettaCode.org ▷ ◁ No Source – No Go! ▷ ◁ DK-E ▷ ◁ :-D ▷ ◁ Stay OmmmmmmPtimistic! ▷ ◁ Why Asimov's Laws of Robotics Don't Work ▷ ◁ DNA is a four letter word. ▷ ◁ Stop slavery! Free all mitochondria! ▷
  • @yeti Thanks! That makes more sense now. It's seems a little odd to me as I'm coming at this from MS BASICs, (VB6, PDS, QB, etc), but hey... live and learn! Thanks for catching that.
  • RaymanRayman Posts: 9,716
    edited 2019-09-11 - 23:28:43
    Trying to figure out how to convert a pure ASM spin2 file into a Spin2+ASM spin2 file...

    See attached for a simple VGA example program that works without any Spin, but doesn't work when a Spin method is added to start the ASM.
    What am I doing wrong?

    Oops... I swear the pure ASM version was working... But, now it's not...
    Prop Info and Apps: http://www.rayslogic.com/
  • RaymanRayman Posts: 9,716
    edited 2019-09-11 - 23:58:56
    Ok, I think I see it now... Appears the bitmap has to be located above some address...
    When I add in some dummy bytes, it works:
    dat 
    byte     0[2000]
    
    
    dat
    ' Bitmap
    

    The attached works with or without the Spin part
    Prop Info and Apps: http://www.rayslogic.com/
  • @Rayman: I think you're running into the problem we saw before, that the "x" and "y" variables (declared with "res 1") are uninitialized but the code expects them to start with 0 in them. That's a bug in the assembly code. If you change them both to "long 0" then I don't think you'll need to insert the dummy bytes.
  • Doesn’t that make res worthless?
    Doesn’t the booter clear ram?
    Prop Info and Apps: http://www.rayslogic.com/
  • Rayman wrote: »
    Doesn’t that make res worthless?
    Doesn’t the booter clear ram?

    res has always just reserved space for variables, it's never put an initial value in them. So if you do:
       org 0
       ...
    x  res 1
       long $deadbeef
    
    then x will start with $deadbeef in it. Similarly if you do
    x  res 1
       file "bitmap.bmp"
    
    then x will start with the first 4 bytes of the bitmap.bmp file in it.

    Clearing the boot RAM is irrelevant in both of the above situations, because the x is explicitly followed by real data that the booter cannot possibly clear.

    Basically one should only ever use "res" for variables where the initial value doesn't matter -- values that get calculated, read from outside, or are otherwise explicitly initialized by the program. In those cases it's quite useful, because it lets you declare COG space that doesn't require any HUB space.

    In the VGA program, unfortunately, the initial value of some of those "res" values does matter (if you look it's assumed to be 0). It was a harmless error in the original demo, since the res was followed by an orgh which inserted 0 padding so the values did end up 0, but if the data is moved around that may no longer be the case.
  • You, also, should never have any non-res data after the res entries, unless you know what you are doing (and comment the crap out of it, since it will look like a bug).

    This is the same as it's always been for P1... no different for P2.
  • Another way to fix the VGA problem is to look at the beginning of the PASM code, which looks like:
            rdfast  #0,##@BitmapFile-$400+$436'##$1000-$400     'load .bmp palette into lut
            rep @.end,#$100
            rflong  y
            shl y,#8
            wrlut   y,x
            add x,#1
    .end
    
    The variable x is being used as an index into the LUT, but it is never initialized. If you put a
            mov x, #0
    
    somewhere before there it will fix the problem.

    (As an aside, this code could use an alternative method of setq2 + rdlong to read the data directly into LUT without needing to do the rep loop at all. That would be both faster and smaller, and not require the use of x and y.)


  • ersmith wrote: »
    Rayman wrote: »
    Doesn’t that make res worthless?
    Doesn’t the booter clear ram?

    res has always just reserved space for variables, it's never put an initial value in them. So if you do:
       org 0
       ...
    x  res 1
       long $deadbeef
    
    then x will start with $deadbeef in it. Similarly if you do
    x  res 1
       file "bitmap.bmp"
    
    then x will start with the first 4 bytes of the bitmap.bmp file in it.

    Clearing the boot RAM is irrelevant in both of the above situations, because the x is explicitly followed by real data that the booter cannot possibly clear.

    Basically one should only ever use "res" for variables where the initial value doesn't matter -- values that get calculated, read from outside, or are otherwise explicitly initialized by the program. In those cases it's quite useful, because it lets you declare COG space that doesn't require any HUB space.

    In the VGA program, unfortunately, the initial value of some of those "res" values does matter (if you look it's assumed to be 0). It was a harmless error in the original demo, since the res was followed by an orgh which inserted 0 padding so the values did end up 0, but if the data is moved around that may no longer be the case.
    Huh? In what sense is res *reserving* space for x if $deadbeef ends up being stored at that location. Isn't that a bug?

  • No it's the way it works.
    You are supposed to put your RES stuff last normally, but you could also use RES lines to "define" a header, then specify a file after them, and use the res labels to access the beginning of the file data.
    Regular DAT data takes up space in HUB as well as in COG, but RES doesn't consume HUB space, so it's handy for setting up buffers and temp vars and whatnot for use only in COG memory, but you need to make sure it's initialized properly yourself.
    Also Spin code can access the regular DAT data in HUB space, which is handy for setting things before starting the COG.

    This is how it has worked on P1 forever.
Sign In or Register to comment.