# The DS5000 Instruction Set Description

As I promised, in an earlier lesson, I am going to go through an in-depth explaination of ALL the DS5000 instructions. I need to do this before I go any further in my explaination of BEGIN2.ASM, so you can better understand it.

In these descriptions, several things are used throughout, that I need to explain, to make it all clearer. Here they are:

Rn - is one of the eight possible registers in the current register bank. Remember, there are four possible banks of registers, one of which is the currently selected bank. Each bank has 8 registers (r0-r7) that can be used.

direct - is one of the 256 possible direct addresses in the internal RAM of the DS5000. Remember that the DS5000 has two distinct sections of memory. One is the on-board internal RAM, which has 256 addresses, the first 128 being the scratchpad RAM (00-7fh), and the last 128 being the Special Function Registers (80-ffh). The other is the external RAM, of which, in our case, has 32,768 addresses (0 - 3fffh). There are a few instructions that can have two direct addresses. They are referred to as direct1 and direct2.

rel - is a relative offset from the next instruction's address. This can be +/- 127 from that address. Remember that the PC is incremented when the current instruction is loaded, so the offset is relative to the address of the next instruction. This doesn't matter to you, the programmer, because the assembler calculates this address based on the address of the label you placed in the instruction, referring to the relative address in question. I tell you this only for your complete understanding of what happens, and I hope it doesn't confuse you. Relative addressing is confusing if you are having to calculate the offset yourself, like I did in the past, before I started using an assembler. The assembler will, however, give an error if you try to reference an address further than +/- 127 from the next instruction's address.

Ri - is one of the two registers, in the current bank, that can be used to index (point to) an internal RAM location. This can be either r0 or r1. Only these two can be used, and is a hardwired feature of the DS5000.

#data - is immediate 8 bit (byte) data. This means that the instruction contains this data. In the case of a mov a,#data , a two byte instruction, the first byte is the mov a, command and the second byte is the data. In this case, that data would be placed in the accumulator.

#data16 - is immediate 16 bit (2 byte) data. This is used with instructions to load a 16 bit register, like dptr, with an address. The dptr is the only 16 bit register to use this type of data.

@ - means "at the address pointed to by". An example would be add a,@r0. This would add the contents of the accumulator, to the data at the address in internal RAM, pointed to by r0, and store the result back into the accumulator.

bit - is a single bit, within a bit addressable byte, in the internal RAM. Remember that the internal scratchpad RAM is divided up functionally into different sections. The first 32 bytes hold the 4 register banks, each with 8 registers. The next 16 bytes are the bit addressable locations, each location having 8 bits, for a total of 128 bits. These represent bits 00-7fh. These can be assigned labels with the .equ assembler directive, so that you don't have to remember their values. The value for a particular bit is determined by which bit position, in which byte, is being referenced. Bit 0, of the first bit addressable byte, is bit 00h. Bit 7, of the last bit addressable byte, is bit 7fh. There are also several bit addressable locations in the Special Function Registers. These occupy bit addresses 80-ffh, making a total possible of 256 bit addresses.

/bit (actually bit with a bar over it) - is the complement of a bit. I can't type something with a bar over it here, but it does exist. It simply means that if the actual state of a particular bit is 0, this would return a 1 instead. I've never used this feature, but it's there, none the less.

addr 11 - is an 11 bit, absolute, address. This is a somewhat diffult concept, but here goes. The actual addressing within the DS5000, with the exception of internal RAM, is 16 bits. This allows for 65,536 unique addresses. Using 11 bit addressing limits the number to 2048 (2K). To use this type of addressing, the assumption is made that the effected address resides within the 2K block you are currently in. There are thirty-two 2K blocks of memory inside the DS5000 address range, looking at it this way. The first is 0000-07ffh, the second is 0800-0fffh, the third is 1000-17ffh, and so forth. I never use this type of addressing, due to the problem of knowing which 2k block a particular instruction, or label, is in. Since, using an assembler, you don't know which actual address any particular instruction or label is at, it makes it risky to use this kind of addressing. The instruction takes the same amout of time to execute as a long address (16 bit) and the only savings is 1 byte of program memory. I guess if you were pressed for space, you could use this type of addressing, but I have never been pressed into that corner, so far.

