The instruction set

All instructions are 16 bits long, and there are only three instruction formats:

000100OpcodeB/WAdDest reg
001ConditionPC offset (10 bit)
OpcodeSource regAdB/WAsDest reg

As and Ad are the source and destination addressing modes. B/W is a bit that is set to 1 for byte instructions. 2-operand opcodes begin at 0100 = 4.

As you can see, there are at most 8+8+12 = 28 instructions to keep track of, which is nice and simple.

One-operand instructions:

000RRC(.B)9-bit rotate right through carry. C->msbit->...->lsbit->C. Clear the carry bit beforehand to do a logical right shift.
001SWPBSwap 8-bit register halves. No byte form.
010RRA(.B)Badly named, this is an 8-bit arithmetic right shift.
011SXTSign extend 8 bits to 16. No byte form.
100PUSH(.B)Push operand on stack. Push byte decrements SP by 2. CPU BUG: PUSH #4 and PUSH #8 do not work when the short encoding using @r2 and @r2+ is used. The workaround, to use a 16-bit immediate, is trivial, so TI do not plan to fix this bug.
101CALLFetch operand, push PC, then assign operand value to PC. Note the immediate form is the most commonly used. There is no easy way to perform a PC-relative call; the PC-relative addressing mode fetches a word and uses it as an absolute address. This has no byte form.
110RETIPop SP, then pop PC. Note that because flags like CPUOFF are in the stored status register, the CPU will normally return to the low-power mode it was previously in. This can be changed by adjusting the SR value stored on the stack before invoking RETI (see below). The operand field is unused.
111Not usedThe MSP430 actually only has 27 instructions.

The status flags are set by RRA, RRC, SXT, and RETI.

The status flags are NOT set by PUSH, SWPB, and CALL.

Relative jumps. These are all PC-relative jumps, adding twice the sign-extended offset to the PC, for a jump range of -1024 to +1022.

000JNE/JNZJump if Z==0 (if !=)
001JEQ/ZJump if Z==1 (if ==)
010JNC/JLOJump if C==0 (if unsigned <)
011JC/JHSJump if C==1 (if unsigned >=)
100JNJump if N==1 Note there is no "JP" if N==0!
101JGEJump if N==V (if signed >=)
110JLJump if N!=V (if signed <)
111JMPJump unconditionally

Two-operand instructions. These basically perform dest = src op dest operations. However, MOV doesn't fetch the destination, and CMP and BIT do not write to the destination. All are valid in their 8 and 16 bit forms.

Operands are written in the order src,dest.

0100MOV src,destdest = srcThe status flags are NOT set.
0101ADD src,destdest += src 
0110ADDC src,destdest += src + C 
0111SUBC src,destdest += ~src + C 
1001SUB src,destdest -= srcImplemented as dest += ~src + 1.
1001CMP src,destdest - srcSets status only; the destination is not written.
1010DADD src,destdest += src + C, BCD. 
1011BIT src,destdest & srcSets status only; the destination is not written.
1100BIC src,destdest &= ~srcThe status flags are NOT set.
1101BIS src,destdest |= srcThe status flags are NOT set.
1110XOR src,destdest ^= src 
1111AND src,destdest &=- src 

There are a number of zero- and one-operand pseudo-operations that can be built from these two-operand forms. These are usually referred to as "emulated" instructions:

NOPMOV r3,r3Any register from r3 to r15 would do the same thing.
POP dstMOV @SP+,dst 

Note that other forms of a NOP instruction can be constructed as emulated instructions, which take different numbers of cycles to execute. These can sometimes be useful in constructing accurate timing patterns in software.

Branch and return can be done by moving to PC (r0):

BR dstMOV dst,PC

The constants were chosen to make status register (r2) twiddling efficient:


Shift and rotate left is done with add:

RLA(.B) dstADD(.B) dst,dst
RLC(.B) dstADDC(.B) dst,dst

Some common one-operand instructions:

INV(.B) dstXOR(.B) #-1,dst
CLR(.B) dstMOV(.B) #0,dst
TST(.B) dstCMP(.B) #0,dst

Increment and decrement (by one or two):

DEC(.B) dstSUB(.B) #1,dst
DECD(.B) dstSUB(.B) #2,dst
INC(.B) dstADD(.B) #1,dst
INCD(.B) dstADD(.B) #2,dst

Adding and subtracting only the carry bit:

ADC(.B) dstADDC(.B) #0,dst
DADC(.B) dstDADD(.B) #0,dst
SBC(.B) dstSUBC(.B) #0,dst