PDA

View Full Version : How to use MOVD?



Mightor
09-16-2007, 02:13 AM
Hey peeps,

I have yet another ASM question...
I was looking at Beau's FunctionEngine code (Click ->here (http://forums.parallax.com/showthread.php?p=605325)<- for thread, and ->here (http://forums.parallax.com/attachment.php?attachmentid=43265)<- for attachment) and I tried very hard to figure out what it is that movd does. Here's a little snipped of the relevant code:



' Function Engine - main loop
'
loop rdlong t1,par wz 'wait for command
if_z jmp #loop

movd :arg,#arg0 'get 8 arguments
mov t2,t1
mov t3,#8
:arg rdlong arg0,t2
add :arg,d0
add t2,#4
djnz t3,#:arg



Well, at least I hope this is all of the relevant code, in any case both the thread and attachment are up ^ there. So my question is, what does this movd do and more importantly what does it cause?

I am basically trying to graft the setcommand code into my own to allow for more control over the PWM signals generated by my code. However, rather than trying to copy this stuff verbatim, I'd much rather have at least a basic grasp of what it does (in case it's not working as I want/need it to).

Gr,
Mightor

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
| To know recursion, you must first know recursion.
| I'm afraid I might be phobophobic.

deSilva
09-16-2007, 02:51 AM
DeSilva explained it shortly in his Tutorial http://forums.parallax.com/images/smilies/smile.gif Have a look at the example where 4 bytes are trickily put into a long! But it could be elaborated on it...

MOVED exactly and only replaces bits 9 to 17 in the "dest" with the lowest 9 bits of the "source"; this is similar to MOVS which does it with bits 0 to 8 and MOVI with bits 23 to 31. Can you guess why it's called D, S, or I respectively http://forums.parallax.com/images/smilies/smile.gif

It is handy (and one could even say: neccessary!) for modifying addresses in instructions.

Mightor
09-16-2007, 03:19 AM
deSilva,

Yeah, I can understand what you do in example ex08A, but what I don't get is what that label :arg is doing in that movd in the FunctionEngine code. The same applies that what you do in ex07C in your tutorial. I am missing something, no coin is dropping for me :) Instead of nice brightly lit bulb over my head, I get a slight short, some smoke and not much else.

Gr,
Mightor

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
| To know recursion, you must first know recursion.
| I'm afraid I might be phobophobic.

deSilva
09-16-2007, 03:21 AM
Well ':arg' is the cell where bits 9 to 17 are modified in, what else?

Mightor
09-16-2007, 03:22 AM
I am trying to figure out what the point of that is :)

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
| To know recursion, you must first know recursion.
| I'm afraid I might be phobophobic.

deSilva
09-16-2007, 03:40 AM
As deSilva explained with many (well: a few, to be honest) examples in his Tutorial, this is the only way to do "indexed addressing" inside the COG.
When you don't know the address where to read from/ write to , then you have to compute it and put it into the appropriate position INSIDE AN INSTRUCTION.

Mightor
09-16-2007, 03:54 AM
Ah now we're getting somewhere! Indexed addressing is what it can be used for. Why would this be better than just adding an offset to the start address of the variable in question with regular mov? I am still not sure why you would manipulate the label name's inner value. Sorry deSilva, no light bulb yet!

Gr,
Mightor

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
| To know recursion, you must first know recursion.
| I'm afraid I might be phobophobic.

deSilva
09-16-2007, 04:03 AM
Mightor said...
I am still not sure why you would manipulate the label name's inner value.


There is no such thing as a "label name's inner value". A label is nothing but a number the compiler has learnt by heart - when it has encountered it at the start of a line - and uses every time you write down that "label".

When you use that label in the dest position of a MOV it will be interpreted as the cell number to be totally changed.
When yu use the label in the dest position of a MOVD, only the bits 9 to 17 in that cell will be changed.

So when it happens this label is a label in front of an instruction, this instruction will be changed.
In our case, the "addresses" (= cell numbers) of cells "arg0", "arg0+1",.... "arg0+7" are stored into the RDLONG instruction so that it will exactly read into that COG cells.

There is no other way to do it! (Sorry, no Perl http://forums.parallax.com/images/smilies/smile.gif )

Mightor
09-16-2007, 04:11 AM
Now I am starting to get it :) I didn't realise it edited the rdlong command, I thought it somehow tweaked the :arg label as it would a normal variable. Anyway, confusing is gone now. I also get what the d0 ($200) variable is for now, it basically adds "1" to the arg0 address, to make rdlong read the next one, right?