addr 16 - is a 16 bit, long, address. This can be any address within the address space of the DS5000. This addressing takes a 3 byte instruction, as opposed to 2 bytes for absolute addressing.

( ) - means "the contents of". For instance (A) means the "contents of the accumulator".

(( )) - means "the contents of the location pointed to by the contents of". For instance ((Ri)) means the contents of the location pointed to by the contents of Ri.

Lastly, when using an assembler, a label can be assigned to any direct location, bit location, long address, absolute address, or relative address in the DS5000, so that you refer to it by the name instead of the actual value. This makes things much easier to keep up with. The following descriptions don't use this, but remember it's there.

Also, the assembler has some hardcoded names that can be used to refer to different bits and direct addresses in the Special Function Registers. For instance bit 0 of the accumulator (direct bit address e0h) is referred to as acc.0 .

There are four flags in the DS5000 that indicate various conditions as the result of an instruction. These are the C (carry), AC (auxillary carry), OV (overflow), and P (parity) flags.

C  is set by either an overflow or underflow of the accumulator. If you add a number to the accumulator that results in a number greater than 255 (ffh), a carry will result. If you subtract a larger number from a smaller number, a borrow will result. If neither of these happen, the carry flag will be cleared. The carry flag can also be set, cleared, or complemented by boolean instructions.

AC is set when the previous operation resulted in a carry (addition) or a borrow (subtraction) from the high order nibble. This is used for BCD arithmetic.

OV is set when when a carry was generated into the high order bit, but not a carry out of the high order bit, or if there was a carry out of the high order bit, but not a carry into the high order bit. It is normally used in 2's complement arithmetic. OV is also set if a divide by zero was executed.

P is set if the modulo-2 sum of the eight bits of the accumulator is 1 (odd parity). It's cleared if even parity. This is an extravagant way of saying that if you add up the number of 1's in the accumulator, and they come out odd, P is set. If there is an even number, P is cleared.

There is one more flag (F0) that can be set by software for whatever purpose. It's really just another bit to twiddle, but it gets saved when the PSW is pushed.

All these flags reside in the PSW (Program Status Word) register. Here is how they are laid out.

PSW.0 (PSW bit 0) is P
PSW.1 is unused
PSW.2 is OV
PSW.5 is F0
PSW.6 is AC
PSW.7 is C

PSW.3 and 4 indicate what register bank is currently selected. PSW.3 is the low order bit and PSW.4 is the high order bit.

00 is bank 0
01 is bank 1
10 is bank 2
11 is bank 3

This is how the register bank is selected. You load the PSW with the value that corresponds to the register bank you want to select. a 00h selects bank 0, 08h selects bank 1, 10h selects bank 2, and 18h selects bank 3. At power up or after a reset, bank 0 is always selected, until you select another. The main reason to use bank switching is to allow for faster ISR's or subroutines and also lessen the need for a larger stack. By using a register bank to hold most of the variables used by a particular routine, that runs a lot, extra pushes and pops can be avoided that would have saved and restored these variables in the stack, also saving precious machine cycles.

I typically use bank 0 for the operating loop, and many of the subroutines. I use another bank for the RS-232 ISR, another for the 120 Hz ISR, and another for whatever.

The stack is a portion of internal RAM (typically towards the end of RAM) that is used for temporary storage of addresses and data. When a call or interrupt happens, 2 bytes are pushed for the return address. Then as many bytes as needed are also pushed, to save their contents, for the return. This usually includes the accumulator, since it's used by so many instructions, and the PSW, since it holds the state of which bank is being currently used and may be holding some flag contents that will be needed upon return from the routine. This means that, at a minimum, 4 bytes will be pushed for every interrupt or subroutine routine. If the stack overflows (runs out of internal RAM), your system is basically toast, and mumbles off to mama every time. So the stack is made as large as possible.

