PASM - Examples of each instruction anywhere?
bill190
Posts: 769
Is there any document which shows examples of how each PASM instruction might be used?
Like for the djnz instruction, it would show something like the following and explain that sub is subtracting 1 (Edit: 2, see below) each time through the loop, and so long as "Delay" has a value greater than 0, it will continue to loop. But when 0, it would continue on to the next line (not loop).
DJNZ
Perhaps examples like this, but for every assembly instruction, would be helpful?
Like for the djnz instruction, it would show something like the following and explain that sub is subtracting 1 (Edit: 2, see below) each time through the loop, and so long as "Delay" has a value greater than 0, it will continue to loop. But when 0, it would continue on to the next line (not loop).
DJNZ
:loop sub Delay, #1 djnz Delay, #:loop
Perhaps examples like this, but for every assembly instruction, would be helpful?
Comments
I recommend the one I wrote about MATH, many code examples are there explained.
propeller.wikispaces.org/MATH
Suggestions are welcome, of course.
I agree with Mike that you can find examples for most of the instructions in the Prop manual. It is interesting that it doesn't give an example for djnz where it describes that instruction, but there are several commented examples of djnz scattered throughout the manual. You just have to do a search in the Prop manual to quickly locate the examples.
BTW, your example of using djnz is a little "different". You are actually decrementing Delay twice in each pass through the loop. If Delay started out as an odd value the loop would never exit.
Dave
All the time I run into instructions that use wc and wz when I don't think they should, and don't use them when I do think they should. Of course, such uses are NEVER documented. They just sit there as a puzzle.
If I had more time, perhaps I would attempt to get to the bottom of the mystery. But I never seem to have the time. Instead I just copy and paste the relevant examples into my code and move on. I've finally realized that Parallax will never document things the way I think they should. One can either live with the documentation that exists or one can use a different chip.
The C and Z bits are results from the execution of the instruction and the way these results are calculated is documented in the Propeller Manual and datasheets. Whether you need these results for your code and how you might use them is a completely different question. It's not the responsibility of Parallax to document all the many different ways to use the various bits and pieces of the Propeller's instructions. It might be the subject of an advanced Propeller programming guide that goes into "did you notice that you could do this cool trick" sort of things.
Maybe you can cite the example that satisfies your needs? We might all learn something from that. I could be wrong, but I suspect you already know the example well and are entrenched in it. If the documentation is actually better than what Parallax has provided, maybe Parallax can learn something too.
http://ww1.microchip.com/downloads/en/DeviceDoc/70157D.pdf
Parallax needs to do something similar, especially if they wish to attract professional users.
I'm not sure how much more information is requried here. I've found it to be quite sufficient for developing on the Propeller.
Bill
Hey you found my timing problem!
I was using the quick reference and was thinking djnz was "do jump not zero"...
When all else fails, read the instructions...
I see it is "Decrement value and jump to address if not zero"!
So I don't even need the "sub Delay, #1" line.
Thanks for pointing that out!
I don't think professional users require the type of examples that Bill is asking for. The ALU and program sequencer portion of a COG is very straightforward. A profession user understands that the COG's processor is simply just a state machine that responds to each instruction and external inputs. I think the documentation of the instruction set in the Prop manual is more than adequate for a profesional user. However, there are other portions of the Prop that need more user documentation and examples, such as the use of the video registers.
With that being said, I do agree with your suggestion for inexperienced new users. A lot of newbies don't grasp the concept of how a microcontroller functions in detail. They rely more on examples than on the precise specification of an instruction. That's how I am with C++ code. I can modify C++ code, but I have difficulties writing it from scratch.
Dave
Edit: Bill, I'm glad I was able to help solve your timing problem.
Right. That is the type of thing I had in mind. With other documentation I have seen, they also show an example for each instruction.
Yesterday, in a Ron Czapala thread, kuroneko did a fantastic job of illustrating a couple of PASM instructions - and it hardly required any words. That's exactly and precisely what I wished existed for every instruction, directive, condition, and effect. If it did, the manual might be 50 pages instead of 400. And busy professionals wouldn't have to do so much sorting of words and piecing together of clues.
@Jazzed: When I have a bit more time I'll extract some of the specific code snippets that have been confusing to me, and post them here. I contemplated doing just that back when I encountered them, but simply didn't have the time then, either.
Perhaps examples could be located elsewhere? I was thinking to include them in the manual making it even larger.
Maybe this could be a forum thing? A topic area just for PASM instructions. No new topics allowed. And topics provided alphabetical starting with...
ABS
ABSNEG
ADD
ADDABS
Etc.
Then as people explain each of these in the regular forum, they could add their explanation in the PASM area in the appropriate topic too.
Over time each instruction would have an example and discussion in that area.
K2, I'm curious to know which implementations are confusing you.
Picking the ADD instruction, I find the Prop manual describes WC and WZ as follows:
Which seems pretty complete to me. It does not actually say the flags are unset (0) if the stated conditions are not met. But that seems like a natural assumption to me.
A beginner to programming might wonder what "an unsigned carry" might mean. But that's not where we are at, is it?
Comparing the PASM section of the manual to other instruction set documentation I have seen it stands up very well to me. Try finding out how exactly DAA behaves in the venerable Z80 microprocessor and you'll see that examples don't help:)
My personal wish is to have the PASM section of the manual in it's own separate document.
@Heater: Seems pretty complete to me too. Then I look at a piece of code where someone is using neither wc nor wz yet is conditionally branching. But the code works. So I copy the relevant line(s) into my code, and my code works too. Pretty soon I stop using the manual. Don't have the time for that sort of monkey business. I'm sure the answers are all there. Somewhere. Somewhere in 400 pages. But not on the page describing wc and wz. And not in any sort of quick-to-grasp form.
BTW, I vote for a separate PASM document, too.
Why not make an online asm examples wiki
http://en.wikipedia.org/wiki/Parallax_Propeller
If they are conditionally branching, then the code has to depend on Z and C for it's operation. And I bet if the code works Z and C are set (with wc/wz) somewhere.
There is no reason why wc/wz should be on the instruction immediately preceding the conditional branch. I for sure have code where the flags are set a long way away from where they are used.
So "copy the relevant line(s) into my code, and my code works too.", if they include conditional execution but are not setting the flags, is a sure recipe for disaster. Possibly seemingly random failures that you can't track down.
At that point you are doomed. Unless you have the capacity to remember every detail in the whole thing. Which I do not.
But didn't we just agree the descriptions of wc and wz were perfectly adequate and complete?
For example, in my AES-128 routines I originally had something like the following: The problem is the subroutine also used the flags. I had to reorganize my code to do the test twice. (And then later fix the tests because AND #4 didn't do what I needed.)
On most other microprocessors the flags are implicitly updated (and there's usually a few more of them), but on the Propeller you have to explicitly update the flags and explicitly make any instruction dependent on those flags. And because the Propeller only has two flags, for some instructions the Z & C flags may not be "result is zero" or "overflow/carry".
In most cases the 2 page instruction table in the Datasheet provides a good summary of the instruction and the flags. But I still want the manual if I want a little more detail.
Last week the problem was that the very first variable used in a DAT file was never initialized - neither in SPIN nor in ASM. Nowhere in the entire code listing. Come to find out, it's initialized in the cog loader inside the chip. Gee, I should have known that! How stupid can I be? How silly was I to look for it in the listing?! (Or the manual!)
Just now I find out that one might set an effect and then use it 100 lines of code later. Perhaps this little tidbit of relevant information is actually mentioned in the manual. I don't know. What search keywords would I use in Adobe Acrobat to track it down? How many false leads would I have to follow in the process?
The documentation is what it is. For many it would appear to be entirely adequate. Super.
EDIT: Here's a precious jewel just extracted from the Manual:
"For any effect not specified next to the instruction in code, the default behavior remains as indicated by the corresponding bit (Z, C, or R) in the ZCRI field of the instruction’s opcode."
The only draw-back for me now seems to be that I keep expecting to find such luxuries in the AVR instruction set
Was your DAT COG variable a LONG or a RES ? LONG (or WORD/BYTE) can be pre-initialized to any value, RES is a weird and different story.
It seems very clear to me. Perhaps there is too much information in the document and newbies are being overwelmed by it.
"The very first variable" - I don't understand. They are always initialized for me, as described for the COGINIT PASM instruction:
The second field, bits 17:4, holds the upper 14-bits of a 16-bit long address pointing to the desired assembly program to load into the cog. Cog registers $000 through $1EF will be loaded sequentially starting at this address, the special purpose registers will be cleared to zero (0), and the cog will start executing the code at register $000.
Doesn't that tell you that whatever you point the COGINIT instruction at will be loaded to COG. i.e initialized.
Hmmm, but if I turn the light on in my living room and then go out I expect it to still be on when I get back. Flip-flops are like that. If the documentation says Z or C is set only if WZ or WC is specified why would I assume that not to be true 1, 10 , 100, 1000 instructions later?
Some things just don't need writing down. If I say "A is true, B is true, C is true" should the reader assume that D, E, F... are also true. Should I specifically say it does not imply so? You are right, what is the search term for all those things that are not supposed to be in the book?
"For any effect not specified next to the instruction in code, the default behavior remains as indicated by the corresponding bit (Z, C, or R) in the ZCRI field of the instruction’s opcode."
Sounds clear to me, just check the ZCRI fields in the instructions opcodes.
Generally the Prop architecture, and the manual are renowned for the lack of "surprises".
Including the instructions opcode, the Z,C and R bits, the indirect bit and the condition bits there are 14 bits specifying each instruction.
That is 16384 different instructions/variants.
This "examples of each instruction" document is going to be huge:)
This is not unique to the Propeller. It's not particularly different from setting a mode variable somewhere in a program and testing it 1000 lines later. This type of programming has existed since the beginnings of programmable machines. Some computer architectures make it more useful as a programming technique and some do not. In the IBM360 series machines, the condition code was used so much for so many things that it was impractical to use it over much more than a few instructions. Almost all instructions would set it and changing it was not optional. In the case of the Propeller, you have to explicitly choose to set C and Z.
I think much of this boils down to learning style and learning preference. It's not the size of the book that matters, it's the characters in its contents right? :smilewinkgrin: ... And you can't just rely on one book to get the point across, you must study the subject at hand using multiple sources and cross-correlate the data from various sources in your head to be an effective programmer.
One of my favorite books ... "PC Assembly Language: Step by Step (Developer's Series)" (ISBN - 1-55755-096-4) which covers processors 8086,8088,80286,80386,and 80486 and is less descriptive by far than the Propeller manual but still a very effective tool. There are also many other books relating to the same subject I had to plow through before I had an aha moment.
... bottom line ... simply Study the information. It wasn't immediate for us at first, and still isn't at times. We all do it because it's a challenge less we forget.
6 bit opcode, 4 bit ZCRI flags, 4 bit condition, 9 bit destination register, 9 bit source register = 32 bits. The PASM ISA really is a matter of form follows function. The 4 condition bits mean every combination of the Z & C flags can be specified. The 9 bit source & destination means COG RAM can only be 512 words and why immediate values can only be 9 bits wide.
However, for the most part the flags ZC & I flags are the same across all instructions. The R flag is implicit with most opcodes being WR, but some NR. (i.e. TEST is AND NR). The condition codes are also the same for all opcodes save NOP which is implicitly if_never.
So there's no need to give examples for all 2^14 combinations, although there would be some value in showing how the flags can be used (i.e. CMPSUB NR for C:= D >= S).
There are also some unused opcodes and HUBOP uses the S value as an opcode extension.
It was a SPIN variable. Declared but never initialized. Its address was passed to PAR. First line of DAT used PAR to load a LONG. For a newbie to ASM, this does not aid comprehension of the SPIN/PASM interaction.
BTW, COGINIT is not used in the Object in question, and even if it were, how would I know to look at COGINIT for information on initializing variables in SPIN? Besides, I still wasn't sure how PAR worked....and a SPIN variable that was magically initialized didn't help explain it.
Back to my original comment re. wc and wz, I'm still not sure which it is. Does a prior use of wc and wz carry some sort of memory with it like Heater seemed to imply, or is the excerpt from the manual correct? Or can the two be rationalized?
"Including the instructions opcode, the Z,C and R bits, the indirect bit and the condition bits there are 14 bits specifying each instruction. That is 16384 different instructions/variants. This "examples of each instruction" document is going to be huge"
Let's not be disingenuous, Heater, I never asked for all combination and permutation of Z, C, and R. Furthermore, to suggest that since there isn't room for 16,384 examples there should be no examples is folly. "Just the basics, Ma'am."
I intend to address more of the comments made, but I'll have to do it later today.
I'm happy for you, Dave. But isn't it axiomatic that once you know something, it is clear?
Each COG has two bits of state (Z and C) in addition to the Program Counter. In many other microprocessors there are explicit registers which contain this state information. On the Prop each instruction can change the Z & C bits. Unlike many other microprocessors, on the Prop whether Z & C flags are changed (and the destination register) is under the control of the programmer.
For example the ADD instruction calculates S+D and implicitly updates D with the result, unless NR (not result) is specified. If WZ is specified, then the Z flag is set when the result is zero (e.g. $0000_0001 + $FFFF_FFFF) even if NR is also specified. If the result is not zero (and WZ is specified) then the Z flag is cleared. If WC is specified, then the C flag is set when an unsigned overflow occurs (e.g. $0000_0001 + $FFFF_FFFF), and cleared if not.
The condition codes (e.g. if_z) control whether an instruction is executed based upon the specified flags. For example:
Note: CMP is equivalent to SUB nr
Your missing the point of my comment. The "Explanation" part of each instruction description is clear to me. Here's the explanation for the DJNZ instruction. It states what the instruction does, and how the flags are affected if WZ or WC is specified. This is the same format that is used to describe all the instructions. K2, what part is not clear to you?
Dave
Explanation
DJNZ decrements the Value register and jumps to Address if the result is not zero.
When the WZ effect is specified, the Z flag is set (1) if the decremented Value is zero. When the WC effect is specified, the C flag is set (1) if the decrement results in an unsigned borrow (32-bit overflow). The decremented result is written to Value unless the NR effect is specified.
DJNZ requires a different amount of clock cycles depending on whether or not it has to jump. If it must jump it takes 4 clock cycles, if no jump occurs it takes 8 clock cycles. Since loops utilizing DJNZ need to be fast, it is optimized in this way for speed.