Designing a Small Microprocessor-Based System
Putting All the Pieces Together
Open interactive version (quiz + challenge)Real-world analogy
What is it?
This lesson integrates all previous concepts into a complete microprocessor-based system design. It covers the systematic process: defining requirements, selecting components (8086 + ROM + RAM + 8255 + 8254 + 8259 + 8251), designing the memory and I/O maps, implementing address decoding with 74LS138 decoders, wiring chip-select logic, writing initialization firmware, and validating the design. The result is a functional embedded system that can read input, process data, display output, handle interrupts, and communicate serially.
Real-world relevance
This is exactly how embedded systems engineers design products today — just with modern components. A car's engine control unit follows the same design process: select an MCU (now ARM), add sensors (via ADC/I/O), add actuators (via GPIO/PWM), design the memory map, write initialization firmware, implement ISRs for real-time events, and validate everything. The tools and chips have evolved, but the methodology is identical to what we practice here with the 8086.
Key points
- System Design Methodology — Designing a microprocessor system follows a structured process: (1) Define requirements — what must the system do? (2) Select components — CPU, memory sizes, peripherals. (3) Design the memory map — assign address ranges. (4) Design address decoding — generate chip selects. (5) Draw the schematic — connect buses, control signals. (6) Write initialization code. (7) Test and validate. Skipping any step leads to debugging nightmares.
- System Block Diagram — The block diagram shows all components and how they connect through the bus system. The 8086 CPU connects to all devices via the address bus (A0-A19), data bus (D0-D15), and control bus (RD, WR, M/IO, INTA). Each device has a chip select (CS) driven by the address decoder. ROM connects to the data bus read-only. RAM connects read/write. I/O chips connect through the lower data bus (D0-D7) with I/O port addresses.
- Memory Map Design — The memory map divides the 1MB address space into regions for each device. Key rules: ROM must include FFFF0h (reset vector). RAM should start at 00000h (interrupt vector table lives at 00000h-003FFh). Leave space between memory and I/O devices. Avoid overlaps. For the I/O space (64KB), assign port addresses to each peripheral with enough consecutive addresses for their registers.
- Address Decoding Design — Use a 74LS138 decoder to generate chip selects from upper address lines. For memory: decode A19-A15 to select ROM and RAM blocks. For I/O: use M/IO combined with address bits to select peripherals. Each chip select equation must be derived from the assigned address range, ensuring no overlaps. Document every decode equation — this is critical for debugging.
- Chip Selection and Signal Connections — Each peripheral chip needs correct signal wiring. ROM: address lines A0-A14 for 32KB, D0-D7/D8-D15 for data, RD to OE, CS from decoder. RAM: same address lines, data lines, RD to OE, WR to WE, CS from decoder. 8255: A0-A1 for register select, D0-D7 for data, RD, WR, CS from I/O decoder. 8259: A0 for register select, D0-D7, RD, WR, CS, INT to CPU INTR. Clock and reset signals to all chips.
- Initialization Code — Booting the System — After reset, the 8086 starts executing from FFFF0h (in ROM). The initialization code must: set up segment registers, set up the stack pointer, initialize the IVT (interrupt vector table), configure the 8259 PIC, configure the 8254 timer, configure the 8255 I/O, configure the 8251 serial port, enable interrupts (STI), and jump to the main application. This boot code is the firmware of the system.
- Design Validation Checklist — Before building, verify: (1) Reset vector FFFF0h is inside ROM. (2) IVT area 00000-003FF is inside RAM. (3) No address overlaps between chips. (4) All chip selects derived correctly — check truth table. (5) Even/odd bank wiring correct for 16-bit bus. (6) Control signals (RD/WR/M-IO) correctly routed. (7) Clock and reset connected to all chips. (8) Pull-up resistors on open-drain signals. (9) Decoupling capacitors near each chip's power pins.
- Complete System Integration Example — The final system: 8086 CPU, 32KB ROM (27256), 32KB RAM (62256), 8255 for keyboard/display, 8254 for timing, 8259 for interrupts, 8251 for serial communication. The boot code in ROM initializes everything, sets up ISRs, and enters a main loop that scans the keyboard, updates the display, and handles serial commands. This is a complete, functional embedded system built entirely from the chips studied in this course.
Code example
; =============================================
; Complete 8086 System Design
; =============================================
;
; Components:
; 8086 CPU @ 5MHz
; 27256 ROM (32KB) at F8000-FFFFF
; 62256 RAM (32KB) at 00000-07FFF
; 8255 PPI at I/O 80-83h
; 8254 Timer at I/O 40-43h
; 8259 PIC at I/O 20-21h
; 8251 USART at I/O 60-61h
;
; === Address Decoding Equations ===
;
; CS_ROM = M/IO AND A19 AND A18 AND A17
; AND A16 AND A15
; CS_RAM = M/IO AND NOT(A19) AND NOT(A18)
; AND NOT(A17) AND NOT(A15)
;
; CS_8259 = NOT(M/IO) AND NOT(A7) AND
; A6 AND NOT(A5)
; CS_8254 = NOT(M/IO) AND NOT(A7) AND
; NOT(A6) AND A5 — wait, that's 20h
;
; Correction using 74LS138:
; I/O decoder: C=A7, B=A6, A=A5
; Y1 (001) → 20-3Fh → CS_8259
; Y2 (010) → 40-5Fh → CS_8254
; Y3 (011) → 60-7Fh → CS_8251
; Y4 (100) → 80-9Fh → CS_8255
;
; === Initialization Sequence ===
;
ORG 0FFF0h ; ROM reset vector
JMP FAR PTR BOOT ; first instruction
;
ORG 0F800h ; Boot code in ROM
BOOT:
CLI ; disable interrupts
MOV AX, 0
MOV DS, AX
MOV ES, AX
MOV AX, 07FFh
MOV SS, AX
MOV SP, 0FFEh
;
; --- Init 8259 PIC ---
MOV AL, 13h
OUT 20h, AL ; ICW1
MOV AL, 08h
OUT 21h, AL ; ICW2
MOV AL, 01h
OUT 21h, AL ; ICW4
MOV AL, 0FEh
OUT 21h, AL ; unmask IR0 (timer)
;
; --- Init 8254 Timer (1ms tick) ---
MOV AL, 36h
OUT 43h, AL ; C0, mode 3
MOV AL, 0A9h
OUT 40h, AL ; LSB of 1193
MOV AL, 04h
OUT 40h, AL ; MSB of 1193
;
; --- Init 8255 (PA=out, PB=in) ---
MOV AL, 82h
OUT 83h, AL
;
; --- Init 8251 (9600, 8N1, 16x) ---
MOV AL, 40h
OUT 61h, AL ; reset
MOV AL, 4Eh
OUT 61h, AL ; mode word
MOV AL, 37h
OUT 61h, AL ; command word
;
; --- Set IVT for timer (INT 08h) ---
MOV WORD PTR DS:[0020h], OFFSET TIMER_ISR
MOV WORD PTR DS:[0022h], CS
;
STI ; enable interrupts
JMP MAIN ; start applicationLine-by-line walkthrough
- 1. Title comment for complete system design
- 2. Separator line
- 3. Blank line
- 4. Component list with specifications
- 5. CPU: 8086 running at 5 MHz
- 6. ROM: 32KB mapped at top of memory for boot code
- 7. RAM: 32KB mapped at bottom for data, stack, and IVT
- 8. Peripheral chips with their I/O port assignments
- 9. Blank line
- 10. Address decoding equations section
- 11. Blank line
- 12. CS_ROM: active when M/IO=1 and all upper address bits = 1 (F8000-FFFFF)
- 13. CS_RAM: active when M/IO=1 and upper bits = 0 (00000-07FFF)
- 14. Blank line
- 15. I/O decoder equations using 74LS138
- 16. Comment on correction: using organized decoder outputs
- 17. Y1 output selects 8259 PIC at ports 20-3Fh
- 18. Y2 selects 8254 timer at ports 40-5Fh
- 19. Y3 selects 8251 USART at ports 60-7Fh
- 20. Y4 selects 8255 PPI at ports 80-9Fh
- 21. Blank line
- 22. Initialization sequence begins
- 23. Blank line
- 24. ORG directive places reset vector jump at ROM address FFF0h
- 25. JMP instruction — first thing executed after power-on reset
- 26. Blank line
- 27. ORG places boot code at beginning of ROM space
- 28. BOOT label — system initialization starts here
- 29. CLI disables interrupts to prevent crashes during setup
- 30. Clear AX for segment register initialization
- 31. Set DS and ES to segment 0 (data at physical 00000h)
- 32. Set ES
- 33. Set stack segment to 07FFh
- 34. Point stack to near top of RAM
- 35. Set SP — stack is ready
- 36. Blank line
- 37. Initialize 8259 PIC — sets interrupt handling policies
- 38. ICW1: edge triggered, single PIC, ICW4 needed
- 39. ICW2: IR0 maps to INT 08h vector
- 40. ICW4: 8086 mode for correct vector generation
- 41. OCW1: unmask only IR0 (timer) — all others masked
- 42. Blank line
- 43. Initialize 8254 timer for 1ms periodic interrupt
- 44. Control word: Counter 0, Mode 3 square wave, LSB+MSB
- 45. Load count value 1193 (for ~1 KHz with 1.193 MHz clock)
- 46. LSB of count
- 47. MSB of count — timer starts generating interrupts
- 48. Blank line
- 49. Initialize 8255: Port A output, Port B input
- 50. Control word 82h configures ports
- 51. Blank line
- 52. Initialize 8251 USART for 9600 baud 8N1
- 53. Reset command clears any previous state
- 54. Mode word: 8 data bits, no parity, 1 stop, 16x clock
- 55. Command word: enable transmitter, receiver, DTR, RTS
- 56. Blank line
- 57. Set up IVT entry for timer interrupt (INT 08h)
- 58. Store ISR offset at IVT address 0020h (vector 08h * 4)
- 59. Store ISR segment at IVT address 0022h
- 60. Blank line
- 61. STI enables interrupts — system is fully initialized
- 62. Jump to main application loop
Spot the bug
; System init — set up stack and start
;
MOV AX, 0800h
MOV SS, AX
MOV SP, 0000h ; stack pointer
;
; Init 8259
MOV AL, 13h
OUT 20h, AL ; ICW1
MOV AL, 20h
OUT 21h, AL ; ICW2: base vector 20h
MOV AL, 01h
OUT 21h, AL ; ICW4
;
STI
JMP MAINNeed a hint?
Show answer
Explain like I'm 5
Fun fact
Hands-on challenge
More resources
- 8086 System Design Example (Education 4u)
- Microprocessor System Design (GeeksforGeeks)
- Complete 8086 Minimum Mode System (Neso Academy)
- 8086 Hardware Reference Manual (Intel)