When the system boots up, the SP register is initialized to an address. This is called the "top of the stack". From that point on, the stack "grows downward" for each push (towards the end of RAM). As addresses and data are "popped off" the stack, those bytes are freed up, to be used again. The problem is that you may be inside a subroutine, when an interrupt occurs, and that ISR may be interrupted by a higher priority interrupt. Each of these events caused the stack to grow deeper. As each finishes, the addresses and data are popped off the stack, and eventually it returns to the top of the stack again. The trick is make enough room for as deep as the stack might ever get, without running out of memory. This is usually not a problem, but it must be considered, and enough room allowed for the stack to grow.

The instructions of the DS5000 are divided into five types. They are Arithmetic Operation, Logical Operation, Data Transfer, Boolean Variable Manipulation, and Program Branching. Capitalization is used in these descriptions, though no caps are used in my actual code. Also I've included a logical explaination to the right of each instruction. This gives a short visual summary of what the instruction does. Some are too complicated to describe this way, and I don't.

There are a total of 111 seperate instructions, but many variations. I note any flags that are affected by the instruction. If no flags are mentioned, then none are affected.

Arithmetic Operation

ADD A, Rn                      (A)=(A) + (Rn)                   Flags C, AC, OV

Adds the contents of a register to the contents of the accumulator and stores the result back into the accumulator.

ADD A, direct                  (A)=(A) + (direct)              Flags C, AC, OV

Adds the contents of a direct address to the contents of the accumulator and stores the result back into the accumulator.

ADD A, @Ri                     (A)=(A) + ((Ri))                Flags C, AC, OV

Adds the contents of the location pointed to by Ri to the contents of the accumulator and stores the result back into the accumulator.

ADD A, #data                    (A)=(A) + #data              Flags C, AC, OV

Adds the immediate data in the instruction to the contents of the accumulator and stores the result back into the accumulator.

ADDC A, Rn                    (A)=(A) + (C) + (Rn)         Flags C, AC, OV

Adds the contents of the register plus the contents of the carry flag, to the contents of the accumulator, and stores the result back into the accumulator.

ADDC A, direct                (A)=(A) + (C) + (direct)        Flags C, AC, OV

Adds the contents of the carry flag, plus the contents of the direct location, to the contents of the accumulator and stores the result back into the accumulator.

ADDC A, @Ri                  (A)=(A) + (C) + ((Ri))           Flags C, AC, OV

Adds the contents of the location pointed to by Ri, plus the contents of the carry flag, to the contents of the accumulator, and stores the result back into the accumulator.

ADDC A, #data                (A)=(A) + (C) + #data           Flags C, AC, OV

Adds the contents of the carry flag, plus the immediate data, to the contents of the accumulator and stores the result back into the accumulator.

SUBB A, Rn                     (A)= (A) - (C) - (Rn)              Flags C, AC, OV

The contents of the carry and the contents of the register are subtracted from the accumulator and the result is stored back into the accumulator.

SUBB A, direct                 (A)=(A) - (C) - (direct)           Flags C, AC, OV

The contents of the carry and the contents of the direct location are subtracted from the accumulator and the result is stored back into the accumulator.

SUBB A, @Ri                   (A)=(A) - (C) - ((Ri))              Flags C, AC, OV

The contents of the carry and the contents of the location pointed to by Ri, are subtracted from the accumlator and the result is stored back into the accumulator.

SUBB A, #data                  (A)=(A) - (C) - #data            Flags C, AC, OV

The contents of the carry and the immediate data are subtracted from the accumulator and the result is stored back into the accumulator.

INC A                                (A)=(A) + 1

Increments the contents of the accumulator by 1.

INC Rn                              (Rn)=(Rn) + 1

Increments the contents of the register by 1.

INC direct                          (direct)=(direct) + 1

Increments the contents of the direct location by 1.

INC @Ri                            ((Ri))=((Ri)) + 1

Increments the contents, of the location pointed to by Ri, by 1.

INC DPTR                         (DPTR)=(DPTR) + 1

Increments the contents of the dptr register by 1.

DEC A                                (A)=(A) -1

Decrements the contents of the accumulator by 1.

