Datapath ও Control Unit — যেখানে সব টুকরো একটা CPU হয়ে ওঠে
Datapath and Control Unit
Register file + ALU + memory + MUX-কে বাসে জুড়ে datapath বানানো হয় — এটাই CPU-র 'পেশি'। তার উপর একটা FSM বসিয়ে control unit বানানো হয় — এটাই 'মস্তিষ্ক', যেটা প্রতি cycle-এ ঠিক করে কোন signal assert হবে। দুটো মিলেই একটা CPU।
আগে এটা বুঝি
চোদ্দটা লেসন ধরে আমরা টুকরো টুকরো জিনিস বানিয়েছি। Transistor থেকে gate। Gate থেকে adder। Adder থেকে ALU। Feedback থেকে flip-flop, flip-flop থেকে register। Clock, timing, FSM, counter। আর গত লেসনে memory।
প্রতিটা টুকরো নিজের মতো সম্পূর্ণ, নিজের মতো পরীক্ষিত — কিন্তু এখনও আলাদা। একটা ALU টেবিলে বসে যোগ করতে পারে। একটা register file একটা মান ধরে রাখতে পারে। একটা memory array একটা বিট সংরক্ষণ করতে পারে। কিন্তু এদের কেউই একা একটা প্রোগ্রাম চালাতে পারে না।
আজকের লেসনে আমরা এই সবগুলো টুকরো এক জায়গায় জড়ো করব, একটা bus system দিয়ে জুড়ে দেব, আর তার উপর একটা নিয়ন্ত্রক (controller) বসাব যেটা প্রতি clock cycle-এ ঠিক করে দেবে কোন টুকরো কী করবে। যখন এই কাজ শেষ হবে, আপনি প্রথমবারের মতো এমন একটা জিনিস দেখবেন যেটাকে সৎভাবে CPU বলা যায় — নিজের ISA (instruction set), নিজের datapath, নিজের control unit সহ।
আর সবচেয়ে গুরুত্বপূর্ণ কথা: এতে কোনো নতুন যাদু নেই। “CPU” নামের একটা রহস্যময় জিনিস নয় — এটা ঠিক সেই জিনিসগুলোই যা আপনি ইতিমধ্যে বানিয়েছেন, শুধু সঠিকভাবে তারের সাথে জোড়া, একটা state machine দিয়ে পরিচালিত। এই লেসনের শেষে “CPU কীভাবে কাজ করে” প্রশ্নের উত্তর মুখস্থ কোনো সংজ্ঞা হবে না — আপনি নিজে সেটা তারের ডায়াগ্রাম থেকে বানিয়ে দেখাতে পারবেন।
মূল ধারণা
দুইটা শব্দ যা এই পুরো লেসনের ভিত্তি
Datapath — register, ALU, memory, multiplexer, আর তাদের সংযোগকারী bus-এর নেটওয়ার্ক, যার মধ্য দিয়ে প্রকৃত ডেটা প্রবাহিত হয়ে একটা operation সম্পন্ন হয়। এটা CPU-র “পেশি” — যেখানে আসল কাজ (যোগ করা, memory-তে পড়া/লেখা) ঘটে।
Control unit — একটা FSM (লেসন ১২), যেটা প্রতি clock cycle-এ datapath-কে বলে দেয় ঠিক কী করতে হবে — কোন MUX কোন input বাছবে, কোন register write হবে, ALU কী operation করবে। এটা CPU-র “মস্তিষ্ক” বা “পরিচালক” (conductor) — নিজে কোনো ডেটা প্রসেস করে না, শুধু বাকিদের নির্দেশ দেয়।
এই বিভাজনটাই — datapath বনাম control — কম্পিউটার architecture-এর সবচেয়ে মৌলিক structural ধারণাগুলোর একটা। এটা এতটাই কেন্দ্রীয় যে John von Neumann-এর ১৯৪৫-এর মূল stored-program computer প্রস্তাবেই এই বিভাজন স্পষ্টভাবে ছিল — “arithmetic unit” (আমাদের datapath-এর অংশ) আর “control unit” আলাদা করে চিহ্নিত করা হয়েছিল। প্রায় ৮০ বছর পরেও, আজকের সবচেয়ে জটিল CPU-তেও এই একই বিভাজন টিকে আছে।
আমাদের toy ISA — মাত্র তিনটা instruction
একটা সম্পূর্ণ ISA ডিজাইন করা Level 3-এর কাজ। এখানে আমরা ইচ্ছাকৃতভাবে ন্যূনতম একটা ISA বানাব — শুধু এতটুকু জটিল যাতে datapath+control-এর প্রতিটা অংশ প্রয়োজন হয়, কিন্তু এতটাই সরল যাতে পুরোটা এক নজরে ধরা যায়।
ADD Rd, Rs, Rt ; Rd ← Rs + Rt (register-register)
LOAD Rd, addr ; Rd ← Memory[addr] (memory থেকে পড়া)
STORE Rs, addr ; Memory[addr] ← Rs (memory-তে লেখা)Instruction format (১৬ বিট, সরলীকৃত — বাস্তব encoding Level 3-এর বিষয়):
বিট: 15 14 | 13 12 11 | 10 9 8 | 7 6 5 | 4 ... 0
┌─────┬─────────┬────────┬───────┬─────────┐
ADD │ opcode│ Rd │ Rs │ Rt │ (অব্যবহৃত)│
├─────┼─────────┼──────────────────────────┤
LOAD │ opcode│ Rd │ addr (১১ বিট) │
├─────┼─────────┼──────────────────────────┤
STORE │ opcode│ Rs │ addr (১১ বিট) │
└─────┴─────────┴──────────────────────────┘
opcode: 00=ADD, 01=LOAD, 10=STORE (২ বিট, ৪-to-1 এনকোডিং সম্ভব, ১১ ব্যবহৃত হয়নি)
Rd/Rs/Rt: ৩ বিট → R0-R7 (৮টা register)
addr: ১১ বিট → 2048 word addressable memory (গত লেসনের 2048-row উদাহরণের ঠিক সমান!)Datapath-এর উপাদান তালিকা
| উপাদান | কোন লেসনের | ভূমিকা এখানে |
|---|---|---|
| Instruction Register (IR) | লেসন ১০ (register) | সক্রিয় instruction ধরে রাখে |
| Register File | লেসন ১০ | ৮টা register, ২টা read port + ১টা write port |
| ALU | লেসন ৮ | Rs + Rt গণনা করে (এই ISA-তে শুধু ADD লাগে) |
| ALUOut register | লেসন ১০ | ALU-র ফলাফল সাময়িকভাবে ধরে রাখে |
| Data Memory | লেসন ১৪ | 2048 × 16 — SRAM/DRAM addressing মডেল |
| MDR (Memory Data Register) | লেসন ১০ | Memory থেকে পড়া মান সাময়িকভাবে ধরে রাখে |
| MemToReg MUX | লেসন ৭ | ALUOut বনাম MDR — কোনটা register file-এ লেখা হবে বাছে |
| Control Unit | লেসন ১২ (FSM) | সবকিছুর control signal নির্ধারণ করে |
সম্পূর্ণ Datapath — ব্লক ডায়াগ্রাম
instruction in (বাইরে থেকে, "already fetched")
│
▼
┌─────────┐ IRWrite (control signal)
│ IR │◄──────────────────────
│ (16-bit)│
└─┬──┬──┬─┘
│ │ └─── addr[10:0] ──────────────────────────────┐
│ │ │
Rd/Rs[13:11] Rt[10:8] │
│ │ (LOAD/STORE-এ addr, ADD-এ Rt) │
▼ ▼ │
┌───────────────────┐ │
│ Register File │ RegWrite (control signal) │
│ 8 × 16, 2R1W │◄──────────────────────────────┐ │
└──┬─────────────┬───┘ │ │
RF[Rs] RF[Rt] │ │
│ │ │ │
▼ ▼ │ │
┌───────────────────────┐ │ │
│ ALU │ (এই ISA-তে সবসময় ADD) │ │
│ Rs + Rt │ │ │
└───────────┬─────────────┘ │ │
▼ │ │
┌───────────┐ │ │
│ ALUOut │ │ │
└─────┬─────┘ │ │
│ ┌──────────┘ │
│ MemWrite ────┤ data=RF[Rs] │
│ ▼ │
│ ┌───────────────┐ │
│ │ Data Memory │◄────┘ address = IR.addr[10:0]
│ │ 2048 × 16 │
│ └───────┬───────┘
│ MemRead ─────┤
│ ▼
│ ┌───────────┐
│ │ MDR │
│ └─────┬─────┘
▼ ▼
┌───────────────────────────────────────────────┐
│ MUX ◄── select: MemToReg (control signal) │
│ 0 = ALUOut, 1 = MDR │
└───────────────────────┬─────────────────────────┘
▼
Register File write port (RF[Rd] ← এই মান)লক্ষ্য করুন — আমি ইচ্ছাকৃতভাবে address গণনার জন্য কোনো MUX রাখিনি; address সরাসরি IR-এর addr[10:0] ফিল্ড থেকে আসে। বাস্তব ISA-তে (base+offset addressing, যেমন LOAD R1, 4(R2)) address প্রায়ই ALU দিয়ে গণনা করতে হয় (register + offset) — তখন ALU-র দ্বিতীয় input-এ আরেকটা MUX লাগে (register value বনাম immediate offset বাছতে)। Level 3-এর addressing mode আলোচনায় এই MUX-টা ফিরে আসবে — আমাদের toy ISA-তে direct addressing ব্যবহার করে আমরা এই জটিলতা এড়িয়ে গেছি।
Control Unit — সংকেত তালিকা
| Signal | কোথায় যায় | 1 হলে কী ঘটে |
|---|---|---|
IRWrite | IR-এর write enable | নতুন instruction latch হয় |
RegWrite | Register file-এর write enable | MUX-এর output RF[Rd]-এ লেখা হয় |
MemRead | Data memory-র read enable | Memory[addr] পড়ে MDR-এ যায় |
MemWrite | Data memory-র write enable | RF[Rs] লেখা হয় Memory[addr]-এ |
MemToReg | MUX-এর select line | 0 = ALUOut, 1 = MDR |
শুধু পাঁচটা signal — এই ছোট ISA-র পুরো আচরণ এই পাঁচটা দিয়েই সম্পূর্ণভাবে নিয়ন্ত্রিত। লক্ষ্য করুন ALUOp নেই — কারণ আমাদের ALU-র একমাত্র কাজ যোগ করা, তাই কোনো operation select দরকার নেই। বাস্তব ISA-তে (যেখানে SUB, AND, OR, শিফট থাকে) এখানে একটা ALUOp signal যোগ হতো, আর লেসন ৮-এর সম্পূর্ণ ALU design (op-select সহ) সরাসরি কাজে লাগত।
Control Unit-কে FSM হিসেবে ডিজাইন — লেসন ১২-এর পদ্ধতি প্রয়োগ
প্রতিটা instruction ভিন্ন সংখ্যক clock cycle নেয় — ADD তিন cycle, LOAD তিন cycle, STORE দুই cycle। এই ভিন্নতাই বলে দেয় আমাদের একটা multi-cycle design দরকার, single-cycle না (নিচের “hood” অংশে এই সিদ্ধান্তের কারণ বিস্তারিত)।
┌─────────────┐
┌───────►│ S_DECODE │◄───────────┐
│ │ (IRWrite=1) │ │
│ └──┬───┬────┬─┘ │
│ opcode=ADD│ │opcode=LOAD opcode=STORE
│ │ │ │
│ ▼ ▼ ▼
│ ┌──────────────┐ ┌───────────────┐
│ │ S_ADD_EXEC │ │ S_MEM_READ │ ┌───────────────┐
│ │ ALU: Rs+Rt │ │ MemRead=1 │ │ S_MEM_WRITE │
│ │ → ALUOut │ │ → MDR │ │ MemWrite=1 │
│ └──────┬───────┘ └───────┬───────┘ └───────┬────────┘
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────────────┐ │
│ │ S_WB │ │
│ │ RegWrite=1 │ │
│ │ MemToReg = (opcode==LOAD) │ │
│ └───────────────┬───────────────┘ │
│ │ │
└───────────────────┴───────────────────────────────────┘
(সবগুলো path S_DECODE-এ ফিরে যায়)পাঁচটা state: S_DECODE, S_ADD_EXEC, S_MEM_READ, S_MEM_WRITE, S_WB। লক্ষ্য করুন S_WB state-টা দুইটা path-এই শেয়ার করা — ADD আর LOAD দুটোই শেষে register file-এ লেখে, তাই একই “writeback” state পুনর্ব্যবহার করা হয়েছে, শুধু MemToReg সংকেতটা ভিন্ন মান নেয়। এটাই multi-cycle design-এর একটা মূল সুবিধা — hardware পুনর্ব্যবহার।
সম্পূর্ণ Control Signal Truth Table
এটাই control unit-এর “সিগন্যাল টেবিল” — প্রতিটা state-এ প্রতিটা signal-এর মান:
| State | IRWrite | RegWrite | MemRead | MemWrite | MemToReg | Next state |
|---|---|---|---|---|---|---|
S_DECODE | 1 | 0 | 0 | 0 | – | opcode অনুযায়ী (নিচে) |
S_ADD_EXEC | 0 | 0 | 0 | 0 | – | S_WB |
S_MEM_READ | 0 | 0 | 1 | 0 | – | S_WB |
S_MEM_WRITE | 0 | 0 | 0 | 1 | – | S_DECODE |
S_WB | 0 | 1 | 0 | 0 | (opcode==LOAD) | S_DECODE |
S_DECODE-এর next-state যুক্তি:
IR.opcode | Next state |
|---|---|
00 (ADD) | S_ADD_EXEC |
01 (LOAD) | S_MEM_READ |
10 (STORE) | S_MEM_WRITE |
এই দুইটা টেবিল একসাথে control unit-কে সম্পূর্ণভাবে সংজ্ঞায়িত করে — লেসন ১২-তে শেখা পদ্ধতিতে, এই টেবিল থেকে সরাসরি state register (flip-flop) + combinational next-state logic + combinational output logic বানানো যায়। পরবর্তী লেসনে আমরা এই একই টেবিলটাকে Verilog case statement-এ রূপান্তর করব — লক্ষ্য করবেন রূপান্তরটা প্রায় যান্ত্রিক।
ভেতরে কী ঘটছে
এই পুরো জিনিসটা আসলে কী দিয়ে তৈরি — উপর থেকে নিচে
এখন প্রশ্ন করা যাক: “CPU” শব্দটার নিচে সত্যিই কী আছে? উত্তরটা এই মডিউলের প্রতিটা লেসনের একটা সরাসরি স্তর।
- CPU একটা instruction execute করছেউপরের abstraction — Level 3-এ এটাই শুরুর বিন্দু
- Control unit FSM একটা state-এ আছেএই লেসনের S_DECODE/S_ADD_EXEC/... এর একটা
- FSM = state register + combinational logicলেসন ১২ — flip-flop-এ state, gate-এ next-state/output logic
- Datapath component-গুলো signal অনুযায়ী সাড়া দেয়Register file, ALU, memory — control signal দিয়ে গেটেড
- ALU = adder সার্কিটলেসন ৪-৮ — gate দিয়ে বানানো bit-by-bit addition
- Register/ALUOut/MDR/IR = flip-flop-এর সারিলেসন ৯-১০ — cross-coupled feedback প্রতিটা bit-এ
- Register file = multi-port SRAMলেসন ১৪ — একাধিক read/write port সহ SRAM cell
- Data memory = SRAM/DRAM array + decoderলেসন ১৪ — row decoder + column mux
- সবকিছুই = CMOS gate = transistorলেসন ১-৩ — একদম নিচের স্তর
কোনো একটা স্তরেই “যাদু” নেই। প্রতিটা তীর একটা লেসনে ব্যাখ্যা করা হয়েছে, আর প্রতিটা লেসন হাতে-কলমে যাচাইযোগ্য। এটাই এই লেসনের কেন্দ্রীয় দাবি।
Single-cycle বনাম Multi-cycle — কেন আমরা multi-cycle বেছে নিলাম
আমাদের ISA-তে ADD/LOAD তিন ধাপ লাগে, STORE দুই ধাপ। এখানে দুইটা মৌলিক ভিন্ন design strategy সম্ভব:
Single-cycle design
প্রতিটা instruction ঠিক এক clock cycle-এ শেষ হয় — সেই cycle-টা যথেষ্ট লম্বা রাখা হয় সবচেয়ে ধীর instruction-এর জন্য (এখানে ADD/LOAD, যেগুলোর register read + ALU/memory + writeback সবকিছু এক cycle-এই ঘটতে হবে)। এর জন্য datapath-এ প্রতিটা সম্ভাব্য পথ সমান্তরালে hardware দিয়ে বানাতে হয় — কোনো ALUOut/MDR register লাগে না (সবকিছু combinationally এক cycle-এই প্রবাহিত হয়), কিন্তু control unit অনেক সরল হয়ে যায়: কোনো state-ই লাগে না, শুধু opcode থেকে সরাসরি combinational logic দিয়ে control signal বের করা যায় (FSM-এর state register পর্যন্ত দরকার নেই)।
সমস্যা: STORE-এর কাজ ADD-এর চেয়ে কম, তবু STORE-কেও ADD-এর সমান দীর্ঘ cycle অপেক্ষা করতে হয় — clock period পুরো ISA-র সবচেয়ে ধীর instruction দিয়ে বাঁধা থাকে, প্রতিটা instruction-এই সেই সময় নষ্ট হয়।
Multi-cycle design (এই লেসনে যা ডিজাইন করলাম)
প্রতিটা instruction যতগুলো ছোট clock cycle দরকার ততগুলোই নেয় — STORE দুই cycle-এই শেষ, ADD/LOAD-এর জন্য বাড়তি সময় নষ্ট হয় না। বিনিময়ে control unit-এ একটা প্রকৃত state লাগে (আমাদের পাঁচটা state), আর datapath-এ মাঝপথের ফলাফল ধরে রাখার জন্য বাড়তি register (ALUOut, MDR) লাগে — যাতে একটা cycle-এর ফলাফল পরের cycle-এ ব্যবহার করা যায়।
তৃতীয় বিকল্প — Pipelining (শুধু নাম, বিস্তারিত Level 3)
আরেকটা কৌশল আছে যেটা single-cycle-এর গতি আর multi-cycle-এর দক্ষতা দুটোই একসাথে পেতে চায়: pipelining — একটা instruction-এর ভিন্ন ধাপ (fetch, decode, execute, …) ভিন্ন hardware stage-এ সমান্তরালে চালানো, যাতে একই সময়ে একাধিক instruction ভিন্ন ধাপে থাকে। এটা Level 3-এর একটা প্রধান বিষয় (hazard, forwarding, stalling সহ) — এখানে শুধু এইটুকু বলা যথেষ্ট: single-cycle, multi-cycle, pipelined — তিনটাই একই datapath component-গুলো ভিন্নভাবে সংগঠিত করার কৌশল, কোনোটাই নতুন hardware আবিষ্কার না।
Hardwired বনাম Microprogrammed Control
আমরা যেভাবে control unit ডিজাইন করলাম — state register + combinational next-state/output logic (গেট দিয়ে সরাসরি বানানো) — তাকে বলে hardwired control। এটা দ্রুত (গেট delay-তে সংকেত পাওয়া যায়) কিন্তু পরিবর্তন করা কঠিন — নতুন instruction যোগ করতে হলে গেট-লেভেল circuit নতুন করে ডিজাইন করতে হয়।
একটা বিকল্প পদ্ধতি: microprogrammed control — control signal-এর প্রতিটা সেট একটা ছোট “microinstruction”-এ encode করে একটা ROM (control store)-এ রাখা, আর control unit স্রেফ সেই ROM-এর মধ্য দিয়ে হাঁটে (একটা “micro-PC” দিয়ে)। এতে control unit ডিজাইন অনেকটা প্রোগ্রামিং-এর মতো হয়ে যায় — নতুন instruction যোগ করা মানে নতুন microcode লেখা, নতুন গেট ডিজাইন করা না।
| Hardwired | Microprogrammed | |
|---|---|---|
| গতি | দ্রুততর | কিছুটা ধীর (ROM lookup) |
| পরিবর্তনযোগ্যতা | কঠিন (নতুন গেট লাগে) | সহজ (নতুন microcode লিখুন) |
| জটিল ISA-তে | কষ্টসাধ্য | স্বাভাবিক |
| উদাহরণ | সাধারণত RISC | ঐতিহাসিকভাবে CISC (নিচে দেখুন) |
আমাদের এই লেসনের ৫-state, ৫-signal design এত ছোট যে hardwired করাই স্বাভাবিক পছন্দ — কিন্তু বাস্তব CISC processor-এ (যেমন পুরনো x86) শত শত জটিল instruction থাকে, যেখানে microcode ঐতিহাসিকভাবে ব্যবহারিক সমাধান ছিল। “Realworld” অংশে এই ইতিহাস বিস্তারিত।
উদাহরণ
সম্পূর্ণ Trace — চারটা instruction, cycle-বাই-cycle
ধরা যাক প্রোগ্রামটা:
LOAD R1, 100 ; R1 ← Memory[100]
LOAD R2, 104 ; R2 ← Memory[104]
ADD R3, R1, R2 ; R3 ← R1 + R2
STORE R3, 108 ; Memory[108] ← R3আর শুরুতে Memory[100] = 7, Memory[104] = 35।
| Cycle | Instruction | State | Control signal সক্রিয় | কী ঘটে |
|---|---|---|---|---|
| 1 | LOAD R1,100 | S_DECODE | IRWrite=1 | IR ← LOAD R1,100; opcode=LOAD |
| 2 | S_MEM_READ | MemRead=1 | Memory[100] পড়ে MDR ← 7 | |
| 3 | S_WB | RegWrite=1, MemToReg=1 | R1 ← MDR = 7 | |
| 4 | LOAD R2,104 | S_DECODE | IRWrite=1 | IR ← LOAD R2,104 |
| 5 | S_MEM_READ | MemRead=1 | Memory[104] পড়ে MDR ← 35 | |
| 6 | S_WB | RegWrite=1, MemToReg=1 | R2 ← MDR = 35 | |
| 7 | ADD R3,R1,R2 | S_DECODE | IRWrite=1 | IR ← ADD R3,R1,R2 |
| 8 | S_ADD_EXEC | (কোনো লেখা নেই) | ALU: R1+R2 = 42 → ALUOut ← 42 | |
| 9 | S_WB | RegWrite=1, MemToReg=0 | R3 ← ALUOut = 42 | |
| 10 | STORE R3,108 | S_DECODE | IRWrite=1 | IR ← STORE R3,108 |
| 11 | S_MEM_WRITE | MemWrite=1 | Memory[108] ← R3 = 42 |
মোট ১১ cycle, চারটা instruction। লক্ষ্য করুন STORE মাত্র ২ cycle নিলো (১০-১১), যেখানে LOAD/ADD তিনটা করে নিলো — ঠিক আমাদের FSM design অনুযায়ী। যদি এটা single-cycle হতো, প্রতিটা instruction-কে সবচেয়ে ধীর পথের (৩ cycle-এর সমান দৈর্ঘ্যের একটা লম্বা cycle) সমান সময় নিতে হতো — STORE-এর জন্যও, যদিও তার দরকার ছিল না।
নিজে চালিয়ে দেখুন
Logisim/Digital-এ এই datapath বানিয়ে ADD চালান
- আগের লেসনগুলোতে বানানো (বা নতুন করে বানানো)
8×16register file,16-বিট ALU (শুধু ADD), আর একটা2048×16RAM component জড়ো করুন। - একটা
16-বিট register বানানIRহিসেবে — input-এ একটা constant/switch bank দিয়ে instruction বিট সরবরাহ করুন (একে “already fetched instruction” হিসেবে ধরুন)। IR-এর bit field split করুন:[15:14]→ opcode আউটপুট,[13:11]→ Rd/Rs,[10:8]→ Rt,[10:0]→ addr।- Register file-এর দুইটা read address input-এ
IR[13:11]আরIR[10:8]যুক্ত করুন; write address input-এIR[13:11]। - ALU-এর দুই ইনপুটে register file-এর দুইটা read output যুক্ত করুন।
- একটা
ALUOutregister, একটাMDRregister, আর একটা2-to-1 MUX(MemToReg select) বসান, উপরের ব্লক ডায়াগ্রাম অনুযায়ী। - Control unit বানান একটা ছোট FSM হিসেবে —
stateএকটা ৩-বিট register (৫টা state এনকোড করতে যথেষ্ট), combinational logic দিয়ে next-state আর output signal বের করুন (সরাসরি উপরের control table থেকে)। - Clock-টা সব register-এ (IR, register file write, ALUOut, MDR, state register) common ভাবে যুক্ত করুন।
পরীক্ষা — ADD R3, R1, R2 (ধরুন R1=7, R2=35 আগে থেকে সেট করা):
১. IR-এ ADD R3,R1,R2 এনকোড করা বিট প্যাটার্ন সেট করুন
২. Clock ১ পালস দিন → state = S_DECODE হওয়ার কথা, IRWrite active দেখুন
৩. Clock ২ পালস দিন → state = S_ADD_EXEC, ALUOut-এ 42 আসার কথা
৪. Clock ৩ পালস দিন → state = S_WB, R3 = 42 হওয়ার কথা
৫. Register file-এর R3 output দেখে যাচাই করুনযদি R3 = 42 দেখেন, আপনার হাতে-আঁকা control table বাস্তবে কাজ করছে প্রমাণিত হলো। একই পদ্ধতিতে LOAD/STORE যাচাই করুন।
একটা register file + ALU + control FSM যখন সঠিকভাবে wire করা হয়, তখন হাতে আঁকা control table অনুযায়ী সত্যিই সঠিক আচরণ পাওয়া যায় — schematic আর বাস্তব সার্কিটের মধ্যে কোনো ফাঁক নেই।
উদাহরণ section-এর সম্পূর্ণ প্রোগ্রাম চালান
আগের experiment-এর circuit ব্যবহার করে:
Memory[100] = 7,Memory[104] = 35সেট করুন (RAM component-এ প্রি-লোড করে, বা প্রথমে দুইটাSTOREচালিয়ে)।IRinput-টাকে একটা ছোট “program” sequence-এ পরিণত করুন — প্রতিবারS_DECODE-এ ফিরে গেলে পরের instruction switch করে দিন (ম্যানুয়ালি, অথবা যদি সাহস থাকে একটা program counter + instruction memory যোগ করে — যদিও সেটা Level 3-এর পূর্ণাঙ্গ fetch mechanism, শুধু কৌতূহলের জন্য চেষ্টা করা যেতে পারে)।- এই লেসনের “example” section-এর চারটা instruction পরপর চালান।
- প্রতি ৩-৪ cycle পরপর register file আর memory-র মান লগ করুন, উপরের ১১-cycle table-এর সাথে মেলান।
প্রত্যাশিত চূড়ান্ত অবস্থা: R1=7, R2=35, R3=42, Memory[108]=42। যদি এটা মিলে যায়, আপনি হাতে দাঁড় করিয়েছেন একটা কার্যকরী (যদিও ক্ষুদ্র) CPU।
একাধিক instruction পরপর সঠিকভাবে চালানো যায় — একটা 'toy CPU' সত্যিই একটা ছোট প্রোগ্রাম এক্সিকিউট করতে পারে, শুধু একটা isolated instruction না।
নিজে বানান
সম্পূর্ণ 3-instruction CPU — datapath + control FSM
- IR, register file, ALU, ALUOut, Data Memory, MDR — প্রতিটা module আলাদাভাবে বানান ও যাচাই করুন
- উপরের ব্লক ডায়াগ্রাম অনুযায়ী সব bus এবং MUX wire করুন
- Control unit-কে একটা state register + combinational logic হিসেবে বানান, সরাসরি control table থেকে
- প্রতিটা instruction টাইপ আলাদাভাবে test করুন (ADD একা, LOAD একা, STORE একা)
- সম্পূর্ণ ৪-instruction প্রোগ্রামটা চালিয়ে চূড়ান্ত register/memory অবস্থা যাচাই করুন
- (চ্যালেঞ্জ) একটা চতুর্থ instruction যোগ করুন — যেমন SUB — আর দেখুন datapath আর control টেবিল দুটোতেই কী বদলাতে হয়
এটাই এই পুরো মডিউলের payoff project — এখান পর্যন্ত বানানো প্রতিটা টুকরো এখানে ব্যবহৃত হচ্ছে।
ধাপ ১ — Module-বাই-module যাচাই। প্রতিটা component (register file, ALU, memory) আলাদাভাবে test করুন, datapath-এ জোড়ার আগে। একটা register file যদি একা ভুল আচরণ করে, পুরো CPU-তে সেই bug খুঁজে বের করা অনেক কঠিন হবে।
ধাপ ২ — Datapath wire করা। উপরের ব্লক ডায়াগ্রাম-টা একদম আক্ষরিকভাবে অনুসরণ করুন। প্রতিটা bus-এর width নোট করুন (16-বিট data, 11-বিট address, 3-বিট register number, 2-বিট opcode)।
ধাপ ৩ — Control unit। State encoding বাছুন (৩ বিট যথেষ্ট 5-টা state-এর জন্য)। Next-state logic আর output logic দুটোই সরাসরি উপরের truth table থেকে — কোনো নতুন সিদ্ধান্ত নেওয়ার দরকার নেই, শুধু টেবিলটা গেটে রূপান্তর করুন (লেসন ১২-এর FSM-থেকে-circuit পদ্ধতি)।
ধাপ ৪-৫ — টেস্টিং। প্রতিটা instruction টাইপ আলাদাভাবে, তারপর একসাথে sequence-এ। “উদাহরণ” section-এর ১১-cycle table-টাই আপনার expected output — প্রতিটা cycle-এ signal আর ডেটা মিলিয়ে দেখুন।
ধাপ ৬ (চ্যালেঞ্জ) — একটা instruction যোগ করা। SUB Rd, Rs, Rt যোগ করতে কী লাগবে?
- Opcode encoding-এ একটা নতুন কোড দরকার (যেমন
11) - ALU-তে এখন দুইটা operation দরকার (ADD, SUB) — অর্থাৎ একটা
ALUOpcontrol signal ফিরে আসে, লেসন ৮-এর op-select ALU সরাসরি কাজে লাগবে - Control table-এ একটা নতুন state (বা
S_ADD_EXEC-কে পুনর্ব্যবহার করেALUOpদিয়ে পার্থক্য করা) দরকার - Datapath-এর কোনো নতুন বাস/MUX লাগবে না — শুধু ALU-র ক্ষমতা আর control logic বাড়ে
এই ছোট চ্যালেঞ্জটাই দেখায় কীভাবে datapath আর control একসাথে evolve করে — নতুন instruction মানে সবসময় নতুন hardware না, প্রায়ই existing hardware-এর নতুন combination।
বাস্তব সিস্টেমে
Datapath+control বাস্তব সিস্টেমে
MIPS single-cycle ও multi-cycle datapath (Patterson & Hennessy) — এই লেসনের toy design সরাসরি এই বিখ্যাত পাঠ্যপুস্তক ডিজাইন থেকে অনুপ্রাণিত, শুধু বহুগুণ ছোট করে। কম্পিউটার আর্কিটেকচার কোর্সে দশকের পর দশক ধরে পড়ানো এই diagram-টাই একই মূলনীতির একটা পূর্ণাঙ্গ (৩২টা instruction পর্যন্ত সমর্থনকারী) সংস্করণ।
MOS 6502 (Apple II, NES, Commodore 64, BBC Micro) — একটা ঐতিহাসিকভাবে গুরুত্বপূর্ণ, তুলনামূলক সরল ৮-বিট CPU, যেটা এতটাই সহজবোধ্য যে visual6502.org প্রজেক্ট এর প্রতিটা transistor (মাত্র ~3510-টা) reverse-engineer করে সম্পূর্ণ simulator বানিয়েছে — এই লেসনের “প্রতিটা স্তর transparent” দাবিটার একটা চূড়ান্ত, বাস্তব প্রমাণ।
PicoRV32 ও SERV — আধুনিক open-source RISC-V core। PicoRV32 একটা compact multi-cycle-স্টাইল implementation। SERV (“Serial RISC-V”) আরও চরম — একটা bit-serial CPU, যেখানে ALU একবারে মাত্র ১ বিট প্রসেস করে (৩২-বিট operation-এ ৩২ cycle লাগে) — extreme area-efficiency-র জন্য multi-cycle নীতির একটা চূড়ান্ত প্রয়োগ, ঠিক এই লেসনের “কম hardware, বেশি cycle” trade-off-এর যুক্তিতে।
IBM System/360 (১৯৬৪) ও microcode-এর জন্ম — IBM-এর যুগান্তকারী সিদ্ধান্ত ছিল একটা একক ISA দিয়ে দাম ও ক্ষমতায় সম্পূর্ণ ভিন্ন কয়েকটা physical machine তৈরি করা। সস্তা মডেলে hardwired control, দামি মডেলে বেশি সমান্তরাল hardware — কিন্তু প্রোগ্রামারের কাছে সবগুলো একই রকম দেখাত, কারণ microcode একটা সাধারণ interface তৈরি করত আলাদা physical datapath-এর উপরে। এটাই আধুনিক ISA-abstraction ধারণার একটা প্রথম বড় বাণিজ্যিক প্রয়োগ।
x86 internally RISC-এ অনুবাদ — Intel Pentium Pro (১৯৯৫) থেকে শুরু করে আধুনিক x86 processor জটিল CISC instruction-কে হার্ডওয়্যারে সরাসরি চালায় না — বরং একটা internal “decode” স্তর প্রতিটা x86 instruction-কে ছোট ছোট RISC-স্টাইল micro-op-এ ভেঙে ফেলে, যেগুলো একটা তুলনামূলক সরল, দ্রুত internal datapath-এ চলে। এটা আধুনিক যুগের microcode — পুরনো IBM System/360-এর একই ধারণার একটা বিবর্তিত রূপ।
FPGA soft-core CPU (Xilinx MicroBlaze, Intel/Altera Nios II) — এগুলো এই লেসনে যা শিখলেন তারই বাণিজ্যিক, production-grade রূপ — একটা synthesizable datapath+control design যেটা যেকোনো FPGA-তে বসিয়ে দেওয়া যায় custom embedded system বানাতে, physical silicon না বানিয়েই।
Nand2Tetris (“The Elements of Computing Systems”) — এই লেসনের spirit-এর সবচেয়ে কাছের শিক্ষামূলক প্রজেক্ট। এই বইয়ে পাঠক gate থেকে শুরু করে ঠিক এই লেসনে যা করলাম তারই একটা পূর্ণাঙ্গ সংস্করণ বানায় — নিজস্ব ALU, register, memory, আর একটা সম্পূর্ণ CPU (নাম “Hack”)। যদি এই লেসনটা ভালো লেগে থাকে, এই বই/কোর্সটাই স্বাভাবিক পরবর্তী গন্তব্য।
যে ভুলগুলো সবাই করে
“CPU ডিজাইন শুরু হয় Verilog/কোড লেখা দিয়ে।”
না — এই লেসন নিজেই তার প্রমাণ। আমরা একটা লাইনও কোড না লিখে সম্পূর্ণ datapath আর control unit ডিজাইন করে ফেলেছি: block diagram, control signal table, FSM state diagram। পরের লেসনে আমরা এই একই ডিজাইনটাকে Verilog-এ প্রকাশ করব — কিন্তু ডিজাইনের চিন্তাটা (কোন component লাগবে, কীভাবে জোড়া লাগবে, কোন signal কখন assert হবে) সম্পূর্ণভাবে HDL ছাড়াই ঘটে। HDL একটা নোটেশন, ডিজাইন প্রক্রিয়া না — ঠিক যেমন algorithm ডিজাইন করা আর সেটা কোনো নির্দিষ্ট programming language-এ লেখা দুইটা আলাদা কাজ।
“Datapath আর control unit চিপের দুইটা আলাদা, শারীরিকভাবে পৃথক অংশ।”
ভুল ধারণা। “Datapath” আর “control unit” একটা conceptual/architectural বিভাজন, কোনো physical অবস্থানের বিভাজন না। বাস্তব সিলিকনে control unit-এর গেটগুলো আর datapath-এর গেটগুলো একই die-তে পাশাপাশি, প্রায়ই interleaved অবস্থায় থাকে — কোনো দৃশ্যমান “দেয়াল” নেই তাদের মাঝে। বিভাজনটা আমাদের চিন্তা করার সুবিধার জন্য — “কে ডেটা প্রসেস করছে” বনাম “কে সিদ্ধান্ত নিচ্ছে” — ঠিক যেভাবে সফটওয়্যারে আমরা “business logic” আর “control flow” আলাদা করে কথা বলি, যদিও একই ফাইলে, একই ফাংশনে মিশে থাকতে পারে।
“Single-cycle design সহজ, তাই বাস্তব CPU-তে এটাই বেশি ব্যবহার হয়।”
উল্টো — single-cycle ডিজাইন করা concept-এ সহজ (control unit-এ কোনো state লাগে না), কিন্তু performance-এ খারাপ। Clock period পুরো ISA-র সবচেয়ে ধীর instruction অনুযায়ী বাঁধা থাকে বলে প্রতিটা instruction (এমনকি দ্রুততমগুলোও) সেই দীর্ঘ সময় নেয়। বাস্তব উচ্চ-performance CPU প্রায় সবসময় pipelined (Level 3-এর বিষয়) — যেটা single-cycle-এর মতো প্রতি cycle-এ progress করে, কিন্তু multi-cycle-এর মতো বিভিন্ন কাজ বিভিন্ন hardware stage-এ ভাগ করে। Single-cycle মূলত একটা শিক্ষামূলক সরলীকরণ — বোঝা সহজ, কিন্তু বাণিজ্যিক CPU-তে বিরল।
“ISA-তে instruction সংখ্যা বাড়ালে শুধু control unit জটিল হয়, datapath অপরিবর্তিত থাকে।”
প্রায়ই ভুল। BuildIt-এর SUB চ্যালেঞ্জ ঠিক এটা দেখায় — নতুন instruction টাইপ যোগ করলে datapath-এও নতুন ক্ষমতা লাগতে পারে (এখানে: ALU-তে একটা নতুন operation, তাই একটা নতুন ALUOp control input)। Control unit আর datapath একসাথে co-design হয় — একটা নতুন instruction মানে সাধারণত দুটোতেই কিছু না কিছু পরিবর্তন, কখনো datapath-এ নতুন MUX/bus, কখনো শুধু control table-এ নতুন state/সংকেত সংমিশ্রণ।
বুঝেছেন কি না দেখুন
1Datapath আর control unit-এর মধ্যে মৌলিক পার্থক্য কী? একটা সহজ উদাহরণ দিয়ে ব্যাখ্যা করুন।
যুক্তি
Datapath হলো সেই সার্কিট যার মধ্য দিয়ে প্রকৃত ডেটা প্রবাহিত হয় ও রূপান্তরিত হয় — register, ALU, memory, MUX, bus। এটা “কাজ করে” কিন্তু নিজে সিদ্ধান্ত নেয় না।
Control unit হলো একটা FSM যেটা datapath-কে বলে দেয় প্রতি cycle-এ কী করতে হবে — কোন MUX কোন input বাছবে, কোন register write হবে। এটা “সিদ্ধান্ত নেয়” কিন্তু নিজে ডেটা প্রসেস করে না।
উদাহরণ (এই লেসনের ADD instruction): ALU যখন R1 + R2 গণনা করে, সেটা datapath-এর কাজ — প্রকৃত যোগফল বের হচ্ছে সেখানে। কিন্তু ALU-কে কখন এই গণনা করতে হবে, আর ফলাফলটা কোথায় যাবে (ALUOut-এ, তারপর কোন register-এ) — এই সিদ্ধান্তগুলো control unit-এর, S_ADD_EXEC আর S_WB state-এর signal দিয়ে।
সংক্ষেপে: datapath = “কী কাজ করা সম্ভব”, control unit = “কখন, কোনটা করা হবে”।
2আমাদের ISA-তে যদি একটা নতুন instruction MOVE Rd, Rs (শুধু Rd ← Rs, কোনো ALU operation ছাড়াই) যোগ করা হয়, তাহলে কয়টা cycle লাগবে বলে আপনি আশা করেন, আর কোন state(গুলো) ব্যবহার হবে?
প্রয়োগ
MOVE Rd, Rs (শুধু Rd ← Rs, কোনো ALU operation ছাড়াই) যোগ করা হয়, তাহলে কয়টা cycle লাগবে বলে আপনি আশা করেন, আর কোন state(গুলো) ব্যবহার হবে?MOVE-এর জন্য কোনো ALU গণনা লাগে না, কোনো memory access লাগে না — শুধু register file-এর একটা read আর একটা write। এটা তাত্ত্বিকভাবে দুই cycle-এই সম্ভব:
S_DECODE—IRWrite=1, opcode চেনা যায়MOVEহিসেবে- একটা নতুন state, ধরুন
S_MOVE_WB—RegWrite=1, কিন্তু write data সরাসরিRF[Rs]থেকে আসতে হবে, ALUOut বা MDR থেকে না
এখানে একটা সমস্যা দেখা দেয়: আমাদের বর্তমান MemToReg MUX-এ শুধু দুইটা input আছে (ALUOut, MDR) — RF[Rs]-কে সরাসরি register file-এর write port-এ ফিরিয়ে দেওয়ার কোনো path নেই। তাই datapath-এ একটা পরিবর্তন লাগবে — হয় MemToReg MUX-এ তৃতীয় input যোগ করে (২-বিট select দরকার হবে ৩টা option-এর জন্য), অথবা ALU-কে “pass-through” করানো (ALU output = A input, একটা বিশেষ ALUOp দিয়ে) — এই দ্বিতীয় উপায়ে ALU নিজেই বিদ্যমান path পুনর্ব্যবহার করে, কোনো নতুন MUX input লাগে না।
এই প্রশ্নটা Misconception অংশের শেষ পয়েন্টটাই প্রমাণ করে — একটা “সহজ মনে হওয়া” instruction-ও datapath-এ (ছোট হলেও) পরিবর্তন দাবি করতে পারে।
3কেন S_WB state-টা ADD আর LOAD উভয়ের জন্য শেয়ার করা যায়, কিন্তু S_MEM_WRITE-এর নিজস্ব state দরকার (কোনো কিছুর সাথে শেয়ার করা যায় না)?
যুক্তি
S_WB state-টা ADD আর LOAD উভয়ের জন্য শেয়ার করা যায়, কিন্তু S_MEM_WRITE-এর নিজস্ব state দরকার (কোনো কিছুর সাথে শেয়ার করা যায় না)?S_WB শেয়ার করা যায় কারণ ADD আর LOAD দুটোই শেষ ধাপে একই কাজ করে — register file-এর write port-এ কিছু একটা লেখা (RegWrite=1)। পার্থক্য শুধু কোন ডেটা লেখা হচ্ছে (ALUOut বনাম MDR), আর সেটা MemToReg সংকেত দিয়ে সামলানো হয়, যেটা IR-এর opcode থেকে নির্ধারিত হয় (Q1-এর callout দ্রষ্টব্য)। একই hardware path (register file write port), শুধু ভিন্ন input উৎস — তাই state শেয়ার করা স্বাভাবিক ও efficient।
S_MEM_WRITE-এর কাজ (RF[Rs] কে Memory[addr]-এ লেখা) সম্পূর্ণ ভিন্ন destination (memory, register file না) আর ভিন্ন উৎস (RF[Rs], ALUOut/MDR না) ব্যবহার করে — কোনো বিদ্যমান state-এর সাথে এই কাজের datapath path মেলে না, তাই একটা আলাদা state লাগে।
সাধারণ নীতি: দুইটা instruction path একটা state শেয়ার করতে পারে যদি তাদের সেই ধাপে একই control signal সেট এবং একই datapath connectivity লাগে (হয়তো ভিন্ন operand সহ) — শুধু “প্রায় একই রকম কাজ” যথেষ্ট না, hardware path-টা আক্ষরিকভাবে একই হতে হবে।
4Single-cycle সংস্করণে (এই লেসনের multi-cycle না) control unit-এ কোনো state লাগে না বলা হয়েছে। কেন? Control signal তাহলে কীভাবে নির্ধারিত হয়?
ডিজাইন
Multi-cycle design-এ state লাগে কারণ একটা instruction একাধিক cycle জুড়ে ভিন্ন ভিন্ন কাজ করে — control unit-কে “মনে রাখতে” হয় এখন কোন ধাপে আছে (S_DECODE? S_ADD_EXEC? S_WB?)। এই “মনে রাখা”-টাই state, যেটা flip-flop-এ সংরক্ষিত থাকে।
Single-cycle design-এ একটা instruction এক cycle-এই সম্পূর্ণ — কোনো “ধাপ” নেই মনে রাখার মতো, কারণ পুরো কাজ একই cycle-এ combinationally ঘটে যায় (register read → ALU → memory (দরকার হলে) → register write, সব এক clock edge-এর মধ্যে, বিভিন্ন সমান্তরাল hardware দিয়ে)। তাই control signal সরাসরি শুধুমাত্র বর্তমান instruction-এর opcode-এর একটা combinational ফাংশন:
RegWrite = (opcode == ADD) OR (opcode == LOAD)
MemRead = (opcode == LOAD)
MemWrite = (opcode == STORE)
MemToReg = (opcode == LOAD)কোনো state register, কোনো clock-চালিত transition দরকার নেই — শুধু একটা decoder + কিছু গেট, ঠিক লেসন ৭-এর combinational logic-এর মতো। এই সরলতাই single-cycle-এর আকর্ষণ, কিন্তু এর মূল্য দিতে হয় clock period-এ (Misconception অংশ দ্রষ্টব্য)।
5যদি STORE-এর ঠিকানা গণনা করতে হতো base + offset (দুইটা যোগ করে, direct address না) — datapath-এ কী কী নতুন উপাদান লাগত?
প্রয়োগ
STORE-এর ঠিকানা গণনা করতে হতো base + offset (দুইটা যোগ করে, direct address না) — datapath-এ কী কী নতুন উপাদান লাগত?বর্তমান ডিজাইনে address সরাসরি IR-এর একটা ফিল্ড থেকে আসে (কোনো গণনা লাগে না)। base + offset addressing-এ address-টা গণনা করতে হবে — এখানে ALU-ই স্বাভাবিক পছন্দ, যেহেতু সেটা ইতিমধ্যেই যোগ করতে পারে। কিন্তু তাহলে দুইটা সমস্যা সমাধান করতে হবে:
১. ALU-এর input-এ একটা MUX দরকার হবে — কখনো ALU দুইটা register value যোগ করবে (ADD instruction-এর জন্য), কখনো একটা register (base) আর instruction-এর ভেতরের একটা immediate/offset ফিল্ড যোগ করবে (address গণনার জন্য)। তাই ALU-এর দ্বিতীয় input-এ একটা MUX লাগবে: register value বনাম sign-extended immediate।
২. Address-এর উৎস বদলাবে — Data memory-র address input এখন সরাসরি IR.addr থেকে না এসে ALUOut থেকে আসবে (কারণ ঠিকানাটা এখন ALU দিয়ে গণনা করা)।
৩. Control unit-এ একটা নতুন state (বা বিদ্যমান state-এর পুনর্ব্যবহার) লাগবে — address গণনার জন্য একটা S_MEM_ADDR ধরনের ধাপ, যেটা ALU: base + offset → ALUOut করে, তারপর পরের state-এ সেই ALUOut-কে address হিসেবে ব্যবহার করে memory access করে।
এটাই বাস্তব ISA-তে (যেমন MIPS-এর lw/sw) ঠিক যেভাবে কাজ করে — আর দেখায় কেন “সরল মনে হওয়া” ফিচার (base+offset addressing, খুবই সাধারণ) datapath-এ একাধিক নতুন উপাদান দাবি করে।
6আপনার এক বন্ধু বলছে, “যেহেতু control unit-ই সব সিদ্ধান্ত নেয়, আমরা datapath আরও ‘বোকা’ (dumb) বানিয়ে সব logic control unit-এ সরিয়ে দিতে পারি — datapath শুধু wire আর register হবে।” এই দাবিটা কতটা যুক্তিসঙ্গত?
ডিজাইন
আংশিক ভুল — একটা গুরুত্বপূর্ণ সীমা আছে। Control unit শুধু কোন signal কখন high/low হবে সেটা ঠিক করে — কিন্তু ALU-এর মধ্যে Rs + Rt গণনা করার জন্য প্রকৃত adder circuit (গেট দিয়ে বানানো, লেসন ৪-৮) থাকতেই হবে। এই গণনাটা control unit “সিদ্ধান্ত” দিয়ে করতে পারে না — control unit একটা FSM, এতে কোনো arithmetic capability নেই, এটা শুধু ০/১ সংকেত তৈরি করতে পারে।
তাই সীমাটা এরকম: control unit datapath-কে বলতে পারে কখন আর কোন input দিয়ে একটা operation করতে হবে, কিন্তু operation-টা নিজে সম্পন্ন করার সামর্থ্য (adder, memory array, register storage) datapath-এই থাকতে হবে। এই বিভাজনটাই আসলে datapath/control-এর সংজ্ঞা — যদি সব “বুদ্ধি” control unit-এ সরিয়ে নেওয়া হয়, control unit নিজেই একটা ALU হয়ে যাবে, আর তখন সেটা আর “control unit” থাকবে না, datapath-এর অংশ হয়ে যাবে। নামকরণ যাই হোক, কাজটা (arithmetic gate দিয়ে করতে হবে) অপরিবর্তনীয়।
আপনার বন্ধুর অন্তর্দৃষ্টি একদিক থেকে ঠিক — datapath-কে যতটা সম্ভব সরল/পুনর্ব্যবহারযোগ্য রাখা ভালো ডিজাইন (এই লেসনের S_WB state শেয়ারিং ঠিক এই নীতি) — কিন্তু “সব logic control unit-এ” একটা category error, কারণ control unit আর datapath ভিন্ন ধরনের কাজ করে, একটা আরেকটাকে প্রতিস্থাপন করতে পারে না।
এরপর কী
এরপর কী
আজকের লেসনে আমরা এই মডিউলের সবগুলো টুকরো — register file, ALU, memory, MUX — একটা bus system দিয়ে জুড়ে দিয়েছি, আর তার উপর একটা FSM (control unit) বসিয়ে একটা কার্যকরী, যদিও ক্ষুদ্র, CPU দাঁড় করিয়েছি। block diagram, control signal table, cycle-বাই-cycle trace — সবকিছুই হাতে, schematic-এ, কোনো HDL ছাড়াই।
কিন্তু বাস্তব CPU-তে কোটি কোটি transistor থাকে — schematic হাতে আঁকা সেখানে অসম্ভব। এই মডিউলের শেষ লেসনে আমরা দেখব ইন্ডাস্ট্রি এই সমস্যাটা কীভাবে সমাধান করে: একটা Hardware Description Language (HDL) দিয়ে — Verilog। আপনি দেখবেন এই লেসনের datapath আর control table কীভাবে প্রায় সরাসরি (mechanical ভাবে) কোডে রূপান্তরিত হয়ে যায় — আর সেই কোডকে একটা tool কীভাবে হাতে-আঁকা schematic-এর সমতুল্য গেট-লেভেল circuit-এ পরিণত করে।
আরও পড়ুন
- Computer Organization and Design (RISC-V Edition), Chapter 4 — David A. Patterson, John L. Hennessy · Multi-cycle datapath ও control unit ডিজাইনের প্রামাণ্য পদ্ধতি — এই লেসনের toy design এখান থেকে অনুপ্রাণিত
- The Elements of Computing Systems (nand2tetris) — Noam Nisan, Shimon Schocken · গেট থেকে সম্পূর্ণ CPU পর্যন্ত হাতে-কলমে বানানোর একটা চমৎকার শিক্ষামূলক প্রজেক্ট — এই লেসনের spirit-এর সবচেয়ে কাছের বই
- Digital — a logic simulator — Helmut Neemann · এই লেসনের datapath+control experiment/build-এর জন্য প্রস্তাবিত টুল