I guess the requirement is to wait for zero after cognew.
That's really all that's necessary. But it's not necessary to initialize the flag to a non-zero condition before issuing a cognew. The command/response protocol that I outlined takes care of that by itself. You could even issue a command before the cog is ready, if you want to, with no deleterious effects.
I've got an idea that expands on the previous ideas:
Obtain new lock semaphore withlockID := LOCKNEW
do LOCKSET lockID
parameter := lockID
cogid := COGNEW(nnn,@parameter)
when COG launches lockID := par
Caller executes repeat while not LOCKSET(lockID)
COG calls LOCKCLR(lockID)
Now the COG and caller are syncronized and LOCKSET/LOCKCLR can be used to control communications. This is a simple and standard approach where the data is initialized upon launching the COG.
Marshalling access to the data is then done a manner as listed in the Propeller Manual:
PUB ReadResource | Idx
repeat until not lockset(SemID) 'wait until we lock the resource
repeat Idx from 0 to 9 'read all 10 longs of resource
LocalData[Idx] := long[Idx]
lockclr(SemID) 'unlock the resource
PUB WriteResource | Idx
repeat until not lockset(SemID) 'wait until we lock the resource
repeat Idx from 0 to 9 'write all 10 longs to resource
long[Idx] := LocalData[Idx]
lockclr(SemID) 'unlock the resource
All of this could be made into an object that implements the whole launching and communicating with cogs. The COG side of the equation is pretty simple and you provide a template for "good practice", the SPIN or C side is abstracted and uses standard Propeller interfaces absent of any language specifics.
But it is the point of this thread! It is as you say "what most of us use anyway", and that by convention (and wide-spread usage) is a standard.
Yes, it is what we already do to a point, but it should be formalized if people want to rely on it. It is a method "for communicating with cogs from any language!"
No it isn't - it's just a set of conventions for starting cogs. How does it assist with actually communicating with them once they've been started?
If you think it's off topic or that I'm being unreasonable some way, you are welcome to hit that little yellow warning button.
I agree it not off-topic if you can explain how your proposal is relevant to the subject of this thread. That's all I want to know.
I'm sorry, but I just don't understand the rest of your post. I think we must be talking at cross purposes. All your point 4 essentially says is that "there must be a documented API". But an API is a language-specific concept - such a thing doesn't exist at the same level that the rest of your points address (starting cogs, passing par parameters etc). Even if there were already such a thing as an API for making cog-to-cog calls (which is what this thread is actually about) Your proposal doesn't even say that two cogs that offer exactly the same functions should offer the same API. So how is it in any way a "standard"?
Or to put it another way - even if I had a cog program which followed all of your proposed conventions (which the cog programs in most OBEX objects already do) how do I actually communicate with it? Use the API? How does that help if no-one's yet written an API for the language I want to use the cog program from? We need something that is applicable to any language, not just one language (hence the topic of this thread!).
Okay. I see where you are going with this then. And these are a pair of very diverse examples. So, is this what you are trying to promote here is something along the lines of:
1. We have a common means for ICC (inter-cog-communications) that is "the registry" or something like that.
2. Each chunk of pogram code can elect to implement ICC as its means of interacting with other modules
3. Then the provider of that program "chunk" just has to document how to interact with it via the specific way it deals with its ICC interface.
4. Then adopters of the "chunk" just have to follow the documentation in order to integrate it.
Is that what you are after here or am I way off the mark still? --- and if I still don't get it -- then I do not expect that you correct me (possibly) errant thinking. I'll just continue to follow along and maybe my lightbulb will just suddenly go on.
Yes, you've got it. I'm kind of sorry I ever introduced the "registry". I happen to think it is a good solution, but anyone is free to propose another. I introduced it because it is the right "kind" of solution - i.e. a way to allow different people to write cog programs that are guaranteed to be able to inter-operate. The registry is only part of that - an equally important part is the formalization of a means of requesting a service from another cog, without having to know anything about the cog other than that it provides the advertised service! But even here, this kind of implied client/server setup is not necessarily what I am after - it is just a special case in a wider set of possibilities.
I've very rarely found locks necessary to coordinate command and data passing. It would be a mistake, I believe, to make locks (a limited resource, BTW) part of an inter-cog communication standard. Let's save them for when they're really needed.
Well, Ross, it seems to me that you are on to something with this notion. So, the steak could be very good....now the sizzle must be added in order to get everyone to buy a slice
I've very rarely found locks necessary to coordinate command and data passing. It would be a mistake, I believe, to make locks (a limited resource, BTW) part of an inter-cog communication standard. Let's save them for when they're really needed.
-Phil
Hi Phil,
I've found a need to use them when communicating with cog programs from multiple other cogs. If I were to go back and redesign the registry, I'd reserve 3 bits for a "lock" value. I'd reserving one value (probably lock 0) to mean "no lock needed". So if the registry entry for a cog program had a non-zero lock value, it would mean that you must acquire that lock successfully before you were allowed to interact with the cog, and that you must release the lock when you are finished. If the value is zero it means you don't need to bother.
Well, Ross, it seems to me that you are on to something with this notion. So, the steak could be very good....now the sizzle must be added in order to get everyone to buy a slice
Surely there is enough sizzle in this thread already
No it isn't - it's just a set of conventions for starting cogs. How does it assist with actually communicating with them once they've been started?I agree it not off-topic if you can explain how your proposal is relevant to the subject of this thread. That's all I want to know.
I'm sorry, but I just don't understand the rest of your post. I think we must be talking at cross purposes. All your point 4 essentially says is that "there must be a documented API". But an API is a language-specific concept - such a thing doesn't exist at the same level that the rest of your points address
No API is not necessarily language specific, it CAN be source code based. Sockets defines an API for example but they are used everywhere.
However, since you insist on API being language specific, API should obviously be replaced by ABI.
An ABI (or API if interpreted reasonably) assists in communicating with a COG once it is started because the user started the COG.
In what cases do you expect a user to communicate with a COG that the user did not start ???
In #5, I don't think the "non-zero before COGNEW" is necessary. A command sent prematurely will just wait to be executed until the driver is ready to start accepting commands. This also precludes the driver having to write a zero to the PAR variable to get the ball rolling. After that, the exchange is: caller writes non-zero to issue a command; driver writes zero to signal done.
That's assuming that the commands are using the same space as the initialization. But that's not necessarily the case. Many drivers may need more parameters during initialization than during commands. For example, a serial port driver needs which pins to use, and the baud rate, to be in its initial parameter block; but those typically are not repeated in request blocks. (Indeed the serial port typically doesn't even really have request blocks, just dynamic queues). If the initial parameter block is longer than any request block, the high level language may want to re-use the excess memory. So it needs to know when it is safe to do so.
I like the 5 part "minimalist" solution. While the registry idea is interesting it seems to me to be overkill. Having the registry as a layer on top of the minimalist approach would be good. That way you only use it if you need it.
No API is not necessarily language specific, it CAN be source code based. Sockets defines an API for example but they are used everywhere.
However, since you insist on API being language specific, API should obviously be replaced by ABI.
An ABI (or API if interpreted reasonably) assists in communicating with a COG once it is started because the user started the COG.
In what cases do you expect a user to communicate with a COG that the user did not start ???
Ok - happy to adopt this terminology. What is your proposed ABI?
Also, you seem to be stuck on the mechanism to be used for one cog starting another cog. Since there isn't really much choice here, let's all agree we just use the coginit instruction with a par parameter and move on (of course, what that par parameter should be is actually one of the problems we need to address). But unfortunately there is no equally simple instruction that allows me to communicate with a cog once it has been started. So we have all had to come up a mechanism on our own, and there are many different ones floating around.
I have proposed a standard for this. What alternative standard you are proposing?
I like the 5 part "minimalist" solution. While the registry idea is interesting it seems to me to be overkill. Having the registry as a layer on top of the minimalist approach would be good. That way you only use it if you need it.
C.W.
But the "minimalist" approach is nothing more than what we have now. How does it actually help?
I'm sorry, but I just don't understand the rest of your post. I think we must be talking at cross purposes. All your point 4 essentially says is that "there must be a documented API". But an API is a language-specific concept - such a thing doesn't exist at the same level that the rest of your points address (starting cogs, passing par parameters etc).
I think the intention is that all communication with the cog should be via writing data to memory at locations which are specified by the initialization block. It's true that this is very vague, but it's something that can be done from any language. The explicit details of having standard ways of communicating with specific drivers (serial, floating point, etc.) is something that nobody has really addressed here, not even in your registry proposal. The registry may list the services, but the details of how to communicate with the services (the meanings of the commands, how many parameters there are, and how to interpret results) are all unspecified. I think we all agree that it would be useful to have such a specification for various classes of drivers, but we're still at a much earlier stage of trying to figure out the low level communication protocol.
Or to put it another way - even if I had a cog program which followed all of your proposed conventions (which the cog programs in most OBEX objects already do) how do I actually communicate with it?
The same problem is true of a cog program which follows the Catalina registry standard. How do I actually communicate with such a program? I can get slightly further, in that I know where in memory it expects its commands and parameters... but I don't know what commands it accepts, or what parameters, or what its results mean. All of that information is only available from external documentation. In other words, somebody has to document the driver and read the documentation in order to communicate with it.
Ideally there would be some "gold standard" drivers whose interfaces were so clear and consistent that all similar drivers followed them, and then plugging in new drivers would be much simpler (and the registry information about what kind of driver it is would then become useful). But I suspect there will always be exceptions -- after all, what is the point of writing a new driver if it doesn't offer new features that the old driver doesn't? And then you still need documentation for the new driver, and applications written to use it will not be compatible with the old driver. That's not to say that a minimum standard isn't useful, just that there is no silver bullet that will replace the need to document interfaces and sometimes re-write code.
But the "minimalist" approach is nothing more than what we have now. How does it actually help?
Ross.
Is it what we have now? I thought one of the problems people have complained about is that some objects interact with the main program via variables or pointers that aren't passed in PAR. So specifying that all communication has to happen via the PAR parameter block and/or pointers contained within is indeed be a step forward -- a baby step, perhaps, but progress nonetheless.
But the "minimalist" approach is nothing more than what we have now. How does it actually help?
I think it is more than we have now because it is a standard approach.
Firstly there is the case where cogs interact via random variables scattered through the program. That makes it almost impossible to use that plugin with multiple languages.
Second is the example where you declare a parameter list in the higher level language like Spin. That makes it difficult to port over to other languages because the parameter list is not in the PASM part.
Third is the case where variables are declared in the pasm part and they are used at the top of the program but they are declared at the bottom of the program. The first thing you want to know when decoding is a program is the parameters it uses and this is hidden away near the bottom. So at the very least there ought to be a note at the top of the program saying to look for the parameter list near the bottom. And a better solution would be a more detailed description of that list near the top - what the variables are called, what the shortened name might stand for, what possible values it could take.
Even just doing these simple things will make it much easier to use pasm code between multiple languages. Also, this doesn't require recoding objects - just possibly moving declarations around to different places and documenting things in more detail. At the moment some PAR lists don't even have comments on them.
Is it what we have now? I thought one of the problems people have complained about is that some objects interact with the main program via variables or pointers that aren't passed in PAR. So specifying that all communication has to happen via the PAR parameter block and/or pointers contained within is indeed be a step forward -- a baby step, perhaps, but progress nonetheless.
Eric
I have no problem with communicating via variables not passed in par - if you think about it, this is in fact my preferred solution. I find this the par technique way too limiting.
I can also agree that the 5 point proposal is a "baby" step to solving a problem. But it is the wrong problem! I'm okay with you guys solving it - but let's not get confused here - that paticular problems is not the problem I intended to address in this thread!
But it is the wrong problem! I'm okay with you guys solving it - but let's not get confused here - that paticular problems is not the problem I intended to address in this thread!
I'm not sure what you gain from the registry other than "discovery", which I don't understand the need for in the context of Propeller applications.
I'm not trying to knock the idea, I just don't understand the need for it.
Ross, I have reread your document on the first posting of this thread and there are a number of good ideas. The problem is that the document introduces so many ideas that the whole thing becomes very confusing. I am having trouble coming to grips with the entire standard that you propose. For the moment, service requests and the structure of the registry are still beyond my comprehension, but to start at the beginning of the document and to work through it, could you comment on some ideas in the following from page 5?
It contains a CON section. However, note that any constants defined here can
only be used within the plugin itself, or within the target that loads it. If any of
these constants are required in C, they will need to be redefined in a C header
file.
· It contains an OBJ section with includes Catalina_Common. This is where all
common platform dependent information (such as I/O pin definitions and clock
speeds) will be stored – such things should not be duplicated in the plugin
itself.
· It contains no SPIN methods, other than a start method which will be invoked
by the target at load time (but note that if the plugin is to be re-loaded
dynamically, this method cannot be called, but its functionality will have to be
duplicated in C).
· It contains no VAR section. While it is possible to have a VAR block and use it
during initialization, after initialization any variables defined in the VAR block
would no longer exist in Hub RAM at run-time. Instead, a plugin that needs
Hub RAM should be told what Hub RAM to use dynamically - either during
startup (i.e. in the start method) or later by passing initialization parameters
via the registry. Doing this allocation statically at initialization time is ok for
plugins that are never intended to be unloaded or reloaded, but in this case
the registry technique is used since we want to be able to reload and restart
the plugin dynamically. However, this does not mean that we have to wait and
initialize the plugin from C - the start method of this plugin actually uses the
registry to initialize the plugin at load time.
· Now look at the DAT section. This contains the PASM that implements the
plugin. The first thing the plugin does (see the code at label entry) is register
itself. This is sometimes done in the start method, but for plugins that may be
loaded dynamically, it is better if they register themselves on startup. All
plugins are passed the address of the registry on startup – this will appear in
the par register. From this, they use their cog id to calculate their registry
block address that is used for all subsequent communications. See the next
section for more details on registration.
The CON section makes sense - these are local variables only as the pasm part might be compiled separately.
The OBJ section seems to break this rule though - here you have common variables declared in another file. Could that cause problems if that other file did not exist? Take the example of describing which pin to use. Your method defines this in a common file, but most obex objects would pass the pin number in a start method. Is your catalina_common file part of your intercog standard?
In the VAR section you talk about dynamically allocating hub ram. Is this part of your new standard? For instance, take a typical serial port object. At the moment, you might declare a contiguous block of longs - either as part of the PAR group (best) or somewhere else in ram but pointed to by a variable in the PAR group (not so good but allowed and probably necessary if the buffer is large).
Your standard proposes a new way which declares ram via the registry. Presumably this now entails a protocol that the registry uses. Is this protocol described somewhere?
Perhaps once we have covered these issues you might also be able to talk about 'service requests' a bit more.
As an example, consider a serial driver plugin where you have three variables - the location of the circular buffer, the head and the tail. Knowing these values, a calling program can determine with one line of code if there is any data (is head equal to tail?) and determine where the data is (head plus location of the buffer). How would this work though with service requests? Does the calling program now send a message to the plugin saying "give me the next value".
I'm not sure the actual method needs help. I think documentation and examples are the main thing.
C.W.
So your solution to making all the new "gold standard" OBEX entries usable from C, C++, Basic, Forth, Java etc is to just document and then let everyone figure out an appropriate mechanism for themselves? That works ok for hobbyists, but not for others.
I think it is more than we have now because it is a standard approach.
Perhaps, Dr_A - but I find it hard to argue for or against it, because this proposed approach is not even addressing the right problem. How do I communicate with a cog that uses this "standard" approach?
Ross, I have reread your document on the first posting of this thread and there are a number of good ideas. The problem is that the document introduces so many ideas that the whole thing becomes very confusing.
Dr_A,
Rather than try and explain that particular solution again (and it is just one possible solution anyway) let me just summarize what this thread is supposed to be about, because some people either seem to have misunderstood it, or lost sight of it in all the hubble and bubble.
This thread is about making it possible to re-use the same cog programs from multiple languages (including Spin), without having to rewrite the cog programs to use either a cog-specific or language-specific mechanism for doing so. The main issue here is not how the cog is started, it is about how we communicate with the cog at run-time.
High level languages generally define a set of services they expect to have available at run-time, and on the Propeller these services are usually (but not always) provided by cog programs. This is part of what makes the Propeller unique. On other processors, such services are generally provided by a simple inline function call to a library function, linked in at compile time - so all you really need on a normal processor is a standard function calling convention and a documented API.
But we can't do that on the Propeller - you cannot call a PASM function in one cog from another - so this thread is about coming up with a language-independent technique (analogous to a calling convention) that allows us to invoke the code in one cog from another cog (in fact, generalizing this - from one or more arbitrary cogs).
Generally, we refer to this as invoking a service request, which is a model similar to a function call - but you could also use the model of remote procedure calls, or message passing, or mailboxes, or rendezvous. These are all mechanisms used by various concurrent languages to achieve the same thing.
Now let me talk a little about what this thread is not about ...
First, you complained about the fact that people use variables sprinkled throughout their code to communicate with cogs - this is true, but it is really a problem peculiar to Spin, since Spin makes it easy (too easy!) to do this. This particular problem will not occur in other languages, and the Spin problem can be resolved by an appropriate set of conventions (including the ones proposed by Jazzed). This is not what this thread is about.
Next, there are various ways of initializing cogs on startup. Some people use a cog-speciifc technique where you pass a custom list of parameters. Others (like me) might prefer a standard technique where you pass a registry from which the cog can then be sent its start up parameters. However, that is not really what this thread is about either!
Other people have mentioned that more documentation about some existing techniques or APIs is all we really need. This is not true - most cog programs are implemented with a Spin API, but this API cannot be used from any other language. The internal API (or ABI, as Jazzed would say) which the Spin code uses to talk to the cog program is arbitrary, and various people use various techniques. Documenting the API and/or the internal ABI is good, but it is also not what this thread is about. Documenting the internal ABItechniques used by each object would be closer to the mark, but is also not really what this thread is about
However, if you instead think standardizing the internal ABI technique, and coming up with one that is appropriate for use from any language, and on top of which each language can build an appropriate API - well, then you are getting mighty close!
Ok, well in that case you are talking about something on a much higher level.
Do you propose numbering your services? eg would a Keyboard be a request for service 1? Would a Mouse be a request for service 2?
Could you start to think about a standard that is cog independent, eg you put a keyboard service in one cog and call it service 1, and a mouse in the next cog and call it service 2, and later you combine the keyboard and mouse into one cog plugin, and then you still don't need to change your calling code - you then call service 1 or 2 from the same cog?
I can see some intriguing advantages in doing this sort of thing.
Do you propose numbering your services? eg would a Keyboard be a request for service 1? Would a Mouse be a request for service 2?
Yes, I would like to see a list of standard cog program/service types - that's when you really start to see some benefit from this. Of course, the technique could also support completely custom cog programs and services. If we used a common numbering scheme, we would probably "reserve" some numbers (or number ranges) specifically for this purpose
Could you start to think about a standard that is cog independent, eg you put a keyboard service in one cog and call it service 1, and a mouse in the next cog and call it service 2, and later you combine the keyboard and mouse into one cog plugin, and then you still don't need to change your calling code - you then call service 1 or 2 from the same cog?
I can see some intriguing advantages in doing this sort of thing.
This is slightly more sophisticated than I originally had in mind - it is more like what Eric subsequently proposed. If people thought this was a good addition (and I do myself - I'm just a bit worried by adding the necessary complexity) then I'd be all in favor of it.
Comments
That's really all that's necessary. But it's not necessary to initialize the flag to a non-zero condition before issuing a cognew. The command/response protocol that I outlined takes care of that by itself. You could even issue a command before the cog is ready, if you want to, with no deleterious effects.
-Phil
- Obtain new lock semaphore with lockID := LOCKNEW
- do LOCKSET lockID
- parameter := lockID
- cogid := COGNEW(nnn,@parameter)
- when COG launches lockID := par
- Caller executes repeat while not LOCKSET(lockID)
- COG calls LOCKCLR(lockID)
Now the COG and caller are syncronized and LOCKSET/LOCKCLR can be used to control communications. This is a simple and standard approach where the data is initialized upon launching the COG.Marshalling access to the data is then done a manner as listed in the Propeller Manual:
All of this could be made into an object that implements the whole launching and communicating with cogs. The COG side of the equation is pretty simple and you provide a template for "good practice", the SPIN or C side is abstracted and uses standard Propeller interfaces absent of any language specifics.
I'm sorry, but I just don't understand the rest of your post. I think we must be talking at cross purposes. All your point 4 essentially says is that "there must be a documented API". But an API is a language-specific concept - such a thing doesn't exist at the same level that the rest of your points address (starting cogs, passing par parameters etc). Even if there were already such a thing as an API for making cog-to-cog calls (which is what this thread is actually about) Your proposal doesn't even say that two cogs that offer exactly the same functions should offer the same API. So how is it in any way a "standard"?
Or to put it another way - even if I had a cog program which followed all of your proposed conventions (which the cog programs in most OBEX objects already do) how do I actually communicate with it? Use the API? How does that help if no-one's yet written an API for the language I want to use the cog program from? We need something that is applicable to any language, not just one language (hence the topic of this thread!).
Ross.
Yes, you've got it. I'm kind of sorry I ever introduced the "registry". I happen to think it is a good solution, but anyone is free to propose another. I introduced it because it is the right "kind" of solution - i.e. a way to allow different people to write cog programs that are guaranteed to be able to inter-operate. The registry is only part of that - an equally important part is the formalization of a means of requesting a service from another cog, without having to know anything about the cog other than that it provides the advertised service! But even here, this kind of implied client/server setup is not necessarily what I am after - it is just a special case in a wider set of possibilities.
Ross.
I've very rarely found locks necessary to coordinate command and data passing. It would be a mistake, I believe, to make locks (a limited resource, BTW) part of an inter-cog communication standard. Let's save them for when they're really needed.
-Phil
Hi Phil,
I've found a need to use them when communicating with cog programs from multiple other cogs. If I were to go back and redesign the registry, I'd reserve 3 bits for a "lock" value. I'd reserving one value (probably lock 0) to mean "no lock needed". So if the registry entry for a cog program had a non-zero lock value, it would mean that you must acquire that lock successfully before you were allowed to interact with the cog, and that you must release the lock when you are finished. If the value is zero it means you don't need to bother.
Ross.
Surely there is enough sizzle in this thread already
Ross.
No API is not necessarily language specific, it CAN be source code based. Sockets defines an API for example but they are used everywhere.
However, since you insist on API being language specific, API should obviously be replaced by ABI.
An ABI (or API if interpreted reasonably) assists in communicating with a COG once it is started because the user started the COG.
In what cases do you expect a user to communicate with a COG that the user did not start ???
That's assuming that the commands are using the same space as the initialization. But that's not necessarily the case. Many drivers may need more parameters during initialization than during commands. For example, a serial port driver needs which pins to use, and the baud rate, to be in its initial parameter block; but those typically are not repeated in request blocks. (Indeed the serial port typically doesn't even really have request blocks, just dynamic queues). If the initial parameter block is longer than any request block, the high level language may want to re-use the excess memory. So it needs to know when it is safe to do so.
Eric
C.W.
Ok - happy to adopt this terminology. What is your proposed ABI?
Also, you seem to be stuck on the mechanism to be used for one cog starting another cog. Since there isn't really much choice here, let's all agree we just use the coginit instruction with a par parameter and move on (of course, what that par parameter should be is actually one of the problems we need to address). But unfortunately there is no equally simple instruction that allows me to communicate with a cog once it has been started. So we have all had to come up a mechanism on our own, and there are many different ones floating around.
I have proposed a standard for this. What alternative standard you are proposing?
Ross.
But the "minimalist" approach is nothing more than what we have now. How does it actually help?
Ross.
The same problem is true of a cog program which follows the Catalina registry standard. How do I actually communicate with such a program? I can get slightly further, in that I know where in memory it expects its commands and parameters... but I don't know what commands it accepts, or what parameters, or what its results mean. All of that information is only available from external documentation. In other words, somebody has to document the driver and read the documentation in order to communicate with it.
Ideally there would be some "gold standard" drivers whose interfaces were so clear and consistent that all similar drivers followed them, and then plugging in new drivers would be much simpler (and the registry information about what kind of driver it is would then become useful). But I suspect there will always be exceptions -- after all, what is the point of writing a new driver if it doesn't offer new features that the old driver doesn't? And then you still need documentation for the new driver, and applications written to use it will not be compatible with the old driver. That's not to say that a minimum standard isn't useful, just that there is no silver bullet that will replace the need to document interfaces and sometimes re-write code.
Eric
Is it what we have now? I thought one of the problems people have complained about is that some objects interact with the main program via variables or pointers that aren't passed in PAR. So specifying that all communication has to happen via the PAR parameter block and/or pointers contained within is indeed be a step forward -- a baby step, perhaps, but progress nonetheless.
Eric
I'm not sure the actual method needs help. I think documentation and examples are the main thing.
C.W.
I think it is more than we have now because it is a standard approach.
Firstly there is the case where cogs interact via random variables scattered through the program. That makes it almost impossible to use that plugin with multiple languages.
Second is the example where you declare a parameter list in the higher level language like Spin. That makes it difficult to port over to other languages because the parameter list is not in the PASM part.
Third is the case where variables are declared in the pasm part and they are used at the top of the program but they are declared at the bottom of the program. The first thing you want to know when decoding is a program is the parameters it uses and this is hidden away near the bottom. So at the very least there ought to be a note at the top of the program saying to look for the parameter list near the bottom. And a better solution would be a more detailed description of that list near the top - what the variables are called, what the shortened name might stand for, what possible values it could take.
Even just doing these simple things will make it much easier to use pasm code between multiple languages. Also, this doesn't require recoding objects - just possibly moving declarations around to different places and documenting things in more detail. At the moment some PAR lists don't even have comments on them.
I have no problem with communicating via variables not passed in par - if you think about it, this is in fact my preferred solution. I find this the par technique way too limiting.
I can also agree that the 5 point proposal is a "baby" step to solving a problem. But it is the wrong problem! I'm okay with you guys solving it - but let's not get confused here - that paticular problems is not the problem I intended to address in this thread!
I'm not sure what you gain from the registry other than "discovery", which I don't understand the need for in the context of Propeller applications.
I'm not trying to knock the idea, I just don't understand the need for it.
C.W.
Now let's move on.
A "standard" is agreed to - not forced upon.
-Phil
The CON section makes sense - these are local variables only as the pasm part might be compiled separately.
The OBJ section seems to break this rule though - here you have common variables declared in another file. Could that cause problems if that other file did not exist? Take the example of describing which pin to use. Your method defines this in a common file, but most obex objects would pass the pin number in a start method. Is your catalina_common file part of your intercog standard?
In the VAR section you talk about dynamically allocating hub ram. Is this part of your new standard? For instance, take a typical serial port object. At the moment, you might declare a contiguous block of longs - either as part of the PAR group (best) or somewhere else in ram but pointed to by a variable in the PAR group (not so good but allowed and probably necessary if the buffer is large).
Your standard proposes a new way which declares ram via the registry. Presumably this now entails a protocol that the registry uses. Is this protocol described somewhere?
Perhaps once we have covered these issues you might also be able to talk about 'service requests' a bit more.
As an example, consider a serial driver plugin where you have three variables - the location of the circular buffer, the head and the tail. Knowing these values, a calling program can determine with one line of code if there is any data (is head equal to tail?) and determine where the data is (head plus location of the buffer). How would this work though with service requests? Does the calling program now send a message to the plugin saying "give me the next value".
So your solution to making all the new "gold standard" OBEX entries usable from C, C++, Basic, Forth, Java etc is to just document and then let everyone figure out an appropriate mechanism for themselves? That works ok for hobbyists, but not for others.
Ross.
I'm fine with you not liking the registry idea - come up with an alternative!
Ross.
Yes - but a standard is more than just a set of conventions.
Ross.
Ross.
Dr_A,
Rather than try and explain that particular solution again (and it is just one possible solution anyway) let me just summarize what this thread is supposed to be about, because some people either seem to have misunderstood it, or lost sight of it in all the hubble and bubble.
This thread is about making it possible to re-use the same cog programs from multiple languages (including Spin), without having to rewrite the cog programs to use either a cog-specific or language-specific mechanism for doing so. The main issue here is not how the cog is started, it is about how we communicate with the cog at run-time.
High level languages generally define a set of services they expect to have available at run-time, and on the Propeller these services are usually (but not always) provided by cog programs. This is part of what makes the Propeller unique. On other processors, such services are generally provided by a simple inline function call to a library function, linked in at compile time - so all you really need on a normal processor is a standard function calling convention and a documented API.
But we can't do that on the Propeller - you cannot call a PASM function in one cog from another - so this thread is about coming up with a language-independent technique (analogous to a calling convention) that allows us to invoke the code in one cog from another cog (in fact, generalizing this - from one or more arbitrary cogs).
Generally, we refer to this as invoking a service request, which is a model similar to a function call - but you could also use the model of remote procedure calls, or message passing, or mailboxes, or rendezvous. These are all mechanisms used by various concurrent languages to achieve the same thing.
Now let me talk a little about what this thread is not about ...
First, you complained about the fact that people use variables sprinkled throughout their code to communicate with cogs - this is true, but it is really a problem peculiar to Spin, since Spin makes it easy (too easy!) to do this. This particular problem will not occur in other languages, and the Spin problem can be resolved by an appropriate set of conventions (including the ones proposed by Jazzed). This is not what this thread is about.
Next, there are various ways of initializing cogs on startup. Some people use a cog-speciifc technique where you pass a custom list of parameters. Others (like me) might prefer a standard technique where you pass a registry from which the cog can then be sent its start up parameters. However, that is not really what this thread is about either!
Other people have mentioned that more documentation about some existing techniques or APIs is all we really need. This is not true - most cog programs are implemented with a Spin API, but this API cannot be used from any other language. The internal API (or ABI, as Jazzed would say) which the Spin code uses to talk to the cog program is arbitrary, and various people use various techniques. Documenting the API and/or the internal ABI is good, but it is also not what this thread is about. Documenting the internal ABI techniques used by each object would be closer to the mark, but is also not really what this thread is about
However, if you instead think standardizing the internal ABI technique, and coming up with one that is appropriate for use from any language, and on top of which each language can build an appropriate API - well, then you are getting mighty close!
Ross.
Do you propose numbering your services? eg would a Keyboard be a request for service 1? Would a Mouse be a request for service 2?
Could you start to think about a standard that is cog independent, eg you put a keyboard service in one cog and call it service 1, and a mouse in the next cog and call it service 2, and later you combine the keyboard and mouse into one cog plugin, and then you still don't need to change your calling code - you then call service 1 or 2 from the same cog?
I can see some intriguing advantages in doing this sort of thing.
This is slightly more sophisticated than I originally had in mind - it is more like what Eric subsequently proposed. If people thought this was a good addition (and I do myself - I'm just a bit worried by adding the necessary complexity) then I'd be all in favor of it.
Ross.