MOVS, MOVD, MOVI, and MOV
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:
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:
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
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
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.
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
Welcome to PropellerLand! Great to see you on board! Looking forward to your contributions.
Paul
@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 Allen
www.emesystems.com
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