Gr,
Mightor

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
| To know recursion, you must first know recursion.
| I'm afraid I might be phobophobic.

deSilva
09-16-2007, 04:22 AM
Right http://forums.parallax.com/images/smilies/smile.gif The most popular modifications are



MOVS instr, #cogcellA
MOVD instr, #cogcellB
ADD instr, #1
ADD instr, a_one_in_dest

....
instr: MOV 0-0, 0-0

...
a_one_in_dest LONG %1_0_0000_0000

Mightor
09-16-2007, 02:42 PM
I finally have a clearer picture of how this MOVD/MOVS stuff works now and what the point of it is. The Prop manual just tells you what it does and your tutorial seems to just show how to write code with it but doesn't explain it in depth. Do you think you could include a couple of examples and explanations of self-modifying code in your next release of the tutorial, perhaps using a concrete, real-world example, like Beau's setcommand code? Or perhaps Beau could write some explanatory comments (more than 'get 8 arguments' :)

I'd really love a HOWTO/Tutorial on this self-modifying code stuff with some heavily commented code and real-life examples and pointers to when and when not to use those 'tricks'. I can't be the only one who struggles with this stuff.

Thanks!

Gr,
Mightor

PS: deSilva, not sure if I told you already, but my PWM code now works like a charm, I've been testing it with LEDs and a L293D dual H bridge. The point of this setcommand stuff is to allow me to set pins for direction from inside ASM, based on commands sent from SPIN. I'd like to have commands like setDirR and setDirL, setSpeedR and setSpeedL.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
| To know recursion, you must first know recursion.
| I'm afraid I might be phobophobic.

deSilva
09-16-2007, 03:14 PM
Good to hear!
Your feedback on the tutorial is especially valuable, as I have not foreseen such difficulties....
There have been good reasons I warned the "total beginner".. I think (no, I am sure!) the reader I imagined was someone having already some experience with machine coding from another micro...

Mightor
09-16-2007, 03:26 PM
Yeah, the problem is that there's a guide for the total beginner and one for someone with some experience already and nothing in between :) I think your guide could fill that gap in the middle and would be a major asset to this community if it did. I am sure that it wouldn't take more than slightly more verbose explanations and a little more hand-holding and move some of the more complex stuff like self-modifying code right to the back of the guide. With a little extra help from you and some of the others on the forums, even I managed to work my way through most of it and I had NO ASM experience at all. If the essence of those conversations could be incorporated into the guide, like for example the "using movd for indexing" thing, all of a sudden it becomes more than just a weird operator that does some bit magic, it becomes a tool that can accomplish a concrete task. I am a person who learns from example, abstract specifications don't always work for me.

Gr,
Mightor

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
| To know recursion, you must first know recursion.
| I'm afraid I might be phobophobic.

Tracy Allen
09-17-2007, 03:25 AM
Mightor said...
Ah now we're getting somewhere! Indexed addressing is what it can be used for. Why would this be better than just adding an offset to the start address of the variable in question with regular mov? I am still not sure why you would manipulate the label name's inner value. Sorry deSilva, no light bulb yet!

Gr,
Mightor


I'll jump in here to comment that the self modifying code is not just "better than just adding an offset to the start address...", because that might imply that there is some other way to do it. No, the only way to do it on the Prop, AFAIK, is via self-modifying code. So because indexing is such a basic operation, the self-modifying code should not be considered advanced, and once you get used to it, it is not that complex either. It's just different.