DEC Rn                              (Rn)=(Rn) - 1

Decrements the contents of the register by 1.

DEC direct                          (direct)=(direct) - 1

Decrements the contents of the direct location by 1.

DEC @Ri                            ((Ri))=((Ri)) - 1

Decrements the contents of the location pointed to by Ri, by 1.

MUL AB                               (B15-8), (A7-0)=(A) * (B)      Flags C, OV

Multiplies the contents of the accumulator by the contents of register b and stores the low order byte back into the accumulator and the high order byte back into register b. This multiplies two 8 bit numbers with a 16 bit result. If the result is greater than 255, in other words the b register has something other than zero in it, the OV flag will be set. The C flag will always be cleared.

DIV AB                                                                           Flags C, OV

Divides the accumulator by the b register and places the integer part of the quotent in the accumulator. The integer remainder is placed in the b register. The C flag is always cleared. In the event that the b register was originally zero (divide by zero), the OV flag will be set, indicating a divide by zero error.

DA A                                                                              Flags C, AC

This instruction is VERY complicated. It is used to adjust the accumulator after an add, that involved BCD (binary coded decimal) numbers, so that the accumulator has the proper BCD result in it. I'm not going to discuss this instruction any further, due to it's complexity and the use of BCD. You can find a two page description of how it works in Intel's "MCS 51 Microcontroller Family User's Manual". It is a handy instruction if you are going to be using BCD numbers, otherwise you will never use it. DA A stands for "Decimal adjust Accumulator for Addition". It could be handy for interfacing to a BCD display. It can be done other ways, which I do.

Logical Operation

ANL A, Rn                            (A)=(A) AND (Rn)

The contents of the accumulator are ANDED with the contents of the register and the result is stored back into the accumulator.

ANL A, direct                        (A)=(A) AND (direct)

The contents of the accumulator are ANDED with the contents of the direct location and the result is stored back into the accumulator.

ANL A, @Ri                          (A)=(A) AND ((Ri))

The contents of the accumulator are ANDED with the contents of the location pointed to by Ri, and the result is stored back into the accumulator.

ANL A, #data                        (A)=(A) AND #data

The contents of the accumulator are ANDED with the immediate data and the result is stored back into the accumulator.

ANL direct, A                        (direct)=(direct) AND (A)

The contents of the accumulator are ANDED with the direct location and the result is stored back into the direct location.

ANL direct, #data                  (direct)=(direct) AND #data

The contents of the direct location are ANDED with the immediate data and the result is stored back into the direct location.

ORL A, Rn                            (A)=(A) OR (Rn)

The contents of the accumulator are OR'ed with the contents of the register and the result is stored back into the accumulator.

ORL A, direct                        (A)=(A) OR (direct)

The contents of the accumulator are OR'ed with the contents of the direct location and the result is stored back into the accumulator.

ORL A, @Ri                          (A)=(A) OR ((Ri))

The contents of the accumulator are OR'ed with the contents of the location pointed to by Ri, and the result is stored back into the accumulator.

ORL A, #data                        (A)=(A) OR #data

The contents of the accumulator are OR'ed with the immediate data and the result is stored back into the accumulator.

ORL direct, A                        (direct)=(direct) OR (A)

The contents of the accumulator are OR'ed with the direct location and the result is stored back into the direct location.

ORL direct, #data                  (direct)=(direct) OR #data

The contents of the direct location are OR'ed with the immediate data and the result is stored back into the direct location.

XRL A, Rn                            (A)=(A) XOR (Rn)

The contents of the accumulator are XOR'ed with the contents of the register and the result is stored back into the accumulator.

XRL A, direct                        (A)=(A) XOR (direct)

The contents of the accumulator are XOR'ed with the contents of the direct location and the result is stored back into the accumulator.

XRL A, @Ri                          (A)=(A) XOR ((Ri))

The contents of the accumulator are XOR'ed with the contents of the location pointed to by Ri, and the result is stored back into the accumulator.

XRL A, #data                        (A)=(A) XOR #data

The contents of the accumulator are XOR'ed with the immediate data and the result is stored back into the accumulator.

