Well yes, Andy, that is the normal way of getting a COG started with a method from another object. But it is not done directly by COGNEW(). But why not?
Looking at it now we see that COGNEW and friends are very weird from a language perspective.
1) They are free standing global functions. That is odd because otherwise Spin has no such concept, all "functions" belong to objects as methods. How come I cannot write such a function for myself?
2) They are polymorphic. I can use COGNEW to start a Spin method in a COG or some PASM code. That tells me that there are really two COGNEW functions under the hood and the one used depends on the type of the parameters I give it. That is odd because Spin otherwise has no concept of polymorphic methods. How come I cannot write such methods myself?
3) They are examples of treating functions as data. The first parameter to COGNEW can be method name. That's very weird because otherwise Spin does dot support using methods as data, for example a value of a parameter in a call. How come I cannot write methods that take other methods as parameters myself?
Let's go further. From a purely language perspective I see no reason why I should not be able to write "COGNEW(someObject.someMethod, ....)
There seems to be no reason why this is not allowed apart from difficulty in the compiler/interpreter.
Looked at this way we see that COGNEW and friends are really special case freaks in the language that don't fit the overall structure of Spin. Perhaps cleaning up this kludge into the Spin syntax is not such a bad idea.
Well yes, Andy, that is the normal way of getting a COG started with a method from another object. But it is not done directly by COGNEW(). But why not?
Looking at it now we see that COGNEW and friends are very weird from a language perspective.
1) They are free standing global functions. That is odd because otherwise Spin has no such concept, all "functions" belong to objects as methods. How come I cannot write such a function for myself?
2) They are polymorphic. I can use COGNEW to start a Spin method in a COG or some PASM code. That tells me that there are really two COGNEW functions under the hood and the one used depends on the type of the parameters I give it. That is odd because Spin otherwise has no concept of polymorphic methods. How come I cannot write such methods myself?
3) They are examples of treating functions as data. The first parameter to COGNEW can be method name. That's very weird because otherwise Spin does dot support using methods as data, for example a value of a parameter in a call. How come I cannot write methods that take other methods as parameters myself?
Let's go further. From a purely language perspective I see no reason why I should not be able to write "COGNEW(someObject.someMethod, ....)
There seems to be no reason why this is not allowed apart from difficulty in the compiler/interpreter.
Looked at this way we see that COGNEW and friends are really special case freaks in the language that don't fit the overall structure of Spin. Perhaps cleaning up this kludge into the Spin syntax is not such a bad idea.
Very good points. I agree with every one of them. One of the basic principles of language design is to avoid lots of special cases. One should be able to pass a value of any type to a function, return it from a function, or assign it to a variable. C is certainly not perfect in this regard either since the syntax for passing arguments "by reference" is different for different types (arrays are passed by reference by default as are functions but structures require an &). I guess there is no perfect language.
I think the reason that a new cog cannot be started with a method in another object is that there was no room in the interpreter to support this. There's no technical reason that prevents starting a Spin cog with a method from another object. The extra code needed to start a cog with a method in another object should be similar to that needed to call a method in another object. There's just no room in the interpreter for it.
Knowing that something is possible and actually being able to do it are two different things:)
My thinking was that we can store anything on an sd-card... so machine executable code could be stored there.... you read it into an array, tell your cog where that array is...
the cog loads the instructions via self-modifying code techniques and you are done. If you want to tell the cog where to start executing the code. If your program wants other parameters, they are stored in the array at specific places with specific meaning, which your cog program respects.
So, I assert that a function returning an error is often the same as an operation that just aborts your entire program. Whatever it is has failed. What can you do? That's OK at test and debug time. When running in the field your system is dead whatever.
No.
This is what 'boundary checks' and 'exception handling' is all about.
If the system has a screen, it can output some debug information, which the user can write down and relay to you, preferably with a detailed description of what they were doing.
If it doesn't have a screen, maybe it has some sort of storage(I2C, SPI, 1-Wire, whatever) that it can dump a log into?
then it should either retry the operation(such as asking the user for the correct input, attempt another read from a device or whatever), 'die gracefully' or possibly restart.
(Die gracefully = stop all external equipment in a safe manner, then halt the CPU. Quite important if it controls heavy machinery or sharp bits... )
If my program tries to perform some operation that fails there seem to be a couple of options:
1) The operation returns an error code which my program checks and handles somehow. Basically the error has diverted the flow of control in my code. If I don't check the error something weird and probably bad happens.
2) The operation throws some kind of exception which my program catches and handles somehow. Basically the error has diverted the flow of control in my code. If I don't catch the exception something weird and probably bad happens. If I don't catch any exceptions then the program probably terminates which may not be such a good thing.
Basically error returns or exceptions are the same thing. Although we can argue about which is the easiest to think about when constructing the code.
Having a user around to decide how to continue makes no difference. In embedded systems that is not an option anyway.
The classic examples are claiming memory, "malloc" in C vs "new" in C++. It could well be that my program is going to fail for lack of memory. It's going to fail. Using exceptions or return codes does not change that fact.
At the end of the day an exception is just a higher level and less efficient way of writing "goto". That is why the Linux kernel is full of gotos.
The issue of "boundary checks" is something else. For example:
In Ada, for example, accessing an array out of bounds "array[x]" can create an exception. Or a simple operation like "x = x + 1" can raise an exception. Sure you cannot do that in C or Spin.
The big gain here is that such exceptions are detected by the run time system or OS rather than silently happening and causing weird stuff to happen later on in execution. You really don't want to be checking an error code every time yo access an array or do an arithmetic operation.
That is to say "I can't do that" is better than "I did it, it might be wrong".
There are those that would argue that if these things are happening in your production code you have not performed enough testing and/or coverage analysis. That quad copter you are controlling is going to crash the same with error code checking or exceptions.
Ummm, I know I'm one of the offenders but could we move language wars to another topic? I keep thinking there is some exciting update on P2 but only find various interesting but irrelevant to the topic comments on language design. :-)
OK David, we are just twiddling our thumbs whist waiting.
Is it ready yet?
Well, some of us don't *have* to be in thumb twiddling mode since we have FPGA boards we could be working with. I have to admit though that I haven't plugged mine in in weeks. I need to get back to it!
UPDATE: someone said they were hoping for an update. The wafers are getting packaged in Taiwan. Hopefully we'll see some chips next week. I'm still working on the compiler. It's coming together nicely. I think all the flow-control (IF/CASE/REPEAT) is done. The variable handling is pretty much done, but needs to grow a little to accommodate some new stack/local type. All the compilers bones are getting adjusted and fine-tuned, and 95% of the flesh is on. I'm really looking forward to being able to use it write programs for Prop2.
I'm going to explore the Invaders code on mine tonight. I've had it off for a few weeks myself. Real life got in the way, and that mystery "why does the TV driver tear?" bug is still out there to get fixed...
UPDATE: someone said they were hoping for an update. The wafers are getting packaged in Taiwan. Hopefully we'll see some chips next week. I'm still working on the compiler. It's coming together nicely. I think all the flow-control (IF/CASE/REPEAT) is done. The variable handling is pretty much done, but needs to grow a little to accommodate some new stack/local type. All the compilers bones are getting adjusted and fine-tuned, and 95% of the flesh is on. I'm really looking forward to being able to use it write programs for Prop2.
UPDATE: someone said they were hoping for an update. The wafers are getting packaged in Taiwan. Hopefully we'll see some chips next week. I'm still working on the compiler. It's coming together nicely. I think all the flow-control (IF/CASE/REPEAT) is done. The variable handling is pretty much done, but needs to grow a little to accommodate some new stack/local type. All the compilers bones are getting adjusted and fine-tuned, and 95% of the flesh is on. I'm really looking forward to being able to use it write programs for Prop2.
One of the wafers we received was deemed bad by the fab, so a few minutes ago we broke the triple seal on the packaging of that wafer, pulled it out, and snapped a few quick pictures (thank you Emily!). Here's a couple of the best pictures (shrunk down for easy forum digestion).
We will take better pictures when we have more time, but we wanted to get you something to look at for now.
NOTE: The every-other-row placement is unexpected by us, and the structure placed in the "blank" rows is unknown. We are currently trying to figure out what that is. Chip thinks it may be a by-product of the MLR (multi-layer reticle) usage.
Fantastic to see such pictures. It's like seeing the ultrascan images of your new baby.
@__red__
What was the mystery about the 186? It was real. I was involved in a couple of projects that used the 80186. It was even used in some really cool "PC compatible" machines from Nokia complete with high res black and white displays, like early Macs, back when PC's were mostly 8086 and green screen text terminals.
Those Nokia machines were supplied as systems with 80286 boxes running xenix as the central file server.
FYI) based on an earlier question on number of die.... Looks like about 236 dies on the wafer. Figure about an 85% to 90% yield and that's 200 to 212 dies per wafer.
Much like people ask what the 8186 processor was between the 8086 and 8286.
The 80186 was mostly used for embedded systems but it was very popular for that purpose. It was very similar to the 8086 but had some additional on-board peripherals which made it easier to design with but less appropriate for a general purpose desktop system. I've put thousands of them in service in my little corner of industry.
Comments
Looking at it now we see that COGNEW and friends are very weird from a language perspective.
1) They are free standing global functions. That is odd because otherwise Spin has no such concept, all "functions" belong to objects as methods. How come I cannot write such a function for myself?
2) They are polymorphic. I can use COGNEW to start a Spin method in a COG or some PASM code. That tells me that there are really two COGNEW functions under the hood and the one used depends on the type of the parameters I give it. That is odd because Spin otherwise has no concept of polymorphic methods. How come I cannot write such methods myself?
3) They are examples of treating functions as data. The first parameter to COGNEW can be method name. That's very weird because otherwise Spin does dot support using methods as data, for example a value of a parameter in a call. How come I cannot write methods that take other methods as parameters myself?
Let's go further. From a purely language perspective I see no reason why I should not be able to write "COGNEW(someObject.someMethod, ....)
There seems to be no reason why this is not allowed apart from difficulty in the compiler/interpreter.
Looked at this way we see that COGNEW and friends are really special case freaks in the language that don't fit the overall structure of Spin. Perhaps cleaning up this kludge into the Spin syntax is not such a bad idea.
Knowing that something is possible and actually being able to do it are two different things:)
My thinking was that we can store anything on an sd-card... so machine executable code could be stored there.... you read it into an array, tell your cog where that array is...
the cog loads the instructions via self-modifying code techniques and you are done. If you want to tell the cog where to start executing the code. If your program wants other parameters, they are stored in the array at specific places with specific meaning, which your cog program respects.
No.
This is what 'boundary checks' and 'exception handling' is all about.
If the system has a screen, it can output some debug information, which the user can write down and relay to you, preferably with a detailed description of what they were doing.
If it doesn't have a screen, maybe it has some sort of storage(I2C, SPI, 1-Wire, whatever) that it can dump a log into?
then it should either retry the operation(such as asking the user for the correct input, attempt another read from a device or whatever), 'die gracefully' or possibly restart.
(Die gracefully = stop all external equipment in a safe manner, then halt the CPU. Quite important if it controls heavy machinery or sharp bits... )
What do you mean "No". Perhaps "maybe".
If my program tries to perform some operation that fails there seem to be a couple of options:
1) The operation returns an error code which my program checks and handles somehow. Basically the error has diverted the flow of control in my code. If I don't check the error something weird and probably bad happens.
2) The operation throws some kind of exception which my program catches and handles somehow. Basically the error has diverted the flow of control in my code. If I don't catch the exception something weird and probably bad happens. If I don't catch any exceptions then the program probably terminates which may not be such a good thing.
Basically error returns or exceptions are the same thing. Although we can argue about which is the easiest to think about when constructing the code.
Having a user around to decide how to continue makes no difference. In embedded systems that is not an option anyway.
The classic examples are claiming memory, "malloc" in C vs "new" in C++. It could well be that my program is going to fail for lack of memory. It's going to fail. Using exceptions or return codes does not change that fact.
At the end of the day an exception is just a higher level and less efficient way of writing "goto". That is why the Linux kernel is full of gotos.
The issue of "boundary checks" is something else. For example:
In Ada, for example, accessing an array out of bounds "array[x]" can create an exception. Or a simple operation like "x = x + 1" can raise an exception. Sure you cannot do that in C or Spin.
The big gain here is that such exceptions are detected by the run time system or OS rather than silently happening and causing weird stuff to happen later on in execution. You really don't want to be checking an error code every time yo access an array or do an arithmetic operation.
That is to say "I can't do that" is better than "I did it, it might be wrong".
There are those that would argue that if these things are happening in your production code you have not performed enough testing and/or coverage analysis. That quad copter you are controlling is going to crash the same with error code checking or exceptions.
Is it ready yet?
How about now?
I have one cogs worth of FPGA to be getting on with.
Heart rate is up right now!!
I'm going to explore the Invaders code on mine tonight. I've had it off for a few weeks myself. Real life got in the way, and that mystery "why does the TV driver tear?" bug is still out there to get fixed...
@Chip: So am I.
Nice progress
BTW: I think the Prop2 identifies the technical name already with the DE0 emulator. But, I don't remember what it was...
P8X32C
We will take better pictures when we have more time, but we wanted to get you something to look at for now.
NOTE: The every-other-row placement is unexpected by us, and the structure placed in the "blank" rows is unknown. We are currently trying to figure out what that is. Chip thinks it may be a by-product of the MLR (multi-layer reticle) usage.
I believe that because we used a low-cost multi-layer reticle set, the fab's test structure was inserted into a blank chip space below each real chip.
If you look at the center area of the chip that looks like a dado blade, you can see 8 mild concentrations of wiring. Each one is the center of a cog.
Much like people ask what the 8186 processor was between the 8086 and 8286.
Chip, It looks like it's Spinning already.
If we're lucky we might actually get a P8x32B.
@__red__
What was the mystery about the 186? It was real. I was involved in a couple of projects that used the 80186. It was even used in some really cool "PC compatible" machines from Nokia complete with high res black and white displays, like early Macs, back when PC's were mostly 8086 and green screen text terminals.
Those Nokia machines were supplied as systems with 80286 boxes running xenix as the central file server.
The 80186 was mostly used for embedded systems but it was very popular for that purpose. It was very similar to the 8086 but had some additional on-board peripherals which made it easier to design with but less appropriate for a general purpose desktop system. I've put thousands of them in service in my little corner of industry.