To clarify it further, note that the destination field of any MOV (or any instruction that writes to a destination register) can only be a direct reference to a specific register from 0 to 511. The only way to index it is to stuff a new value into the destination field of the instruction itself. It works on the Prop because code is always executing from RAM.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Tracy Allen
www.emesystems.com (http://www.emesystems.com)

Fred Hawkins
09-17-2007, 03:50 AM
or (more perversely and accurately) code is always stored and executed in the register space.

Mightor, there's one trap here: you can't change an source or destination of the code immediately after your current instruction. Not that they won't change, but because
they have already been fetched to the instruction pipeline. (2 deep, I think. Current and next instruction)

Wonder if this behavior could (has been) exploited for a auto-incrementing stack?

deSilva
09-17-2007, 04:20 AM
WRT instruction pipeline look at the nice timeline in one of deSilva's "Sidetracks" http://forums.parallax.com/images/smilies/smile.gif

And no, this behaviour cannot be exploited, because you always need a second instruction, and that would not be called "auto".

Neither can I imagine a situations where you should need such a specific "post-increment".

Mightor
09-17-2007, 11:53 AM
K, now I'm *really* starting to get it. The fact that the destination field is a register address from 0-511, does that mean why in the following piece of code



'ex07B
MOV addr, X
MOV sum, #0
MOV count, #20
:loop
RDLONG r, addr
ADDS sum, r
ADD addr, #4 ' the next long
DJNZ count, #:loop



4 is added to addr because rdlong takes a byte address as its argument and a long is 4 bytes big?

In the following piece of code:



'ex07C
' we assume X to X+19 contain 20 longs to be added up
MOVS :access, #X ' this instruction modifies a COG cell (*)
MOV sum, #0
MOV count, #20
:loop
:access
ADDS sum, 0-0 ' the lower 9 bits of this instruction…
' … will be modified by (*)
ADD :access, #1 ' modify a cell to point to the next number
DJNZ count, #:loop

X: RES 20



you only add one to the src address because it refers to a register between 0-511?

I think if this is really the only way to indexed addressing in ASM in the Cog RAM then it really warrants a bit more explanation in all the documents I've come across. deSilva, I know you mentioned the fact that you can't change the next operation but you never explicitly say why that is. Perhaps you can add that to your tutorial as well. I didn't realise it was because of the way instructions are fetched. Now that I do know, it makes sense, but before it was just a rule with no (apparent) reason.

Gr,
Mightor

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
| To know recursion, you must first know recursion.
| I'm afraid I might be phobophobic.

deSilva
09-17-2007, 02:40 PM
Have a look at the Sidetrack F, pp. 23/24. If it does not contain a sufficient explanation, I shall add things to it.. But what?

Tracy Allen
09-17-2007, 03:26 PM
Mightor, Your surmise about adding 4 in one case and adding 1 in the second case is correct. Hub longs in multiples of 4, cog ram always longs.

There is a difference between the move and math instructions on one hand and the branch and hub access commands on the other. In the move and math instructions, the source and destination arguments (0-511) point to a register and it is the value from that register that is used in the operations. (Also, of course the source can be a literal value that is used directly in the operation.) There is no redirection, where the value in the register is in turn used as a pointer to somewhere else. Thus, indirect addressing and indexing require self-modifying code tricks.

On the other hand, an exception, in hub access commands like RDLONG, a reference is made to a register that contains a pointer to a location in hub ram. So the routine you started with only has to increment a variable by 4 to move through a block of addresses of longs in the hub. No fancy self-modification there. The RDLONG can also use an immediate source argument, but that is only capable of accessing 512 bytes at the low addresses in the hub.

Another sort of exception is the branch commands like jmp. An immediate source argument like {jmp #loop} points directly to the jump destination, while a register reference like {jmp hoops} is a pointer to a pointer, that is, the value contained in the register, hoops, points to the jump destination. Things get interesting with subroutinish instructions like jmpret and call,. The Prop can use self-modifying code for returns, or it can use indirect pointers through registers to keep several threads running, as seen in fullduplexserial.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Tracy Allen
www.emesystems.com (http://www.emesystems.com)

Mightor
09-17-2007, 03:41 PM
deSilva,

That explanation in Sidetrack F is fine, I think I misunderstood it at first and never looked at it again. I just had a problem with ex07C. Maybe if you could mention explicitly that "MOVS :access, #X" puts the address of X into the source of the "ADDS sum, 0-0" instruction. Also maybe explain what 0-0 means. I was also a little confused about why you'd only add #1 to the address, instead of 4, like you would for the addresses in the HUB. If you could mention that a little more explicitly, that'd be great.

Now that I know what is going, it makes a lot more sense and I can see how it's a fairly simple mechanism, but it's not so obvious if you're stumbling across it for the first time. There is a lot of info coming at you when you're starting out with ASM and it can be quite overwhelming. When I look at it with the knowledge I have now I'm like "Why didn't I get it before?".

I think it would be a real boon to this guide if you could take that code of Beau's and add it to the guide with a very thorough explanation of what happens in it. It's something that people will definitely need for more complex ASM programs. ex08A is nice but it's only manipulating a variable, not an instruction. It might also be a good thing to mention that for cog-memory indexed stuff, this self-modifying code is the ONLY way to do it and that TIMTOWTDI does not apply here :)

Assuming your reader can figure out a lot of the implicit (and seemingly obvious) things may lead to the reader wrongly assuming he understood what you wrote :) Being explicit may be a little boring at times, especially for the author, but it can really reduce confusion.

Gr,
Mightor

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
| To know recursion, you must first know recursion.
| I'm afraid I might be phobophobic.