Internal Architecture
The 8051 is a Harvard architecture — separate address spaces for program memory (ROM) and data memory (RAM). All major peripherals are on-chip, connected via an internal 8-bit data bus.
Key Features
| Feature | Specification |
|---|---|
| CPU | 8-bit, Boolean processor, Harvard architecture |
| Clock | Up to 12 MHz; 1 machine cycle = 12 clock periods |
| Program Memory | 4 KB internal ROM; up to 64 KB external via PSEN |
| Data Memory | 128 bytes internal RAM; up to 64 KB external via RD/WR |
| I/O Ports | 4 × 8-bit bidirectional (P0–P3) = 32 pins total |
| Timers | 2 × 16-bit (Timer 0, Timer 1) — 4 modes each |
| Serial Port | Full-duplex UART — 4 modes; baud via Timer 1 |
| Interrupts | 5 sources, 2 priority levels; 6 vectors |
| Instruction Set | 111 instructions; single-cycle to 4-cycle |
| Package | 40-pin DIP (standard), also PLCC, QFP variants |
| Supply | VCC = 5V (CMOS variants: 3.3V) |
40-Pin DIP Pinout
Memory Organization
Internal RAM (0x00–0x7F)
Program Memory (64KB)
CPU Registers
Accumulator (ACC / A) — 0xE0
Primary working register for all ALU operations. Results of ADD, SUB, MUL, DIV, ANL, ORL, XRL all land here. Bit-addressable (ACC.0–ACC.7).
B Register — 0xF0
Second operand for MUL AB and DIV AB. MUL result: A=low byte, B=high byte. DIV result: A=quotient, B=remainder. Used as general-purpose otherwise.
Program Counter (PC) — 16-bit
Not directly addressable. Holds address of next instruction. Increments automatically. Modified by JMP, CALL, RET. Reset to 0x0000 on power-up or RST.
Stack Pointer (SP) — 0x81
8-bit. Default = 0x07 after reset. Stack grows upward (pre-increment on PUSH, post-decrement on POP). Stays in internal RAM; avoid SP > 0x7F.
Data Pointer (DPTR) — 0x82/0x83
16-bit register formed by DPH (0x83) and DPL (0x82). Used with MOVX (external RAM access) and MOVC (program memory table lookup). Only 16-bit register in 8051.
R0–R7 (Register Banks)
Four banks of 8 registers (R0–R7), each 8-bit. Active bank selected by RS1:RS0 bits in PSW. Bank 0 at 0x00–0x07, Bank 1 at 0x08–0x0F, Bank 2 at 0x10–0x17, Bank 3 at 0x18–0x1F.
PSW — Program Status Word (0xD0)
| Bit | Name | Description |
|---|---|---|
| CY | Carry | Set by carry-out from bit 7 in ADD; borrow in SUBB; also used in bit operations |
| AC | Aux Carry | Carry from bit 3 to bit 4; used by DA A (decimal adjust) |
| F0 | User Flag | General-purpose flag, set/cleared by software |
| RS1:RS0 | Reg Bank | 00=Bank0, 01=Bank1, 10=Bank2, 11=Bank3 |
| OV | Overflow | Set if signed arithmetic overflows (carry into bit 7 ≠ carry out) |
| P | Parity | Hardware-set: 1 if ACC has odd number of 1s (even parity) |
Special Function Registers (SFRs)
| SFR | Address | Bit-addr? | Function |
|---|---|---|---|
| P0 | 0x80 | Yes | Port 0 I/O latch (AD0–AD7, open-drain, needs pull-ups) |
| SP | 0x81 | No | Stack Pointer — default 0x07 after reset |
| DPL | 0x82 | No | Data Pointer low byte |
| DPH | 0x83 | No | Data Pointer high byte |
| PCON | 0x87 | No | Power control; SMOD (bit 7) doubles UART baud rate |
| TCON | 0x88 | Yes | Timer control; TF1, TF0 overflow flags; TR1, TR0 run bits; IE1, IE0, IT1, IT0 |
| TMOD | 0x89 | No | Timer mode select — upper nibble=Timer1, lower=Timer0 |
| TL0 | 0x8A | No | Timer 0 low byte |
| TL1 | 0x8B | No | Timer 1 low byte |
| TH0 | 0x8C | No | Timer 0 high byte |
| TH1 | 0x8D | No | Timer 1 high byte (reload value in Mode 2) |
| P1 | 0x90 | Yes | Port 1 I/O latch (general-purpose only) |
| SCON | 0x98 | Yes | Serial control — SM0/SM1 mode, REN, TI, RI flags |
| SBUF | 0x99 | No | Serial buffer — write=transmit, read=receive (separate regs) |
| P2 | 0xA0 | Yes | Port 2 I/O latch (A8–A15 for external memory) |
| IE | 0xA8 | Yes | Interrupt enable — EA, ET2, ES, ET1, EX1, ET0, EX0 |
| P3 | 0xB0 | Yes | Port 3 — alternate functions: RXD, TXD, INT0, INT1, T0, T1, WR, RD |
| IP | 0xB8 | Yes | Interrupt priority — PT2, PS, PT1, PX1, PT0, PX0 |
| PSW | 0xD0 | Yes | Program Status Word (see above) |
| ACC | 0xE0 | Yes | Accumulator |
| B | 0xF0 | Yes | B register (MUL/DIV operand) |
Timer / Counter
Both timers are 16-bit up-counters. Each can count internal clock pulses (timer mode) or external pulses on T0 (P3.4) / T1 (P3.5) pins (counter mode). Configured via TMOD and TCON.
TMOD Register (0x89) — not bit-addressable
Upper nibble = Timer 1 · Lower nibble = Timer 0 · GATE=1: timer runs only when INTx pin is HIGH · C/T̄=0: timer, 1: counter
| M1:M0 | Mode | Description |
|---|---|---|
| 00 | Mode 0 | 13-bit timer (TH as 8-bit + TL lower 5-bit). Legacy MCS-48 compatible. |
| 01 | Mode 1 | 16-bit timer/counter (TH:TL). Most commonly used. No auto-reload. |
| 10 | Mode 2 | 8-bit auto-reload — TL counts, reloads from TH on overflow. Ideal for UART baud rate. |
| 11 | Mode 3 | Timer 0 only: splits into two 8-bit timers (TL0 and TH0). Timer 1 stops. |
Timer Delay Calculation
At 12 MHz: machine cycle = 1 µs. For a 50 ms delay in Mode 1 (16-bit):
Counts needed = 50,000. Initial value = 65536 − 50000 = 15536 = 0x3CB0
So: TH0 = 0x3C, TL0 = 0xB0, TMOD = 0x01, TR0 = 1, poll TF0.
Interrupt System
| Source | Vector | IE Bit | Flag | Triggered by |
|---|---|---|---|---|
| External INT0 | 0x0003 | EX0 (IE.0) | IE0 (TCON.1) | P3.2 low-level or falling edge (IT0) |
| Timer 0 | 0x000B | ET0 (IE.1) | TF0 (TCON.5) | Timer 0 overflow |
| External INT1 | 0x0013 | EX1 (IE.2) | IE1 (TCON.3) | P3.3 low-level or falling edge (IT1) |
| Timer 1 | 0x001B | ET1 (IE.3) | TF1 (TCON.7) | Timer 1 overflow |
| Serial Port | 0x0023 | ES (IE.4) | TI or RI | Transmit complete (TI) or byte received (RI) |
Enable an interrupt: set its IE bit and set EA (IE.7). Priority: set the corresponding IP bit for high priority (high priority ISR can interrupt a low priority ISR).
Serial Port (UART)
SCON Register (0x98)
| SM0:SM1 | Mode | Description | Baud Rate |
|---|---|---|---|
| 00 | 0 | Shift register (synchronous), 8-bit | fosc / 12 |
| 01 | 1 | 8-bit UART (1 start, 8 data, 1 stop) | Timer 1 Mode 2 |
| 10 | 2 | 9-bit UART, fixed baud | fosc/64 or fosc/32 |
| 11 | 3 | 9-bit UART, variable baud | Timer 1 Mode 2 |
Baud rate formula (Mode 1, SMOD=0): Baud = fosc ÷ (384 × (256 − TH1))
For 9600 baud at 11.0592 MHz: TH1 = 256 − (11059200 ÷ 384 ÷ 9600) = 256 − 3 = 0xFD
Instruction Set Summary
Data Transfer
MOV dst,src — internal moveMOVX A,@DPTR — external RAM readMOVC A,@A+DPTR — program memory (tables)PUSH / POP direct — stack operationsXCH A,Rn — exchange accumulator
Arithmetic
ADD A,src — A = A + srcADDC A,src — A = A + src + CYSUBB A,src — A = A − src − CYMUL AB — 16-bit result in B:ADIV AB — A=quotient, B=remainderINC / DEC — increment/decrementDA A — decimal adjust after ADD
Logical
ANL / ORL / XRL A,src — bitwise AND/OR/XORCLR A — A = 0CPL A — A = ~A (complement)RL / RLC A — rotate left (with/without CY)RR / RRC A — rotate rightSWAP A — exchange nibbles of A
Branching
AJMP / LJMP addr — unconditional jumpSJMP rel — short relative jump (±127)JZ / JNZ rel — jump if A=0 / A≠0JC / JNC rel — jump on carryDJNZ Rn,rel — decrement and jump if not zeroCJNE A,src,rel — compare and jump
Bit Operations
SETB bit — set bit to 1CLR bit — clear bit to 0CPL bit — complement bitMOV C,bit / MOV bit,C — move to/from carryANL C,bit / ORL C,bit — bit AND/OR with carryJB / JNB / JBC bit,rel — jump on bit
Subroutine / Misc
ACALL / LCALL addr — call subroutine (pushes PC)RET — return from subroutine (pops PC)RETI — return from interrupt (also clears priority)NOP — no operation (1 machine cycle)ORL / ANL direct,#data — direct bit manipulation
Assembly Code Examples
1 — LED Blink on P1.0
; Toggle P1.0 continuously with ~500ms delay at 12MHz ORG 0000H MAIN: SETB P1.0 ; LED ON ACALL DELAY500 CLR P1.0 ; LED OFF ACALL DELAY500 SJMP MAIN ; ~500ms delay using nested loops (12 MHz → 1µs/cycle) DELAY500: MOV R0,#250 D1: MOV R1,#250 D2: MOV R2,#8 D3: DJNZ R2,D3 ; 8 cycles ≈ 8µs DJNZ R1,D2 DJNZ R0,D1 RET END
2 — Timer 0 Mode 1 Interrupt (50ms)
; Timer 0 Mode 1 — 50ms interrupt at 12MHz, toggle P2.0 ORG 0000H LJMP MAIN ORG 000BH ; Timer 0 interrupt vector LJMP T0_ISR ORG 0030H MAIN: MOV TMOD,#01H ; Timer 0, Mode 1 (16-bit) MOV TH0,#3CH ; 65536-50000 = 15536 = 0x3CB0 MOV TL0,#0B0H SETB ET0 ; Enable Timer 0 interrupt SETB EA ; Global interrupt enable SETB TR0 ; Start timer SJMP $ ; Wait (background loop) T0_ISR: MOV TH0,#3CH ; Reload MOV TL0,#0B0H CPL P2.0 ; Toggle LED RETI END
3 — UART Transmit a Byte (9600 baud @ 11.0592 MHz)
; Initialize UART Mode 1, 9600 baud, transmit 'A' ORG 0000H MAIN: MOV TMOD,#20H ; Timer 1, Mode 2 (auto-reload) MOV TH1,#0FDH ; 9600 baud at 11.0592MHz MOV TL1,#0FDH SETB TR1 ; Start Timer 1 MOV SCON,#50H ; Mode 1, REN=1 (receive enabled) MOV A,#'A' ; Character to send (0x41) MOV SBUF,A ; Load transmit buffer → starts TX WAIT: JNB TI,WAIT ; Poll TI flag (set when TX done) CLR TI ; Clear TI manually SJMP $ END
4 — Lookup Table with MOVC
; Read 7-segment display code for digit in R0 (0–9) ORG 0000H MAIN: MOV R0,#3 ; Digit to display = 3 MOV A,R0 MOV DPTR,#SEG_TABLE MOVC A,@A+DPTR ; A = SEG_TABLE[A] MOV P1,A ; Output to 7-seg on Port 1 SJMP $ SEG_TABLE: ; Common-cathode 7-segment codes for 0–9 DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH END