For the same reason I don't think you need the _PROP2_NAMES define to protect the defines of _DIRA, etc. You can just unconditionally define them. New programs written for Prop2 should always use the underscore version, for compatibility with other compiilers and to leave the non-underscore version free for the user's use.
I take your first point, but a problem still occurs if a program uses (say) DIRA as a local variable name, but also uses _DIRA, expecting it to refer to the special register. This would be quite legal. But if the #defines are unconditional then such a program would compile without error, but it would not execute correctly. By requiring the definition of _PROP2_NAMES to get it to compile, the user is at least made aware that there is a potential name conflict.
Of course, I am suggesting this only for Catalina's version of the include file, not for other compilers, which may not have the same issue.
One advantage of this solution is that it can be fixed on the command line, and does not require a source code change - unless of course there actually is a conflict. I am posting this mainly to see if there is an easier or better solution that I may have missed.
Requiring _PROP2_NAMES to be defined before the standard _DIRA, _INA, etc. register names are present kind of defeats the purpose of propeller2.h, which is to provide a set of standard names for all programs that #include it. I mean, we could require that programs always #define _PROP2_NAMES before including propeller2.h, but then why even do that? (edit: Oh, I see you were suggesting it be defined on the command line; that's better, it does avoid source code changes, but still feels awkward to me.)
It seems to me that the Prop2 is a chance for a clean slate for developers. We may need some ugly hacks to get Prop1 code to compile on Prop2, and that seems OK to me, but let's make things simple for new Prop2 projects.
Could you invert the situation: that is, could you make _DIRA, _INA, etc. the standard names, and define DIRA, INA, etc. only in one of the legacy header files (propeller.h or catalina_cog.h)? And make those definitions conditional? So the old propeller.h could contain something like:
#ifndef _PROP2_NAMES
#define DIRA _DIRA
#define INA _INA
// etc
#endif
Then existing Prop1 code (and your library code) should still compile, while not impacting new Prop2 code and having minimal impact on the ANSI user namespace.
(Having a global variable named DIRA that the library depends on is a violation of the C standard, so it may be worth taking this second approach for compatibility.)
Requiring _PROP2_NAMES to be defined before the standard _DIRA, _INA, etc. register names are present kind of defeats the purpose of propeller2.h, which is to provide a set of standard names for all programs that #include it. I mean, we could require that programs always #define _PROP2_NAMES before including propeller2.h, but then why even do that? (edit: Oh, I see you were suggesting it be defined on the command line; that's better, it does avoid source code changes, but still feels awkward to me.)
It seems to me that the Prop2 is a chance for a clean slate for developers. We may need some ugly hacks to get Prop1 code to compile on Prop2, and that seems OK to me, but let's make things simple for new Prop2 projects.
Could you invert the situation: that is, could you make _DIRA, _INA, etc. the standard names, and define DIRA, INA, etc. only in one of the legacy header files (propeller.h or catalina_cog.h)? And make those definitions conditional? So the old propeller.h could contain something like:
#ifndef _PROP2_NAMES
#define DIRA _DIRA
#define INA _INA
// etc
#endif
Then existing Prop1 code (and your library code) should still compile, while not impacting new Prop2 code and having minimal impact on the ANSI user namespace.
(Having a global variable named DIRA that the library depends on is a violation of the C standard, so it may be worth taking this second approach for compatibility.)
I will have a think on this. The idea of inverting the names and then redefining them in the old propeller.h file would have legs if such a file had itself been standardized and used consistently. But alas ....
The correct answer was staring me in the face - I even mentioned it yesterday, but I hadn't fully thought it through.
This is to define (for example) bothDIRA and _DIRA in the code generator. It is the declaration of these names as "extern volatile" in the user's C program that triggers the association by the code generator with the special register DIRA. Otherwise, they are just symbols like any other.
So if you include "propeller2.h" - or manually declare "extern volatile _DIRA" - then _DIRA means the special register and DIRA is just a symbol with no special meaning.
And if you include the old "propeller.h" - or manually declare "extern volatile DIRA" (which some programs do) - then DIRA means the special register and _DIRA is just a symbol with no special meaning.
I think this will work for all P1 and P2 programs - no conditional compilation or command line options required!
Does anyone have any C code - or code in any other language that could be converted to C code - that would make a good test for these functions? Note that we are not actually trying to test the smart pins themselves, just the C function calls - so quite trivial examples are perfectly fine. But it would be nice if they produced results that were evident on one or more of the LEDs on the P2_EVAL board.
Here's a routine I use for scanning all the smartpins before initialising the comport. I lifted it from someone else, Oz or Rog I think. It uses the repository mode to build a map of functioning smartpins, which was particularly useful with the FPGA builds.
'--------- Detect available smart pins -------
'Returns a 64 bit mask indicating active smart pins - mask_lsb/mask_msb.
mov smart_pin, #63 'test all 64 pins
.searchloop
wrpin #%11_0, smart_pin 'long repository mode
dirh smart_pin
mov pa, ##$c0ffee00
add pa, smart_pin 'unique pattern
wxpin pa, smart_pin 'write long to smart pin
shl mask_lsb, #1 wc 'build valid smart pin mask
rcl mask_msb, #1
rdpin pb, smart_pin 'get long from smart pin repository
cmp pb, pa wz 'valid response?
if_e bith mask_lsb, #0
dirl smart_pin
wrpin #0, smart_pin 'disable smart pin
djnf smart_pin, #.searchloop 'next smart pin
Here's a routine I use for scanning all the smartpins before initialising the comport. I lifted it from someone else, Oz or Rog I think. It uses the repository mode to build a map of functioning smartpins, which was particularly useful with the FPGA builds.
Reading the code now, I think it would be more efficient to use bit indexing in place of the shifts and set ...
EDIT: Deleted previous attemps! There is an instruction for the job! Man, Chip has thought hard here. I'd missed it every time. I kept reading this particular instruction as ALTR, not ALTB, and not even noticed they were separately listed only a few entries apart in the docs!
'--------- Detect available smartpins -------
'Returns a 64-bit bitmap indicating active smartpins - mask_lsb/mask_msb.
mov smart_pin, #63 'test all 64 pins
.searchloop
mov pa, ##$c0ffee00
add pa, smart_pin 'unique pattern
wrpin #%11_0, smart_pin 'longword repository smartpin mode
dirh smart_pin
wxpin pa, smart_pin 'write longword to smartpin
dirl smart_pin 'compact use of smartpin sequencing, requires a gap between write and read
rdpin pb, smart_pin 'get longword from smartpin repository
wrpin #0, smart_pin 'turn off smartpin
cmp pb, pa wz 'valid response?
altb smart_pin, #mask_lsb 'extracts cogRAM address as if bitfield addressing - bitwise ALTxx
bitz 0-0, smart_pin 'S value (smart_pin) is masked to least 5 bits by the instruction
djnf smart_pin, #.searchloop 'next pin
Ok, I give up. What is _lockchk() supposed to actually do?. None of the implementations I have tried do what I would have expected such a function to do, so if someone can just tell me what it does in Spin, or (better yet) in other C compilers, I will make it do that and forget about it
EDIT: I've now looked at the Spin interpreter, and I can see that Spin interpreter apparently does "lockrel x wc" and then returns with the carry in bit 31. This is not what I had posted earlier, which Chip thought at the time was correct. However, I guess I will just do what Spin does and move on
Catalina is nearly ready for its next release, but I'm a bit unhappy releasing software that doesn't appear to do what it says on the box. I have still been unable to get _lockchk() to do anything useful, even though I believe I am now doing exactly what Spin does - i.e.
lockrel r0 wc
bitc r0, #31
I am sure I must be doing something wrong, but I can't see what. Perhaps I am just completely misunderstanding what this instruction is supposed to do?
Does anyone have a program (any language) that demonstrates a working example of _lockchk() (or "lockrel x wc") ?
I don't think anyone has ever used _lockchk. So for now I would recommend that we just leave it out of propeller2.h. Better to have an incomplete header than a broken one. When/if Spin is finished we can try implementing the missing features.
Catalina is nearly ready for its next release, but I'm a bit unhappy releasing software that doesn't appear to do what it says on the box. I have still been unable to get _lockchk() to do anything useful, even though I believe I am now doing exactly what Spin does - i.e.
lockrel r0 wc
bitc r0, #31
I am sure I must be doing something wrong, but I can't see what. Perhaps I am just completely misunderstanding what this instruction is supposed to do?
Does anyone have a program (any language) that demonstrates a working example of _lockchk() (or "lockrel x wc") ?
Reading the code you have there in concert with the Parallax Propeller 2 documentation, the content of r0 needs to identify which of the 16 locks (semaphore bits) you are checking.
If this cog holds the lock it is released, otherwise the lock is unaffected, with WC set and because r0 is a register the status of the lock is returned in C and the cogid of the current/last owner is returned in r0.
So it seems to be useful for checking which cog holds a lock, e.g. if a locktry fails to capture the lock.
I'm not sure what the behaviour of a locktry r0 wc would be if this cog already owns the lock.
The LOCKCHK might be used in a watchdog cog in combination with a COGATN to ask another cog to release the lock to prevent a stall.
If that fails then the watchdog cog could kill the non-responsive cog.
Catalina is nearly ready for its next release, but I'm a bit unhappy releasing software that doesn't appear to do what it says on the box. I have still been unable to get _lockchk() to do anything useful, even though I believe I am now doing exactly what Spin does - i.e.
lockrel r0 wc
bitc r0, #31
I am sure I must be doing something wrong, but I can't see what. Perhaps I am just completely misunderstanding what this instruction is supposed to do?
Does anyone have a program (any language) that demonstrates a working example of _lockchk() (or "lockrel x wc") ?
Reading the code you have there in concert with the Parallax Propeller 2 documentation, the content of r0 needs to identify which of the 16 locks (semaphore bits) you are checking.
If this cog holds the lock it is released, otherwise the lock is unaffected, with WC set and because r0 is a register the status of the lock is returned in C and the cogid of the current/last owner is returned in r0.
So it seems to be useful for checking which cog holds a lock, e.g. if a locktry fails to capture the lock.
I'm not sure what the behaviour of a locktry r0 wc would be if this cog already owns the lock.
The LOCKCHK might be used in a watchdog cog in combination with a COGATN to ask another cog to release the lock to prevent a stall.
If that fails then the watchdog cog could kill the non-responsive cog.
Yes, r0 is a register that holds the lock to be checked, and is also the value returned by the _lockchk() function.
As far as I can tell, the code does nothing at all. It (luckily!) does not appear to release the lock - that would be bad. But it also does not seem to return a useful value - i.e. the return value appears to be the same whether the lock has been allocated or not, or locked or not. You might be correct that the result is meaningless if this function is called by the cog that already has the lock - but how can you know that in advance? However, I will try that case when I get time.
In the meantime, and on the basis that it is much more likely that I have made a silly mistake than Chip has I have decided to leave the code in for the present. It is present in the Spin interpreter, so presumably it does something. I'm just not sure what.
@RossH said:
Catalina is nearly ready for its next release, but I'm a bit unhappy releasing software that doesn't appear to do what it says on the box. I have still been unable to get _lockchk() to do anything useful, even though I believe I am now doing exactly what Spin does - i.e. lockrel r0 wc
 bitc r0, #31
I am sure I must be doing something wrong, but I can't see what. Perhaps I am just completely misunderstanding what this instruction is supposed to do?
Does anyone have a program (any language) that demonstrates a working example of _lockchk() (or "lockrel x wc") ?
I was just implementing the Propeller 2 lock functions in Lua, and again found that the Propeller 2 LOCKREL instruction doesn't appear to do what the documentation says it should do when you call it with WC - e.g. as LOCKREL reg WC. A quick search and I found this old thread on the same issue. The Spin LOCKCHK() function apparently uses this instruction, and that function is still in the Spin documentation.
Has anyone actually used it and gotten it to work yet?
LOCKREL can also be used to query the current lock status. When LOCKREL is executed with WC, the C flag will indicate whether the lock is currently taken. Additionally, if the D field references a register (not an immediate value), the register will be written with the cog ID of the current owner (if held) or last owner (if released). If the cog executing LOCKREL is also the cog that is holding the lock, the normal LOCKREL behavior will still be performed (i.e. the lock will be released).
Even if LOCKREL worked as this suggests (and it doesn't seem to) that last sentence would be a kicker - i.e. "If the cog executing LOCKREL is also the cog that is holding the lock, the normal LOCKREL behavior will still be performed (i.e. the lock will be released)."
This makes any LOCKCHK() type function quite tricky to implement - first, you have to use LOCKTRY to see if the lock is currently held by you. If it was not, but now is, then you have to use LOCKREL to release it again. If it was not and still is not then you must use LOCKREL to get the status of the lock. And this leads to a race condition if some other code is also trying to get the lock - i.e. they may not succeed when they should have, if not for the competing LOCKCHK(). Which means all LOCKTRYs must have additional retry code ... etc etc ...
Fortunately, Catalina also implements Propeller 1 style lock functions (i.e. LOCKSET/LOCKCLR) on the Propeller 2, and the Propeller 1 functions just work. Catalina's multi-threading is only possible because they do.
So those functions are what I will implement in Lua as well, and again give the whole issue a wide berth, until someone with more brains and more patience than me figures it out
Comments
I take your first point, but a problem still occurs if a program uses (say) DIRA as a local variable name, but also uses _DIRA, expecting it to refer to the special register. This would be quite legal. But if the #defines are unconditional then such a program would compile without error, but it would not execute correctly. By requiring the definition of _PROP2_NAMES to get it to compile, the user is at least made aware that there is a potential name conflict.
Of course, I am suggesting this only for Catalina's version of the include file, not for other compilers, which may not have the same issue.
One advantage of this solution is that it can be fixed on the command line, and does not require a source code change - unless of course there actually is a conflict. I am posting this mainly to see if there is an easier or better solution that I may have missed.
It seems to me that the Prop2 is a chance for a clean slate for developers. We may need some ugly hacks to get Prop1 code to compile on Prop2, and that seems OK to me, but let's make things simple for new Prop2 projects.
Could you invert the situation: that is, could you make _DIRA, _INA, etc. the standard names, and define DIRA, INA, etc. only in one of the legacy header files (propeller.h or catalina_cog.h)? And make those definitions conditional? So the old propeller.h could contain something like: Then existing Prop1 code (and your library code) should still compile, while not impacting new Prop2 code and having minimal impact on the ANSI user namespace.
(Having a global variable named DIRA that the library depends on is a violation of the C standard, so it may be worth taking this second approach for compatibility.)
I will have a think on this. The idea of inverting the names and then redefining them in the old propeller.h file would have legs if such a file had itself been standardized and used consistently. But alas ....
The correct answer was staring me in the face - I even mentioned it yesterday, but I hadn't fully thought it through.
This is to define (for example) both DIRA and _DIRA in the code generator. It is the declaration of these names as "extern volatile" in the user's C program that triggers the association by the code generator with the special register DIRA. Otherwise, they are just symbols like any other.
So if you include "propeller2.h" - or manually declare "extern volatile _DIRA" - then _DIRA means the special register and DIRA is just a symbol with no special meaning.
And if you include the old "propeller.h" - or manually declare "extern volatile DIRA" (which some programs do) - then DIRA means the special register and _DIRA is just a symbol with no special meaning.
I think this will work for all P1 and P2 programs - no conditional compilation or command line options required!
Does anyone have any C code - or code in any other language that could be converted to C code - that would make a good test for these functions? Note that we are not actually trying to test the smart pins themselves, just the C function calls - so quite trivial examples are perfectly fine. But it would be nice if they produced results that were evident on one or more of the LEDs on the P2_EVAL board.
Another way to test the smart pins is to put one in repository mode; then you can write data to it with _wrpin() and read it back with _rdpin().
Thanks Eric. I really need to learn about smart pins ... when I get some time
Thanks! I will use parts of this one as well.
EDIT: Deleted previous attemps! There is an instruction for the job! Man, Chip has thought hard here. I'd missed it every time. I kept reading this particular instruction as ALTR, not ALTB, and not even noticed they were separately listed only a few entries apart in the docs!
EDIT: I've now looked at the Spin interpreter, and I can see that Spin interpreter apparently does "lockrel x wc" and then returns with the carry in bit 31. This is not what I had posted earlier, which Chip thought at the time was correct. However, I guess I will just do what Spin does and move on
I am sure I must be doing something wrong, but I can't see what. Perhaps I am just completely misunderstanding what this instruction is supposed to do?
Does anyone have a program (any language) that demonstrates a working example of _lockchk() (or "lockrel x wc") ?
Reading the code you have there in concert with the Parallax Propeller 2 documentation, the content of r0 needs to identify which of the 16 locks (semaphore bits) you are checking.
If this cog holds the lock it is released, otherwise the lock is unaffected, with WC set and because r0 is a register the status of the lock is returned in C and the cogid of the current/last owner is returned in r0.
So it seems to be useful for checking which cog holds a lock, e.g. if a locktry fails to capture the lock.
I'm not sure what the behaviour of a locktry r0 wc would be if this cog already owns the lock.
The LOCKCHK might be used in a watchdog cog in combination with a COGATN to ask another cog to release the lock to prevent a stall.
If that fails then the watchdog cog could kill the non-responsive cog.
Yes, r0 is a register that holds the lock to be checked, and is also the value returned by the _lockchk() function.
As far as I can tell, the code does nothing at all. It (luckily!) does not appear to release the lock - that would be bad. But it also does not seem to return a useful value - i.e. the return value appears to be the same whether the lock has been allocated or not, or locked or not. You might be correct that the result is meaningless if this function is called by the cog that already has the lock - but how can you know that in advance? However, I will try that case when I get time.
In the meantime, and on the basis that it is much more likely that I have made a silly mistake than Chip has I have decided to leave the code in for the present. It is present in the Spin interpreter, so presumably it does something. I'm just not sure what.
Mike
I think the LOCKNEW instruction is the one you want to allocate a new lock number, and LOCKRET frees it.
Fastspin implements the Spin1 lock functions for both P1 and P2, so you could just use those instead of creating your own.
Yes,it does, the code is quite older and I had to do it in SPIN and PASM so I wanted to be sure it is the same.
Locknew seems lo set the lock too and lockrel seems to release the lock AND frees the given lock number.
I simply gave up and require the lock number as parameter given manually.
Mike
I was just implementing the Propeller 2 lock functions in Lua, and again found that the Propeller 2 LOCKREL instruction doesn't appear to do what the documentation says it should do when you call it with WC - e.g. as
LOCKREL reg WC
. A quick search and I found this old thread on the same issue. The Spin LOCKCHK() function apparently uses this instruction, and that function is still in the Spin documentation.Has anyone actually used it and gotten it to work yet?
Ross.
I found this in the Propeller 2 documentation ...
Even if LOCKREL worked as this suggests (and it doesn't seem to) that last sentence would be a kicker - i.e. "If the cog executing LOCKREL is also the cog that is holding the lock, the normal LOCKREL behavior will still be performed (i.e. the lock will be released)."
This makes any LOCKCHK() type function quite tricky to implement - first, you have to use LOCKTRY to see if the lock is currently held by you. If it was not, but now is, then you have to use LOCKREL to release it again. If it was not and still is not then you must use LOCKREL to get the status of the lock. And this leads to a race condition if some other code is also trying to get the lock - i.e. they may not succeed when they should have, if not for the competing LOCKCHK(). Which means all LOCKTRYs must have additional retry code ... etc etc ...
Fortunately, Catalina also implements Propeller 1 style lock functions (i.e. LOCKSET/LOCKCLR) on the Propeller 2, and the Propeller 1 functions just work. Catalina's multi-threading is only possible because they do.
So those functions are what I will implement in Lua as well, and again give the whole issue a wide berth, until someone with more brains and more patience than me figures it out
Ross.