Shop OBEX P1 Docs P2 Docs Learn Events
How to use MOVD? — Parallax Forums

How to use MOVD?

MightorMightor Posts: 338
edited 2007-09-17 07:41 in Propeller 1
Hey peeps,

I have yet another ASM question...
I was looking at Beau's FunctionEngine code (Click ->here<- for thread, and ->here<- 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.

Comments

  • deSilvadeSilva Posts: 2,967
    edited 2007-09-15 18:51
    DeSilva explained it shortly in his Tutorial 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 smile.gif

    It is handy (and one could even say: neccessary!) for modifying addresses in instructions.
  • MightorMightor Posts: 338
    edited 2007-09-15 19:19
    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 [noparse]:)[/noparse] 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.
  • deSilvadeSilva Posts: 2,967
    edited 2007-09-15 19:21
    Well ':arg' is the cell where bits 9 to 17 are modified in, what else?
  • MightorMightor Posts: 338
    edited 2007-09-15 19:22
    I am trying to figure out what the point of that is [noparse]:)[/noparse]

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    | To know recursion, you must first know recursion.
    | I'm afraid I might be phobophobic.
  • deSilvadeSilva Posts: 2,967
    edited 2007-09-15 19:40
    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.
  • MightorMightor Posts: 338
    edited 2007-09-15 19:54
    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.
  • deSilvadeSilva Posts: 2,967
    edited 2007-09-15 20:03
    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 smile.gif )
  • MightorMightor Posts: 338
    edited 2007-09-15 20:11
    Now I am starting to get it [noparse]:)[/noparse] 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.
  • deSilvadeSilva Posts: 2,967
    edited 2007-09-15 20:22
    Right 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
    
  • MightorMightor Posts: 338
    edited 2007-09-16 06:42
    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' [noparse]:)[/noparse]

    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.
  • deSilvadeSilva Posts: 2,967
    edited 2007-09-16 07:14
    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...
  • MightorMightor Posts: 338
    edited 2007-09-16 07:26
    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 [noparse]:)[/noparse] 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 AllenTracy Allen Posts: 6,660
    edited 2007-09-16 19:25
    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
  • Fred HawkinsFred Hawkins Posts: 997
    edited 2007-09-16 19:50
    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?
  • deSilvadeSilva Posts: 2,967
    edited 2007-09-16 20:20
    WRT instruction pipeline look at the nice timeline in one of deSilva's "Sidetracks" 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".
  • MightorMightor Posts: 338
    edited 2007-09-17 03:53
    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&#8230;
    ' &#8230; will be modified by (*)
    ADD :access, #1 ' modify a cell to point to the next number
    DJNZ count, #:loop
    &#8230;
    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.
  • deSilvadeSilva Posts: 2,967
    edited 2007-09-17 06:40
    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 AllenTracy Allen Posts: 6,660
    edited 2007-09-17 07:26
    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
  • MightorMightor Posts: 338
    edited 2007-09-17 07:41
    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 [noparse]:)[/noparse]

    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 [noparse]:)[/noparse] 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.
Sign In or Register to comment.