XRL direct, A                        (direct)=(direct) XOR (A)

The contents of the accumulator are XOR'ed with the direct location and the result is stored back into the direct location.

XRL direct, #data                  (direct)=(direct) XOR #data

The contents of the direct location are XOR'ed with the immediate data and the result is stored back into the direct location.

CLR A                                   (A)= 0

The accumulator is cleared, or zero'ed out.

CPL A                                   (A)=(/A)

The contents of the accumulator is complemented. All one's become zero's and all zero's become one's.

RL A

The contents of the accumulator are rotated left by one bit. Bit 7 goes into bit 0.

RR A

The contents of the accumulator are rotated right by one bit. Bit 0 goes into bit 7.

RLC A                                                                               Flags C

The contents of the accumulator are rotated left, through the carry flag. Bit 7 goes into the carry, and the carry goes into bit 0.

RRC A                                                                               Flags C

The contents of the accumulator are rotated right, through the carry flag. The carry goes into bit 7 and bit 0 goes into the carry.

SWAP A                                 (A3-0)=(A7-4)

The upper nibble of the accumulator is swapped with the lower nibble. This can also be looked at as a 4 bit rotate. No flags are affected.

Data Transfer

MOV A, Rn                              (A)= (Rn)

The accumulator is loaded with the contents of the register.

MOV A, direct                          (A)=(direct)

The accumulator is loaded with the contents of the direct location.

MOV A, @Ri                            (A)=((Ri))

The accumulator is loaded with the contents of the location pointed to by Ri.

MOV A, #data                          (A)= #data

The accumulator is loaded with the immediate data.

MOV Rn, A                               (Rn)=(A)

The register is loaded with the contents of the accumulator.

MOV Rn, direct                         (Rn)= (direct)

The register is loaded with the contents of the direct location.

MOV Rn, #data                         (Rn)= #data

The register is loaded with the immediate data.

MOV direct, A                            (direct)= (A)

The direct location is loaded with the contents of the accumulator.

MOV direct, Rn                          (direct)= (Rn)

The direct location is loaded with the contents of the register.

MOV direct1, direct2                  (direct1)= (direct2)

The direct1 location is loaded with the contents of the direct2 location.

MOV direct, @Ri                        (direct)= ((Ri))

The direct location is loaded with the contents of the location pointed to by Ri.

MOV direct, #data                      (direct)= #data

The direct location is loaded with the immediate data.

MOV @Ri, A                               ((Ri))= (A)

The location pointed to by Ri is loaded with the contents of the accumulator.

MOV @Ri, direct                         ((Ri))= (direct)

The location pointed to by Ri is loaded with the contents of the direct location.

MOV @Ri, #data                         ((Ri))= #data

The location pointed to by Ri is loaded with the immediate data.

MOV DPTR, #data16                   (DPTR)= #data16

The dptr register is loaded with the 16 bit immediate data.

MOVC A, @A + DPTR                 (A)= ((A) + (DPTR))

The accumulator is loaded with the location in program memory pointed to by the original contents of the accumulator plus the contents of the dptr register. This is a handy instruction for implementing a lookup table in program memory. Say you created a table of ascii values that represent the numbers 0 thru 9. The ascii value for 0 would be the first entry in the table and the ascii value for 9 would be the last entry in the table. By setting dptr to the start of the table, if the accumulator had a 0 in it, the instruction would return with the first entry in the table, which is the ascii value for 0, in the accumulator. Walla! I use this one regularly.

MOVC A, @A + PC                      (A)=((A) + (PC))

This instruction acts exactly as the previous one except the PC (program conter) is the register used. I haven't came up with a good use for this instruction yet. But it is there to use.

MOVX A, @Ri                              (A)= ((Ri))

Loads the accumulator with the contents of the location, in external data memory, pointed to by Ri. This means that the first 256 locations in external data memory could be used by this instruction, possibly for frequently used variables or buffers. There are other options for this instruction if you are using p2 and p0 of the DS5000 for an external memory address/data bus. You could load p2 with the high order address bits and then use this instruction to access the 256 locations, or the page of memory pointed to by p2. This would allow you to create 256 pages of 256 locations, using a 64K RAM chip. I haven't used this instruction for anything yet, but it seems like it could be useful.

