Shop OBEX P1 Docs P2 Docs Learn Events
Catalina 2.7 - now available on SourceForge — Parallax Forums

Catalina 2.7 - now available on SourceForge

RossHRossH Posts: 5,593
edited 2010-11-26 17:19 in Propeller 1
All,

I have uploaded Catalina patch release 2.7 to the Catalina SourceForge site (http://sourceforge.net/projects/catalina-c).

Patch release 2.7 was a minor bug fix release for Catalina 2.6. It added no new functionality - all the new functionality I have been working on (multi-threading support, new libraries, new 2-phase loader) will be included in the forthcoming release 2.8.

The most significant fixes in release 2.7 are to the underlying C compiler (lcc) - including one bug that meant programs that used complex macros could crash the preprocessor (cpp).

Note that if you have purchased a license for the Catalina Optimizer you will already have received release 2.7 - I was holding back from releasing it more generally as I originally hoped I would get the chance to release some of the new functionality at the same time as a more general release of 2.7 - but the new functionality has turned out to be bigger than Ben Hur, and may take me a few weeks more yet.

Ross.

P.S. According to SourceForge, Catalina 2.6 now has over 800 downloads! I can't help but wonder who all these people that download it actually are - I don't see evidence of that many C users here in the Parallax forums.

P.P.S. For some reason SourceForge no longer shows the comments from people who have either donated to Catalina or purchased the Catalina Optimizer - in fact it now thinks no-one has donated at all. I don't have much experience with SourceForge, so I'm not sure whether I should be worried about this or not - do these "donation" records get reset periodically?

Comments

  • jorozcojorozco Posts: 14
    edited 2010-11-19 09:17
    First of all congratulations Ross on a job well done with your Catalina C compiler.

    Now to my point, I was wandering if the implementation of _outa (and _outb) are correct. Of course I may be misinterpreting the intended operation of this functions.

    I am assuming that the intended operation of this function is to write to OUTA only the bits of the desired output that are masked by ones in the mask.

    From the Catalina source code:
    C__outa
     mov r0, OUTA
     andn OUTA, r3
     or OUTA, r2
     jmp #RETN
    

    As I understand r3 is the mask and r2 the desired output.

    I see two problems here:
    First it is writing two times to OUTA. It should first calculate the desired value and then write only once to OUTA at the end of the function.
    The second problem is that we are able to write to OUTA values that are not masked, in the instruction "or OUTA,r2".

    May I suggest the next implementation (Note: The original suggestion did not work, thankyou kuroneko for pointing this out and for sharing the correct solution):
    ' Optimal solution proposed by kuroneko and adapted by jorozco:
    C__outa
      mov r0, OUTA
      and r2, r3
      and r3, OUTA
      xor r2, r3
      xor OUTA, r2
      jmp #RETN
    
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2010-11-19 15:01
    multi-threading support, new libraries, new 2-phase loader) will be included in the forthcoming release 2.8.

    Woot!
  • kuronekokuroneko Posts: 3,623
    edited 2010-11-19 15:25
    jorozco wrote: »
    May I suggest the next implementation:
    C__outa
     mov r0, OUTA
     and r2, r3
     or OUTA, r2
     jmp #RETN
    

    May I suggest you review your suggestion again?
  • jorozcojorozco Posts: 14
    edited 2010-11-19 15:44
    I added a Synth.c demo on parallax OBEX. It uses by default a DEMO board and when executed flashes leds 16 and 17 at 10 and 2 Hz respectively as an example of how to use the A and B counters of a Cog:

    http://obex.parallax.com/objects/688/

    Ross:

    This object needs and includes the LMM PASM functions:
    _ctra, _ctrb, _frqa, _frqb, _phsa and _phsb

    Do you think these could be included in Catalina? You can copy paste them if you find them useful, they are just simple LMM PASM code to access and update this special Propeller registers.
  • jorozcojorozco Posts: 14
    edited 2010-11-19 15:56
    @kuroneko:

    You are right, I did not think this trough. The zeros of the desired value do not get set in my suggestion just the ones.

    Back to the drawing board ...

    Kuroneko do you at least agree with me that the original code needs fixing?

    BTW Just in case I need it, is it OK to use an extra register? Is r4 safe?
  • jorozcojorozco Posts: 14
    edited 2010-11-19 16:46
    A binary logic table should make clear what I am trying to do for _outa(mask, value):
    Original OUTA 00001111
             Mask 00110011
            Value 01010101
                  ________
         New OutA 00011101
    

    Is this the expected operation of _outa(mask, value)?

    If indeed this is the desired operation, please see my original post (#2) for new proposed solutions.
  • kuronekokuroneko Posts: 3,623
    edited 2010-11-19 16:59
    jorozco wrote: »
    Kuroneko do you at least agree with me that the original code needs fixing?

    If there are bits being set outside of what the mask covers (i.e. !mask & value <> 0) then probably yes (see below). Otherwise it's OK and there would only be a minor issue as you temporarily clear a bit which might otherwise stay high.

    As you just pointed out, if the API is _outa(mask, value) (both user-defined) then the question is whether setting bits outside of mask is supposed to have undesired side effects. It may not have been intended as a safe API.
  • jorozcojorozco Posts: 14
    edited 2010-11-19 17:35
    I don't like how my proposed solution to a safe _outa(mask, value) looks in my post (#2) because it is long and therefore slower than the original.

    A shorter solution can be achieved if we had _set_outa(mask), _clr_outa(mask)

    @kuroneko: I agree that if _outa(mask, value) was not intended to be a safe API then it works OK as long as !mask & value == 0 holds. I started all this because this bit me on a program I was building, and it took me a while to figure out what the problem was. I suppose we could then have a safe _outa_safe(mask, value) and a simplified (and fast) _outa(mask, value) and it would be very helpful for the user if this is clearly documented, _set_outa(mask), _clr_outa(mask) as noted above may come in handy too (and they will be safe). By the way IMHO the unsafe _outa(mask, value) may produce bugs that are difficult to trace.

    I almost forgot, there is also the double write to OUTA problem on the current implementation. This is specially problematic since it goes to 0 and then to 1 when the original bit was 1, the new desired value for this bit is 1 and the mask is also 1, if the IO gets written between this two operations (1/16th chance if I recall well), a pulse will appear in the output. This would be problematic when driving a counter for example or a serial device. I think I avoided this in my corrected version1 suggestion, even though it has also a double write to OUTA, at least I think I did but I have not look at it carefully enough for all cases.
  • kuronekokuroneko Posts: 3,623
    edited 2010-11-19 17:43
    jorozco wrote: »
    I don't like how my proposed solution to a safe _outa(mask, value) looks in my post (#2).

    Careful with neg (dst = -src <> !src) and what is nand supposed to be?

    What about:
    ' mask  = 00[COLOR="Red"]1111[/COLOR]00
    ' value = 11[COLOR="Red"]0110[/COLOR]11
    ' outa  = [COLOR="Blue"]01[/COLOR]0011[COLOR="Blue"]01[/COLOR]
    
    and value, mask        ' value = 00011000
    and mask, outa         ' mask  = 00001100
    xor value, mask        ' value = 00010100
    xor outa, value        ' outa  = [COLOR="Blue"]01[/COLOR][COLOR="Red"]0110[/COLOR][COLOR="Blue"]01[/COLOR]
    
  • jorozcojorozco Posts: 14
    edited 2010-11-19 18:00
    I will be leaving town tomorrow for about a week, so I think I will not be able to follow the thread. But I will check it out on my return for sure, or if I find an inexpensive WIFI in my trip.

    Sorry to stir things up and then leave!
  • jorozcojorozco Posts: 14
    edited 2010-11-19 18:16
    kuroneko wrote: »
    Careful with neg (dst = -src <> !src) and what is nand supposed to be?

    OK, noted. I tried to correct my code in post #2 but I am not sure I used bit negation ! correctly.
    kuroneko wrote: »
    What about:
    ' mask  = 00[COLOR="Red"]1111[/COLOR]00
    ' value = 11[COLOR="Red"]0110[/COLOR]11
    ' outa  = [COLOR="Blue"]01[/COLOR]0011[COLOR="Blue"]01[/COLOR]
    
    and value, mask        ' value = 00011000
    and mask, outa         ' mask  = 00001100
    xor value, mask        ' value = 00010100
    xor outa, value        ' outa  = [COLOR="Blue"]01[/COLOR][COLOR="Red"]0110[/COLOR][COLOR="Blue"]01[/COLOR]
    

    I have no time to check this, I really need to go packing. My flight leaves very early tomorrow. But I hope it is correct since we would be back to 4 instructions (instead of 3 from the original) in my opinion this would be a good tradeoff for a safe _outa(mask,value) function. (Correction, this solution has 5 PASM instructions counting the missing "mov r0, OUTA" that goes on the top, still not bad for what it does).
  • Heater.Heater. Posts: 21,230
    edited 2010-11-19 18:53
    kuroneko,

    That works, in my brain so far at least.

    Zog has yet to flash his first LED so do you mind if Zog borrows that snippet?
  • kuronekokuroneko Posts: 3,623
    edited 2010-11-19 18:56
    Heater. wrote: »
    Zog has yet to flash his first LED so do you mind if Zog borrows that snippet?
    Be my guest ;)
  • jorozcojorozco Posts: 14
    edited 2010-11-19 20:28
    kuroneko wrote: »
    What about:
    ' mask  = 00[COLOR="Red"]1111[/COLOR]00
    ' value = 11[COLOR="Red"]0110[/COLOR]11
    ' outa  = [COLOR="Blue"]01[/COLOR]0011[COLOR="Blue"]01[/COLOR]
    
    and value, mask        ' value = 00011000
    and mask, outa         ' mask  = 00001100
    xor value, mask        ' value = 00010100
    xor outa, value        ' outa  = [COLOR="Blue"]01[/COLOR][COLOR="Red"]0110[/COLOR][COLOR="Blue"]01[/COLOR]
    

    OK, finished packing and could not stand reviewing the code. Your proof is incomplete but the code is fortunately correct. You repeated 2 times the 010 and 011 and omitted 000 and 001 combinations of mask, value and outa.

    The proof should have been for it to be complete:
    ' mask  = 00[COLOR="Red"]1111[/COLOR]00
    ' value = 00[COLOR="Red"]0110[/COLOR]11
    ' outa  = [COLOR="Blue"]01[/COLOR]0011[COLOR="Blue"]01[/COLOR]
    
    and value, mask        ' value = 00011000
    and mask, outa         ' mask  = 00001100
    xor value, mask        ' value = 00010100
    xor outa, value        ' outa  = [COLOR="Blue"]01[/COLOR][COLOR="Red"]0110[/COLOR][COLOR="Blue"]01[/COLOR]
    

    In any case the code did work with the completed table.

    Darn it! I really wanted to contribute code. I knew there should be an xor in the solution, I also knew my corrected solution was not optimal and that is why I never like it. Well done kuroneko. I guess this is what open source is all about.
  • jorozcojorozco Posts: 14
    edited 2010-11-19 21:02
    I still think that _set_outa(mask) and _clr_outa(mask) should be implemented, see my explanation below the suggested code:
    ' _set_outa(mask)
    ' r2 = mask
    C__set_outa
      or OUTA, r2
      jmp #RETN
    
    ' _clr_outa(mask)
    ' r2 = mask
    C__clr_outa
      and OUTA, !r2  'Is this valid, or how do I make bitwise NOT on a register.
      jmp #RETN
    

    Of course we could add "mov r0, OUTA" on the first line of each function and get the current OUTA value as a return value for the function but we will be wasting another PASM instruction and IMHO a very important quality of this instructions is speed. We could also have 2 versions one with that returns OUTA and another one (fast) that does not return OUTA.

    I hope this time I got it right.
    The merit of this functions is that they are a single PASM instruction against 5 for the safe _outa(mask, value) or 3 for the current unsafe implementation. In some algorithms this can make a big difference. OK I admit it, as I said before, I also want to contribute some code ;)

    Now seriously, fast and reliable flipping of IO pins is very important for microcontrollers in general and for the propeller in particular so attention should be given to optimize it.
  • RossHRossH Posts: 5,593
    edited 2010-11-19 21:24
    jorozco wrote: »
    I still think that _set_outa(mask) and _clr_outa(mask) should be implemented, see my explanation below the suggested code:
    ' _set_outa(mask)
    ' r2 = mask
    C__set_outa
      or OUTA, r2
      jmp #RETN
    
    ' _clr_outa(mask)
    ' r2 = mask
    C__clr_outa
      and OUTA, !r2  'Is this valid, or how do I make bitwise NOT on a register.
      jmp #RETN
    
    Of course we could add "mov r0, OUTA" on the first line of each function and get the current OUTA value as a return value for the function but we will be wasting another PASM instruction and IMHO a very important quality of this instructions is speed. We could also have 2 versions one with that returns OUTA and another one (fast) that does not return OUTA.

    I hope this time I got it right.
    The merit of this functions is that they are a single PASM instruction against 4 for the safe _outa(mask, value) or 3 for the current unsafe implementation. In some algorithms this can make a big difference. OK I admit it, as I said before, I also want to contribute some code ;)

    Hi jorozco,

    I'll have a look at your implementation, and consider adding your new functions to the standard Catalina library. The current set of routines were primarily intended to suit my own needs, and may not suit yours.

    Also, you are free to either modify the standard library to suit your needs, or (perhaps a better choice) create a new user library of your own low-level LMM PASM functions, and then share this library - either here or in the OBEX.

    Instructions on creating your own libraries are included in the "Getting Started with Catalina" tutorial. This tutorial talks through the simple steps required to create a user library and include some C functions, but incluidng LMM PASM functions is just as easily.

    Just be aware that if you intend to use the Catalina Optimizer, then there are some rules that hand-crafted LMM PASM functions must follow in order to be optimized correctly. These are described in the Catalina Optimizer Reference Manual.

    Note that there is one additonal rule not described in the Catalina documentation, which is:
    • All functions must have only ONE return instruction (RETN or RETF), which must be the last instruction in the function. If you need to exit the function at another point, jump instead to a label on the single return instruction.
    Ross.
  • jorozcojorozco Posts: 14
    edited 2010-11-26 17:19
    RossH wrote: »
    Hi jorozco,

    I'll have a look at your implementation, and consider adding your new functions to the standard Catalina library. The current set of routines were primarily intended to suit my own needs, and may not suit yours.

    I agree Ross. My needs are basically to have a fast reliable and standard C compiler for the propeller and Catalina is doing this job quite well in my opinion, and it seems to be getting better all the time. About the non-standard libraries I personally don't care too much where are they placed and how are they named as long as they are available.

    I also agree with you that most of the time requested functionality should be done as custom libraries by whoever needs them.

    By the way the Synth.c demo that I uploaded to the OBEX (
    http://obex.parallax.com/objects/688/) as you may have seen works and compiles OK using your current version of Catalina so there is no urgent need on my part that you include this functions in Catalina. On the other hand if I am not mistaken this are the only missing Propeller IO functions in Catalina that are included on PASM and Spin.

    Thanyou also on the pointers and tips to build custom libraries and to write faster code.

    jorozco
Sign In or Register to comment.