MCS-51 Addressing & Instruction Set
MCS-51 instructions are best understood as routes among the accumulator, register banks, internal data, SFRs, bit space, code tables, and external data—not as a flat mnemonic list. Each addressing form determines both where an operand lives and which side effects are possible.
The MCS-51 instruction set is compact because operand location is encoded through several specialized forms. Learning it as “256 opcodes” obscures the real structure: the instruction selects an address space, an operand route, and a set of architectural effects.
Addressing forms #
| Form | Example | Operand source or target |
|---|---|---|
| Register | MOV A,R3 |
R0–R7 in the bank selected by PSW |
| Direct | MOV A,30h |
Internal RAM below 80h, or an SFR at 80h–FFh |
| Register indirect | MOV A,@R0 |
Internal data through R0 or R1 |
| Immediate | MOV A,#55h |
Constant encoded after the opcode |
| Bit direct | SETB 20h |
One bit in bit-addressable RAM or a bit-addressable SFR |
| Indexed code | MOVC A,@A+DPTR |
Code byte at table base plus unsigned accumulator index |
| External data | MOVX A,@DPTR |
External/data-space byte through a 16-bit pointer |
| Relative branch | JNZ rel |
Signed displacement from the next instruction |
The mnemonic MOV is not one universal move. Its operand forms decide which memory exists on each side and what encoding is legal. MOVC explicitly reads code space; MOVX explicitly accesses external data space.
Data movement and exchange #
Moves connect the accumulator, registers, direct bytes, indirect bytes, SFRs, external data, and code tables. Stack instructions operate on internal data through SP. XCH and nibble exchange support compact transformations but also create implicit accumulator dependencies.
For table lookup, MOVC A,@A+DPTR uses DPTR as a base and A as an index, then overwrites A with the fetched byte. A routine that still needs the index must preserve it. This is a general reading rule: list every implicit input and output, not only operands printed by the assembler.
Arithmetic and flags #
Addition and subtraction update carry-related flags; ADDC consumes carry and supports multi-byte arithmetic. SUBB subtracts both the operand and the input borrow represented by carry, so firmware must establish the initial carry state deliberately.
MUL AB produces a 16-bit result split across B:A; DIV AB returns quotient and remainder. Decimal adjustment is meaningful only after the intended BCD addition sequence. Increment/decrement instructions do not all update carry in the way a programmer familiar with another ISA may expect.
Boolean processor #
The carry flag acts as a one-bit accumulator. Instructions can move between carry and an addressed bit, combine carry with a bit or its complement, set/clear/complement bits, and branch on bit state while optionally clearing it.
This is powerful for control firmware because a pin, flag, or software bit can be manipulated without a byte-wide mask sequence. It is also concurrency-sensitive: a peripheral flag may change asynchronously, and a read-modify-write operation on a port or SFR may observe the latch rather than the external signal.
Control flow and reach #
- short conditional branches use signed relative offsets;
SJMPis compact but local;AJMP/ACALLencode a destination within a page-related reach;LJMP/LCALLcarry a full 16-bit code address;RETrestores a normal call return;RETIalso completes the interrupt-controller protocol expected by the architecture/device.
Assembler and linker placement matter because a source-level call can require a different encoding when code moves. Hand-written absolute assumptions become fragile as soon as modules are linked or boot regions are introduced.
A worked multi-byte addition #
To add two 16-bit little-endian values:
- clear carry;
- load the low byte of the first operand into
A; - add the low byte of the second operand and store the result;
- load the high byte of the first operand;
- use
ADDCwith the second high byte; - store the high result; carry now records unsigned overflow beyond 16 bits.
The algorithm works because the low-byte instruction produces the exact carry state consumed by the high-byte instruction. An interrupt that modifies A, carry, DPTR, or selected bank without preserving it breaks the chain.
Timing belongs to the implementation #
Instruction semantics come from the architecture; cycle counts come from a particular core and memory system. The original 8051 organized work around twelve oscillator periods per machine cycle. Modern compatible cores can execute most instructions in one or two system clocks. Delay loops must therefore be derived from the exact device clock and instruction timing—or replaced by a timer whose behavior is itself specified.
Sources
- docsMCS-51 Family of Single Chip Microcomputers User's Manualpdfnotes
- docsEFM8BB51 Reference Manualpdfnotes
- bookDesign of Microprocessor Systems: Programming MCS-51 Microcontrollerspdfnotes