MOVX @Ri, A                              ((Ri))= (A)

This is just like the previous instruction, except that the external location is loaded with the contents of the accumulator.

MOVX A, @DPTR                        (A)= ((DPTR))

Loads the accumulator with the contents of the location in external data memory pointed to by dptr. This one works for all the locations in external data memory, and I use it a lot.

MOVX @DPTR, A                        ((DPTR))= (A)

Loads the location in external data memory pointed to by dptr, with the contents of the accumulator. Again, I use this one a lot for larger buffers that I don't have space for in internal data RAM.

PUSH direct                                 (SP)=(SP) + 1 ; ((SP))=(direct)

Increments the stack pointer (SP) and stores the contents of the direct location into the location pointed to by sp. This is one of the most used instructions. It, along with the POP instruction, implement the stack within the DS5000. The stack is used to temporarily store addresses and data, to allow the use of subroutines, with less memory overhead than would be possible without it. It also allows for relatively fast temporary storage and retrieval of information. The stack resides in internal RAM, usually towards the end of the internal RAM.

POP direct                                  (direct)=((SP)) ; (SP)=(SP) - 1

Loads the direct location with the contents of the location pointed to by the sp, then decrememts the sp register.

XCH A, Rn                                    (A)=(Rn)

The contents of the accumulator and the contents of the register are swapped. This is handy for intermediate storage of the accumulator contents, or for retrieving the contents of a register, while also saving the contents of the accumulator.

XCH A, direct                                (A)=(direct)

The contents of the accumulator and the contents of a direct location are swapped. Also handy.

XCH A, @Ri                                  (A)=((Ri))

The contents of the accumulator and the contents of the location pointed to by Ri are swapped.

