Shop OBEX P1 Docs P2 Docs Learn Events
MOVS, MOVD, MOVI, and MOV — Parallax Forums

MOVS, MOVD, MOVI, and MOV

Chuck McManisChuck McManis Posts: 65
edited 2008-02-05 23:00 in Propeller 1
Color me dense but I just figured out what was going on with these instructions. Sometimes it takes like 8 readings of the documentation to finally get things to sink in.

If I may, I'd like to suggest some additional description around these opcodes that goes something like:

Assembler: Moving Things Around

Each COG has 512 32-bit memory values associated with the COG (alternatively called memory and registers in different places). Each location is capable of holding an instruction for the COG to execute, or data to be used by the program executing on the COG. Each 32 bit location in memory is separated into three sections, the Instruction section, the Destination section, and the Source section. There are assembler opcodes available to write any one section or all three at once.

The MOV operation

Equivalent function (D) <- (S)

The MOV opcode moves its source to the destination. If the source is an immediate operand (of the form #value) then the lowest 9 bits of the destination gets set to value and the upper 23 bits are cleared to zero. If the the source is an address (9 bits addresses all 512 locations of COG memory) then the contents of that address is moved to the destination, all 32 bits.

The MOVS operation

Equivalent function (D) <- (D & 0xFFFFFE00) | ((S) & 0x000001FF)

The MOVS instruction is similar except that rather than copying all the bits from the source to the destination it only overwrites the lower 9 bits (the source). So if the source operand to this opcode is an immediate operand of the form #value then the 9 bits of value replace what ever was in the lower 9 bits of destination without changing the upper 23 bits.. This latter point is important. In some assembly languages you might have an indirect bit which uses the contents of one location to address another, on the Propeller you modify the instruction on the fly with the new source. So the following loop:
DAT

entry   MOV     temp3, #Index   ' Load the address of Index into temp3
           MOVS   :loop, temp3      ' Modify the instruction at label :loop to point at Index (Note 1)
           MOV     temp1, #32        ' Create a 32 iteration loop
:loop    MOV     temp2, Index     ' Load a value into Temp2
           MOV     temp3, :loop      ' Load the instruction from :loop into temp3 
           ADD     temp3, #1          'Now temp3 has the instruction but its pointer has been incremented
           MOVS   :loop, temp3       'Now the instruction at :loop has been modified to load the next long (Note 2)
           ... do something with temp2 ... ' your program uses the value from the array
           DJNZ    temp1, :loop      ' Now loop back to :loop and get the next value

temp1  LONG    0
temp2  LONG    0
temp3  LONG    0
Index   LONG   $foof000           ' Value of array at [noparse][[/noparse]0]
           LONG   $deadbeef         '              ...     at 
           LONG   $0coffee0          '              ...     at 
           ... repeated for 29 more values ...
           FIT                              ' Make sure everything fits



There are two important points to remember from this code, the first is that the initial loading of the address of Index into :iloop has to happen at least two instructions before you get to :iloop other wise the propeller will have pre-fetched that value and it won't be executed as changed. It is always safe to change an instruction "behind" you in your code.

The second important point is to remember is that even though the code read the entire instruction at :loop, when :iloop is written with only the lower 9 bits are changed.

The MOVD operation

Equivalent function (D) <- (D & 0xFFFC01FF) | ((S & 0x000001FF) << 9)

The MOVD instruction works exactly like MOVS except that it changes the 9 destination bits rather then the source bits. The lower 9 bits of the value are shifted left by 9 bits and replace the 9 bits occupied by the destination reference in the destination address. An example of how this code might be used is as follows:

DAT

entry   MOV     temp3, #Buffer   ' Load the address of the buffer into temp3
           MOVD   :loop, temp3      ' Modify the instruction at label :read to point at Index (Note 1)
           MOV     temp1, #16        ' Create a 16 iteration loop
:loop    MOV     Buffer, OUTA      ' Read a value from OUTA and store it in the buffer
           MOV     temp3, :loop       ' Load the instruction from :loop into temp3 
           SHR     temp3, #9           ' Move the buffer address into the lower 9 bits
           ADD     temp3, #1          '  Increment the address to point to the next buffer location
           MOVD   :loop, temp3       ' Now the instruction at :loop has been modified store the the next read (Note 2)
           DJNZ    temp1, :loop      ' Now loop back to :loop and get the next value
           ... do something with Buffer ... ' your program uses the 16 values read from OUTA and stored in the array

temp1  LONG    0
temp2  LONG    0
temp3  LONG    0
Buffer  RES      16                    ' Reserve 16 long words off buffer space.
           FIT                              ' Make sure everything fits




It is different than the MOVS example in that now we have to shift the destination address into the low order 9 bits to increment it, but other than that it is very similar. As with MOVS you cannot modify the next instruction to be executed because it has already been prefetched by the Propeller.

The MOVI operation

Equivalent function: (D) <- ( D & 0x007FFFFF) | ((S & 0x000001FF) << 23)

The MOVI opcode moves the 9 bits either contained in its source location or the 9 bits in the instruction (if the immediate operator is used) into the upper 9 bits of the destination. These bits determine the operation code of the destination. However the nine bits only cover the operation code and the effects flags, they do not cover the immediate bit or the condition bits you cannot retroactively change those properties with this instruction.

Sorry but I can't think of a good reason to MOVI yet. Still working on it.

--Chuck

Comments

  • deSilvadeSilva Posts: 2,967
    edited 2008-02-05 10:49
    Very good examples, Chuck. Most covered in my Tutorial of course smile.gif but not sooo explicit.

    Cases for generating instructions are rare. However this a very powerful technique!!
    Sometimes it can be convenient to modify an opcode, as exchanging SHL or SHR depending on the situation,
    withour dupliocating the code.

    In most published cases, MOVI is used to set DATA.
    You might have noticed that many LONG bit-structures are arranged in a 9+5+9+9 fashion.
  • hippyhippy Posts: 1,981
    edited 2008-02-05 11:27
    Hi Chuck ( and a very belated thank you for your decoding of the BS1 ! )

    Three things worth mentioning -

    1) Due to processor pipe-lining there must be at least one instruction executed before an instruction
    modified by MOV, MOVD, MOVI and MOVS is executed ( your example code is okay on that point ).

    2) The form "0-0" ( zero-minus-zero ) is often used to indicate a source or destination register that
    is modified by another instruction. I don't know who to credit for that idea, but I find it works very
    well for me.

    3) There is the Propeller Wiki where everyone is more than welcome to add any information useful
    to other Propeller programmers and users.

    propeller.wikispaces.com
  • Paul Sr.Paul Sr. Posts: 435
    edited 2008-02-05 13:01
    Chuck,

    Welcome to PropellerLand! Great to see you on board! Looking forward to your contributions.

    Paul
  • Chuck McManisChuck McManis Posts: 65
    edited 2008-02-05 17:43
    @deSilva Yes, you do cover it in your tutorial which, between reading that, the manual, and your example in the "Fast Wavesforms to a DAC" thread finally broke through my thick head as to what was going on! I wanted to pull out just this specific bit of knowledge into its own spot because the indirect addressing idiom is very common in most assembly language programs and it takes three documents to figure out how to do it! Your help here is invaluable.

    @hippy The 0-0 syntax I've seen it as well and at the time it was pretty opaque to me, now it makes more sense. As a "don't care" value it works fairly well. Also I pointed out the pipelined fetch concern above in the example but perhaps it should be called out more explicitly. (or emphasized with bold or italic letters). Oh and you're welcome of course on the BS1 stuff, I'm always amazed at how many hits it still gets on my web site.

    --Chuck
  • Tracy AllenTracy Allen Posts: 6,662
    edited 2008-02-05 18:28
    I just updated the pointer on my links web page, to your decoding the BASIC Stamp article. I got a lot out of that too, and I'm sure it inspired Brian Forbes in his book on the Stamp II. There have been a few efforts in a similar direction here. I don't have the references close at hand. It does help to know how the gears are turning inside!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Tracy Allen
    www.emesystems.com
  • deSilvadeSilva Posts: 2,967
    edited 2008-02-05 23:00
    @Chuck: Good to hear my Tutorial helped smile.gif
    In fact I feel silly from time to time, when people say they never understood video, or this, or that....
    Or: This is not in Propeller doc or that...

    This is why I wrote the "Tutorial", now many monthes ago... I just read through my own Chapter 7.. Interesting work, I must say smile.gifsmile.gif
Sign In or Register to comment.