PDA

View Full Version : Catalina 2.7 - now available on SourceForge



RossH
11-02-2010, 11:56 PM
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?

jorozco
11-19-2010, 05:17 PM
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_Acula
11-19-2010, 11:01 PM
multi-threading support, new libraries, new 2-phase loader) will be included in the forthcoming release 2.8.

Woot!

kuroneko
11-19-2010, 11:25 PM
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?

jorozco
11-19-2010, 11:44 PM
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.

jorozco
11-19-2010, 11:56 PM
@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?

jorozco
11-20-2010, 12:46 AM
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.

kuroneko
11-20-2010, 12:59 AM
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.

jorozco
11-20-2010, 01:35 AM
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.

kuroneko
11-20-2010, 01:43 AM
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 = 00111100
' value = 11011011
' outa = 01001101

and value, mask ' value = 00011000
and mask, outa ' mask = 00001100
xor value, mask ' value = 00010100
xor outa, value ' outa = 01011001

jorozco
11-20-2010, 02:00 AM
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!

jorozco
11-20-2010, 02:16 AM
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.



What about:

' mask = 00111100
' value = 11011011
' outa = 01001101

and value, mask ' value = 00011000
and mask, outa ' mask = 00001100
xor value, mask ' value = 00010100
xor outa, value ' outa = 01011001


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.
11-20-2010, 02:53 AM
kuroneko (http://forums.parallax.com/member.php?u=52678),

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?

kuroneko
11-20-2010, 02:56 AM
Zog has yet to flash his first LED so do you mind if Zog borrows that snippet?
Be my guest ;)

jorozco
11-20-2010, 04:28 AM
What about:

' mask = 00111100
' value = 11011011
' outa = 01001101

and value, mask ' value = 00011000
and mask, outa ' mask = 00001100
xor value, mask ' value = 00010100
xor outa, value ' outa = 01011001


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 = 00111100
' value = 00011011
' outa = 01001101

and value, mask ' value = 00011000
and mask, outa ' mask = 00001100
xor value, mask ' value = 00010100
xor outa, value ' outa = 01011001


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.

jorozco
11-20-2010, 05:02 AM
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.

RossH
11-20-2010, 05:24 AM
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.

jorozco
11-27-2010, 01:19 AM
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