XCHD A, @Ri                                (A3-0)=((Ri3-0)

The low order nibble of the accumulator and the low order nibble of the location pointed to by Ri are swapped. The high order nibbles are not affected.

Boolean Variable Manipulation

CLR C                                           (C)=0

The carry flag is cleared.

CLR bit                                          (bit)=0

The direct bit location is cleared.

SETB C                                          (C)=1

The carry flag is set.

SETB bit                                         (bit)=1

The direct bit location is set.

CPL C                                            (C)=(/C)

The carry flag is complemented. If it was a 0, it's now a 1, and vise versa.

CPL bit                                           (bit)=(/bit)

The direct bit location is complemented.

ANL C, bit                                        (C)=(C) AND (bit)

The carry flag is AND'ed with the direct bit location and the result is stored back into the carry.

ANL C, /bit                                       (C)=(C) AND (/bit)

The carry flag is AND'ed with the complement of the direct bit location and the result is stored back into the carry.

ORL C, bit                                        (C)=(C) OR (bit)

The carry is OR'ed with the direct bit location and the result is stored back into the carry.

ORL C, /bit                                       (C)=(C) OR (/bit)

The carry is OR'ed with the complement of the direct bit location and the result is stored back into the carry.

MOV C, bit                                        (C)= (bit)

The carry flag is loaded with the contents of the direct bit location.

MOV bit, C                                       (bit)= (C)

The direct bit location is loaded with the contents of the carry.

Program Branching

ACALL addr 11

The PC is incremented by 2 and then it is pushed onto the stack, low byte first (2 pushes, one for each byte) and the immediate 11 bits of the instruction are cancantenated with (added in, but not ADDED to) the high order 5 bits of the incremented PC, creating the 16 bit address. The sp is incremented by 2 in the process. The incremented PC value and the address to which the call is being made, must reside in the same 2K block of memory. I never use this one.

LCALL addr 16

The PC is incremented by 2 and pushed (as the previous instruction) on to the stack, then the PC is loaded with the immediate 16 bit address in the instruction. This is the one I always use for a call.

RET

The PC is popped off of the stack, loading it with the address popped off (2 pops, one for each byte). The sp is decremented by two in the process.

RETI

This does the same thing as the RET, but in addition, it re-enables the interrupts to accept another interrupt of the same or lower level (priority). This is used to return from an interrupt service routine. Should an interrupt of a higher level occur, it is serviced, even though it might be in the middle of servicing a lower level interrupt.

AJMP addr 11

This does the same thing as the ACALL, except no address is pushed onto the stack.

LJMP addr 16                                  (PC)= addr 16

The PC is loaded with the immediate address in the instruction, which causes the next instruction to come from the new address. Same as the LCALL except no address is pushed onto the stack.

SJMP rel

The PC is incremented by 2 and then the relative offset is added to the PC to get the new address. The next instruction will come from there. This is good for short jumps (+/- 127 locations from the incremented PC address).

JMP @A + DPTR                             (PC)=(A) + (DPTR)

The PC is loaded with the address resulting from adding the contents of the accumulator to the contents of the dptr register. Neither the accumulator nor dptr contents are changed. This could be used for making a jump table. The accumulator contents would determine what jump was executed in the table. If the dptr is set to the start of the table and the accumulator has an even number in it, then the AJMP at that location would be executed. If the accumulator has multiples of 3 in it, then you could use LJMP's in the table. A seemingly handy, but tricky, instruction that I've never used, so far.

JZ rel

The PC is incremented by two (to get to the address of the next instruction, as normal). If the accumulator contents are zero, then the relative offset in the instruction is added to the incremented PC and the next instruction comes from there. If the accumulator isn't zero, the next instruction after the JZ is executed.

JNZ rel

This acts just like the JZ, except the relative offset is added if the accumulator isn't zero, or the next instruction after the JNZ is executed, if it is zero.

JC rel

The PC  incremented by 2, and if the carry is set, the relative offset is added to the PC and the next instruction comes from there. Otherwise the next instruction after the JC is executed.

JNC rel

Like the JC except the offset is added if the carry is 0, otherwise the next instruction is executed.

JB bit, rel

As in previous examples the PC is incremented by two. If the direct bit location is 1, the offset is added, otherwise the next instruction is executed.

JNB bit, rel

Same as JB, except offset is added if the direct bit location is 0, otherwise the next instruction is executed.

JBC bit, rel

Same as JB, except that if the bit is 1, it is cleared and the offset added. Otherwise the next instruction is executed.

CJNE A,direct, rel                                                                     Flags C

Compares the accumulator with the direct location and, if they're not equal, adds the offset to the PC. Otherwise the next instruction is executed. If A is less than direct, then C is set. Otherwise it's cleared.

CJNE A, #data, rel                                                                    Flags C

Compares the accumulator with the immediate data and, if they're not equal, adds the offset. Otherwise the next instruction is executed. If A is less than #data, then C is set. Otherwise it's cleared.

CJNE Rn, #data, rel                                                                  Flags C

Compares the register with the immediate data and, if they're not equal, adds the offset. Otherwise the next instruction is executed. If Rn is less than #data, then C is set. Otherwise it's cleared.

CJNE @Ri, #data, rel                                                               Flags C

Compares the location pointed to by Ri, with the immediate data and, if they're not equal, adds the offset. Otherwise, the next instruction is executed. If @Ri is less than #data, then C is set. Otherwise it's cleared.

DJNZ Rn, rel

Decrements the register and, if not zero, adds the offset to the PC. Otherwise, the next instruction is executed. This is used for looping.

DJNZ direct, rel

Decrements the contents of the direct location and, if not zero, adds the offset. Otherwise, the next instruction is executed. Used for looping.

NOP

This instruction does ablolutely nothing, except waste instruction cycles. That's it's sole purpose. Sometimes it's necessary to wait a short time after executing an instruction, before executing another. I use it for I/O accesses mostly. I output the select lines and then wait a small time to let the chips setup, then read or write. It uses up 1 instruction cycle.

The information presented here came from three sources, my experience, the Dallas Semiconductor Soft Microcontroller Data Book, and the Intel MCS 51 Microcontroller Family User's Manual.

My home page is http://www.hkrmicrop.com/personal/index.html .