SRAM ও DRAM — একটা bit-কে ভৌতভাবে ধরে রাখা
SRAM and DRAM — Memory Cells
SRAM 6 transistor দিয়ে feedback-এ bit ধরে রাখে — দ্রুত কিন্তু ব্যয়বহুল। DRAM 1 transistor + 1 capacitor দিয়ে — সস্তা ও ঘন কিন্তু leak করে, তাই refresh লাগে। দুটোই address হয় row decoder আর column mux দিয়ে।
আগে এটা বুঝি
গত লেসনে আমরা flip-flop বানিয়েছি — কয়েকটা gate দিয়ে feedback loop, যেটা এক bit মনে রাখে। Register বানিয়েছি — কয়েকটা flip-flop পাশাপাশি। কিন্তু এখন প্রশ্নটা স্কেল করি।
আপনার ল্যাপটপে ১৬ GB RAM আছে ধরুন। সেটা মানে ১২৮ বিলিয়ন bit — প্রতিটাকে আলাদাভাবে সংরক্ষণ করতে হবে, প্রতিটাকে আলাদাভাবে address করা যেতে হবে, আর পুরো জিনিসটা একটা আঙুলের নখের সমান সিলিকনে বসতে হবে।
গত লেসনের D flip-flop-টা আবার দেখুন — সেটা বানাতে লাগে অন্তত ২০টা transistor (দুইটা cross-coupled NOR latch, mux-based edge triggering, বাড়তি gate)। ১২৮ বিলিয়ন bit-এর জন্য যদি প্রতি bit-এ ২০টা transistor লাগে, তাহলে দরকার ২.৫ ট্রিলিয়ন transistor — শুধু memory-র জন্য।
এটা বাস্তবে হয় না। কারণ engineer-রা memory-র জন্য flip-flop ব্যবহার করেন না — তারা প্রশ্নটাকে নতুন করে করেন: “শুধু একটা bit ধরে রাখতে ন্যূনতম কয়টা transistor লাগে?”
উত্তর দুইটা, দুই ভিন্ন trade-off-এ:
- SRAM (Static RAM): ৬টা transistor। দ্রুত, নির্ভরযোগ্য, কিন্তু জায়গা বেশি লাগে।
- DRAM (Dynamic RAM): ১টা transistor + ১টা capacitor। প্রায় ৬ গুণ ঘন, কিন্তু একটা বাড়তি সমস্যা নিয়ে আসে যেটা প্রতি ৬৪ মিলিসেকেন্ডে সমাধান করতে হয়।
এই লেসনে আমরা দুটোই ট্রানজিস্টর লেভেলে দেখব — কীভাবে প্রতিটা bit শারীরিকভাবে সংরক্ষিত হয়, কেন DRAM-কে ক্রমাগত “রিফ্রেশ” করতে হয়, আর একটা বিশাল array-তে একটা নির্দিষ্ট bit-কে কীভাবে ঠিকানা (address) দিয়ে খুঁজে বের করা হয়। লেসন ১৫-তে এই memory-টাই ALU আর register file-এর সাথে wire হয়ে datapath-এর অংশ হবে।
এই বিভাজনটা — SRAM বনাম DRAM — আসলে কম্পিউটিং-এর ইতিহাসে বারবার ফিরে আসা একটা প্যাটার্নের প্রথম উদাহরণ: একটা একক সমাধান সবসময় সব প্রয়োজন মেটায় না, তাই engineer-রা দুইটা (বা তার বেশি) trade-off point বেছে নেন আর তাদের মাঝে একটা সিঁড়ি বানান। এই লেসনের শেষে যখন আমরা দেখব cache কেন SRAM আর main memory কেন DRAM, সেটাই এই প্যাটার্নের প্রথম বাস্তব উদাহরণ — Level 3-এ memory hierarchy, Level 4-এ storage hierarchy (RAM বনাম disk), এমনকি Level 12-এ cloud storage tier (hot বনাম cold storage) পর্যন্ত এই একই যুক্তি বারবার ফিরে আসবে।
মূল ধারণা
SRAM — feedback দিয়ে ধরে রাখা
গত লেসনে flip-flop বানিয়েছিলাম gate দিয়ে — AND, OR, NOT-এর মতো সম্পূর্ণ, ready-made building block দিয়ে। SRAM cell একই ধারণা ব্যবহার করে, কিন্তু গেট-লেভেলে না নেমে সরাসরি transistor থেকে বানানো — কারণ গেট বানাতে গেলেই কয়েকটা transistor লাগে, আর memory-তে প্রতিটা transistor গুনতি হয়। এটাই SRAM-এর ৬T (6-transistor) cell-এর জন্ম।
গঠন — দুইটা inverter, মুখোমুখি
মূল অংশ হলো দুইটা CMOS inverter, ক্রস-কানেক্ট করা — প্রথমটার output দ্বিতীয়টার input, দ্বিতীয়টার output প্রথমটার input:
Vdd Vdd
│ │
─┴─ M2 (PMOS) ─┴─ M4 (PMOS)
┌─┘ ┌─┘
Q ●───────┤ ├───────● Q̄
└─┐ └─┐
─┬─ M1 (NMOS) ─┬─ M3 (NMOS)
│ │
GND GND
inverter #1 (M1,M2): input = Q̄, output = Q
inverter #2 (M3,M4): input = Q, output = Q̄
Word Line (WL)
│
┌───────────┼───────────┐
│ │
═══[M5]══ Q Q̄ ══[M6]═══
│ │
BL BL̄
(bit line) (bit line complement)প্রতিটা inverter-এর output অন্যটার input-এ যাচ্ছে — এটাই lesson ৯-এর SR latch-এর একই feedback trick, শুধু gate-level abstraction ছাড়াই, সরাসরি transistor দিয়ে। যদি Q = 1, তাহলে inverter #2 তাকে Q̄ = 0 বানায়, আর inverter #1 সেই 0-কে ফিরিয়ে Q = 1 বানায় — একটা স্থিতিশীল (stable) অবস্থা, যতক্ষণ Vdd সরবরাহ চালু থাকে। ঠিক তেমনি Q = 0, Q̄ = 1 আরেকটা স্থিতিশীল অবস্থা।
M1–M4 — চারটা transistor এই দুইটা inverter বানায়। বাকি M5, M6 — দুইটা access transistor, যেগুলোর gate word line (WL)-এর সাথে যুক্ত। মোট ৬টা transistor — তাই নাম 6T cell।
Read — খুব হালকা হাতে ছোঁয়া
- দুইটা bit line (BL, BL̄) কে প্রথমে precharge করা হয় — দুটোকেই
Vdd/2-এর কাছাকাছি একটা মধ্যবর্তী ভোল্টেজে টেনে রাখা হয়। - Word line (WL) assert করা হয় — M5, M6 চালু হয়ে যায়, ভেতরের
Q,Q̄নোড দুটো এখন BL, BL̄-এর সাথে সরাসরি যুক্ত। - ভেতরের inverter-গুলো নিজেদের অবস্থা ধরে রাখার মতো যথেষ্ট শক্তিশালী (sized) — তাই তারা BL, BL̄-কে সামান্য ঠেলে দেয় নিজেদের মানের দিকে। যেটা
0ধরে রেখেছে, সেটা তার bit line-কে সামান্য নিচে টানে। - একটা sense amplifier — একটা ভিন্ন circuit, তুলনামূলক বেশি transistor দিয়ে বানানো — সেই সামান্য পার্থক্য ধরে পুরোপুরি
0/1-এ বিবর্ধন (amplify) করে।
লক্ষ্য করুন — read করার সময় ভেতরের feedback loop-টা কখনো ভাঙে না। Cell নিজের মান জোর করে ধরে রাখে, শুধু সেটা বাইরে পড়া হচ্ছে। এই কারণেই SRAM read non-destructive।
Write — জোর করে বদলে দেওয়া
Write করতে হলে বাইরে থেকে BL, BL̄-কে শক্তিশালীভাবে নতুন মানের দিকে drive করা হয় (শুধু sense করা নয়, পুরোপুরি Vdd/GND-এ ঠেলে দেওয়া), তারপর WL assert করা হয়। এখন বাইরের driver ভেতরের feedback-এর চেয়ে শক্তিশালী — তাই ভেতরের অবস্থা নতুন মানে flip হয়ে যায়, আর feedback loop সেই নতুন মানটাই ধরে রাখতে শুরু করে।
একটা সম্পূর্ণ read cycle-এর সময়রেখা
লেসন ১১-এর timing ধারণা (setup time, propagation delay) এখানেও প্রযোজ্য — একটা read operation কয়েকটা ধাপ পরপর, প্রতিটার নিজস্ব সময় নিয়ে ঘটে:
time → t0 t1 t2 t3 t4
│ │ │ │ │
PRE ▔▔▔▔▔▔▔▔▔▔╲__________________________________
(precharge active)
│
WL ____________╱▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔╲________
(word line assert) (deassert)
│
BL,BL̄ ══════════╪──╲___(সামান্য পার্থক্য শুরু)
│ ╲___________
│ (cell থেকে ধীরে ধীরে পার্থক্য বাড়ে)
SAE ______________________╱▔▔▔▔▔▔╲________________
(sense amp enable)
│
Data ────────────────────────────╱▔▔▔▔(পূর্ণ 0/1)▔▔╲──
t3-এ ডেটা স্থিতিশীলধাপে ধাপে: t0-এ precharge শেষ, দুই bit line সমান। t1-এ WL assert — cell bit line-এ প্রভাব ফেলা শুরু করে। t2-এ যথেষ্ট পার্থক্য জমা হয়েছে। t3-এ sense amplifier enable হয়ে দ্রুত পার্থক্যকে পূর্ণ Vdd/GND-এ বিবর্ধিত করে — এখানেই ডেটা “স্থিতিশীল” হয়ে বাইরে পড়ার উপযোগী হয়। t4-এ WL deassert, cycle শেষ।
এই পুরো ক্রমটাই SRAM-এর access time নির্ধারণ করে — t0 থেকে t3 পর্যন্ত সময়টাই datasheet-এ “access time” হিসেবে উল্লেখ করা থাকে। DRAM-এর জন্য এই একই ধরনের সময়রেখা আরও দীর্ঘ, কারণ charge sharing-এর differential SRAM-এর সরাসরি push-এর চেয়ে ধীরে গড়ে ওঠে, আর তার উপর rewrite-এর বাড়তি ধাপ যোগ হয়।
SRAM cell-এর সম্পূর্ণ operation table
তিনটা signal (WL, BL-এ যা drive করা হচ্ছে, BL̄-এ যা drive করা হচ্ছে) মিলিয়ে cell-এর আচরণ সম্পূর্ণভাবে বর্ণনা করা যায়:
WL | BL drive | BL̄ drive | ফলাফল |
|---|---|---|---|
| 0 | — (floating) | — (floating) | Hold — cell নিজের feedback দিয়ে বর্তমান মান ধরে রাখে |
| 1 | precharge (দুর্বল) | precharge (দুর্বল) | Read — cell bit line ঠেলে দেয়, sense amp পড়ে |
| 1 | strong 1 (Vdd) | strong 0 (GND) | Write 1 — বাইরের driver feedback overpower করে |
| 1 | strong 0 (GND) | strong 1 (Vdd) | Write 0 — বিপরীত দিকে overpower |
লক্ষ্য করুন — WL = 0 অবস্থায় cell সম্পূর্ণভাবে বিচ্ছিন্ন (isolated), শুধু নিজের feedback-এর উপর নির্ভর করে বাঁচে। এটাই SRAM-এর “static” আচরণের প্রকৃত উৎস — বাইরের কোনো সংকেত ছাড়াই cell স্থিতিশীল থাকে।
Static নামটা এখান থেকেই — cell নিজে থেকে (statically) নিজের মান ধরে রাখে, refresh লাগে না। শুধু Vdd সরবরাহ চালু থাকতে হয়। Power off হলে feedback loop-এর energy চলে যায়, দুইটা transistor-ই একই অবস্থায় settle করতে পারে, মান হারিয়ে যায় — SRAM তাই এখনও volatile, শুধু active-refresh-free।
Precharge — read শুরুর আগেই বিটলাইন প্রস্তুত করা
উপরে read-এর ধাপ ১-এ “precharge” শব্দটা এসেছিল সংক্ষেপে — এটা নিজেই একটা ছোট সার্কিট যেটা প্রতিটা read/write cycle-এর শুরুতে চলে।
Vdd Vdd
│ │
─┴─ Mp1 ─┴─ Mp2
PRE ──────┤ ├────── PRE
└─┬─ └─┬─
│ │
BL ────────┬──────── BL̄
(equalizer Mp3,
দুই লাইন সমান করে)প্রতিটা access শুরুর আগে PRE সংকেত সংক্ষিপ্তভাবে assert হয় — Mp1, Mp2 দুইটা bit line-কেই Vdd-তে টেনে তোলে, আর একটা তৃতীয় “equalizer” transistor (Mp3) দুইটা লাইনকে ঠিক সমান ভোল্টেজে নিয়ে আসে। কেন এটা জরুরি: read-এর সময় cell যে সামান্য পার্থক্য তৈরি করবে সেটা যদি আগে থেকেই দুই লাইনের ভোল্টেজ অসমান থাকে, sense amplifier ভুল দিকে amplify করতে পারে। Precharge নিশ্চিত করে প্রতিটা read একটা পরিষ্কার, শূন্য-পার্থক্য অবস্থা থেকে শুরু হয়।
Sense amplifier — নিজেই একটা SRAM cell-এর মতো গঠন
এখানে একটা চমৎকার স্ব-নির্দেশক (self-referential) তথ্য: differential sense amplifier প্রায়ই ঠিক SRAM cell-এরই মতো cross-coupled inverter জোড়া দিয়ে বানানো হয় — শুধু আকারে অনেক বড় (দ্রুত ও শক্তিশালীভাবে amplify করার জন্য), আর স্থায়ীভাবে একটা মান ধরে রাখার বদলে প্রতি cycle-এ রিসেট হয়।
BL ──────┬────────────────┬────── BL̄
│ │
─┴─ ─┴─
│ │◄──cross──────►│ │ ← ঠিক SRAM cell-এর মতো
└┬┘ coupled └┬┘ cross-coupled pair,
│ inverter │ কিন্তু sense-amp হিসেবে
└────────┬───────┘ ব্যবহৃত
│
SAE (sense amp enable)BL, BL̄-এর মধ্যে cell যখন একটা ক্ষুদ্র পার্থক্য (কয়েক mV) তৈরি করে, SAE assert হলে এই cross-coupled pair-টা তার নিজস্ব positive feedback ব্যবহার করে সেই ক্ষুদ্র পার্থক্যকেই exponentially বড় করে দুই লাইনকে পুরোপুরি Vdd/GND-এ নিয়ে যায় — একই feedback trick, যেটা SRAM cell নিজের মান ধরে রাখতে ব্যবহার করে, এখানে ব্যবহৃত হচ্ছে একটা ক্ষুদ্র সংকেতকে বিবর্ধিত করতে।
DRAM-এর read cycle — একই ধারণা, একটা বাড়তি ধাপসহ
SRAM-এর সময়রেখার সাথে তুলনা করলে DRAM-এর পার্থক্যটা স্পষ্ট হয়ে যায়:
time → t0 t1 t2 t3 t4 t5
│ │ │ │ │ │
RAS/ ____________╱▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔╲______
ACTIVATE (row activate — word line assert)
│
Cell ════════════╪──╲___(charge sharing শুরু, মূল charge দুর্বল হচ্ছে)
capacitor │
BL,BL̄ │ ╲___(ক্ষুদ্র পার্থক্য bit line-এ)
│
SAE ________________________╱▔▔▔▔▔▔╲______________________
(amplify)
│
Rewrite ______________________________╱▔▔▔▔▔▔▔▔▔▔▔╲____________
(amplified মান cell-এ ফিরিয়ে লেখা)
│
Data ──────────────────────────────╱▔▔▔(পূর্ণ 0/1)▔▔╲────────
outSRAM আর DRAM timing-এর তুলনায় লক্ষ্য করুন — DRAM-এ “Rewrite” নামের একটা বাড়তি লেন যোগ হয়েছে, যেটা SRAM-এ কখনো ঘটে না (SRAM-এর read non-destructive)। এই বাড়তি ধাপটাই DRAM-এর access time-কে SRAM-এর তুলনায় সাধারণত ১০-৫০ গুণ ধীর করে দেয় — এটা কোনো “খারাপ ইঞ্জিনিয়ারিং” না, বরং charge-based storage-এর সহজাত খরচ।
Read disturb — কেন transistor-এর আকার এলোমেলো বাছা যায় না
SRAM read করার সময় access transistor (M5, M6) চালু হয়ে ভেতরের Q, Q̄ নোডকে bit line-এর সাথে যুক্ত করে দেয়। এখানে একটা সূক্ষ্ম বিপদ আছে: bit line precharge করা থাকে Vdd-তে, কিন্তু ভেতরের নোড হয়তো 0 (GND)। মুহূর্তের জন্য access transistor আর pull-down transistor (M1 বা M3) একটা voltage-divider তৈরি করে — যদি access transistor pull-down-এর তুলনায় খুব শক্তিশালী হয়, ভেতরের 0 নোড সাময়িকভাবে ওপরে উঠে যেতে পারে, আর চরম ক্ষেত্রে feedback loop ভুলভাবে flip করে ফেলতে পারে।
এটা এড়াতে চিপ ডিজাইনাররা সাবধানে beta ratio বজায় রাখেন — pull-down transistor (M1/M3)-কে access transistor (M5/M6)-এর তুলনায় ইচ্ছাকৃতভাবে শক্তিশালী (চওড়া) বানানো হয়, যাতে read করার সময় ভেতরের অবস্থা “disturb” না হয়। এটা এই লেসনের পরিসরের বাইরের একটা advanced VLSI ডিজাইন বিবেচনা, কিন্তু উল্লেখযোগ্য কারণ এটা দেখায় — “correct সার্কিট ডায়াগ্রাম” আঁকাই যথেষ্ট না; transistor-এর প্রকৃত physical sizing-ও সঠিকতার অংশ।
Word-oriented organization — বাস্তবে এক বিট না, এক word একসাথে
এখন পর্যন্ত আমরা প্রতিটা cell-কে ১ বিট হিসেবে দেখেছি। কিন্তু বাস্তব memory chip বা array সাধারণত একবারে ১ বিট না, একটা সম্পূর্ণ word (যেমন 8, 16, 32, বা 64 বিট) address করে। এটা করা হয় row-টাকে একবারে “N বার পাশাপাশি” রেখে — প্রতিটা bit-position-এর জন্য একটা করে সম্পূর্ণ column-array, সবগুলো একই row address আর একই word line ভাগ করে নেয়।
address (row+col)
│
┌────────────┼────────────┐
│ │ │
┌────▼────┐ ┌────▼────┐ ┌────▼────┐
│ bit-plane│ │ bit-plane│ │ bit-plane│ ... (মোট N-টা plane,
│ #0 │ │ #1 │ │ #2 │ N = word width)
│(row×col │ │(row×col │ │(row×col │
│ grid, ১টা│ │ grid, ১টা│ │ grid, ১টা│
│ বিট আউট)│ │ বিট আউট)│ │ বিট আউট)│
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
D[0] D[1] D[2] ... D[N-1]
└────────────┴────────────┴──── ... ────┘
N-বিট data busএকই row address আর একই word line সবগুলো bit-plane-এ একসাথে পাঠানো হয় — তাই একটা word-এর সবগুলো bit সমান্তরালভাবে (parallel) বেরিয়ে আসে, একটার পর একটা সিরিয়ালি না। এই ধারণাটাই পরের লেসনে সরাসরি কাজে লাগবে — register file-এর প্রতিটা register একটা সম্পূর্ণ N-বিট word, আর memory থেকে একবারে পুরো word read/write করা এই word-oriented organization-এরই ফল।
Multi-port SRAM — লেসন ১৫-এর register file-এর পূর্বপ্রস্তুতি
এতক্ষণ আমরা ধরে নিয়েছিলাম প্রতিটা cell-এ একটা মাত্র bit line জোড়া (BL, BL̄) থাকে — মানে একটা সময়ে মাত্র একটা read বা write সম্ভব। কিন্তু CPU-এর ভেতরে register file-এর মতো জায়গায় প্রায়ই একই cycle-এ একাধিক register পড়তে হয় (যেমন ADD Rd, Rs, Rt — একই সাথে Rs আর Rt দুটোই পড়তে হয়)।
এর সমাধান — multi-port SRAM cell: প্রতিটা cell-এ একাধিক জোড়া access transistor আর একাধিক জোড়া bit line যোগ করা হয়, প্রতিটা জোড়ার নিজস্ব word line সহ। একটা “2-read-1-write” (2R1W) cell-এ তিন জোড়া access transistor থাকে — দুই জোড়া independent read-এর জন্য, এক জোড়া write-এর জন্য। মূল cross-coupled inverter (M1-M4) অপরিবর্তিত থাকে — শুধু access করার পথ বাড়ানো হয়।
DRAM — charge দিয়ে ধরে রাখা
SRAM-এর ৬টা transistor অনেক জায়গা খায়। প্রশ্ন: feedback loop ছাড়াই যদি bit-টা সংরক্ষণ করা যেত?
DRAM-এর উত্তর প্রায় নিষ্ঠুরভাবে সরল: একটা capacitor-এ charge জমিয়ে রাখো। Charge থাকলে 1, না থাকলে 0। Capacitor access করতে একটা transistor লাগে — গেট control করে কখন capacitor-টা bit line-এর সাথে যুক্ত হবে।
Word Line (WL)
│
│
BL ───────┤├─────┬──── (access transistor, NMOS)
(bit line) │
═══ ← Capacitor (storage node)
│
GNDWrite
WL assert করে transistor চালু করা হয়, তারপর BL-কে Vdd (লেখার জন্য 1) বা GND (0) -এ drive করা হয়। Capacitor সেই ভোল্টেজে charge/discharge হয়ে যায়। WL de-assert হলে transistor বন্ধ, capacitor-এর charge (আপাতত) আটকে থাকে — কোনো সরাসরি leakage path নেই এই মুহূর্তে transistor বন্ধ থাকায়।
Read — এবং কেন এটা “ধ্বংসাত্মক”
Capacitor-টা অবিশ্বাস্য রকম ছোট — সাধারণত কয়েক femtofarad (~30 fF)। বিপরীতে, bit line নিজে একটা লম্বা তার, তার নিজের parasitic capacitance আছে যেটা cell-এর capacitance-এর তুলনায় অনেক বড় (~30× বা তার বেশি)।
Read করতে: WL assert করলে cell-এর capacitor bit line-এর সাথে যুক্ত হয়ে যায়, আর তাদের মধ্যে charge ভাগাভাগি (charge sharing) হয়। ফলাফল — bit line-এর ভোল্টেজে একটা ক্ষুদ্র পরিবর্তন, যেটা একটা sense amplifier ধরে amplify করে পূর্ণ 0/1-এ পরিণত করে।
কিন্তু এই charge-sharing প্রক্রিয়ায় cell-এর নিজের charge redistribute হয়ে দুর্বল হয়ে যায় — read নিজেই মূল মানটা মুছে ফেলে বা দুর্বল করে দেয়। তাই প্রতিটা DRAM read-এর পরপরই sense amplifier সেই amplified মানটা আবার cell-এ ফিরিয়ে লেখে (rewrite-after-read)। এটা কোনো ঐচ্ছিক পদক্ষেপ না — DRAM-এর read সার্কিট ডিজাইনেই এই rewrite অন্তর্ভুক্ত।
কেন Refresh লাগে — mechanically
এখন আসল প্রশ্ন। Capacitor-এ charge জমিয়ে রাখলাম, কিন্তু বাস্তব জগতে কোনো capacitor নিখুঁতভাবে charge আটকে রাখতে পারে না। কয়েকটা leakage path আছে:
- Access transistor-এর subthreshold leakage — transistor “বন্ধ” থাকলেও একদম শূন্য current যায় না, একটা ক্ষুদ্র রিসাইনি (leakage current) সবসময় থাকে।
- Junction leakage — capacitor-এর storage node আর সিলিকন substrate-এর মধ্যে p-n junction দিয়ে সামান্য current বেরিয়ে যায়।
- Capacitor dielectric নিজেই সম্পূর্ণ নিখুঁত insulator না — সামান্য leakage current দিয়ে charge ধীরে ধীরে বেরিয়ে যায়।
এই তিনটার মিলিত ফল — capacitor-এর ভোল্টেজ সময়ের সাথে exponentially decay করে, ধ্রুপদী RC discharge-এর মতো:
যেখানে R হলো এই সব leakage path-এর সম্মিলিত effective resistance (খুবই বড়, ~10^12–10^15 ohm range-এ), আর C cell capacitance (~30 fF)। কিছু সময় পর V(t) sense amplifier-এর ন্যূনতম detectable threshold-এর নিচে নেমে যায় — তখন cell-টা কী সংরক্ষণ করেছিল সেটা আর নির্ভরযোগ্যভাবে পড়া যায় না। ডেটা হারিয়ে যায়।
সমাধান — Refresh: ডেটা হারানোর আগেই প্রতিটা row read করে আবার rewrite করা হয় (যেটা আমরা উপরে দেখলাম DRAM read এমনিতেই করে!)। এটা সম্পূর্ণ নতুন কোনো প্রক্রিয়া না — refresh মানে ইচ্ছাকৃতভাবে row-বাই-row read করা, যাতে sense amp-এর built-in rewrite প্রতিটা cell-এর charge পুনরায় পূর্ণ শক্তিতে ফিরিয়ে দেয়, decay শুরুর আগেই।
JEDEC (memory ইন্ডাস্ট্রির standard সংস্থা) DDR SDRAM-এর জন্য নির্ধারণ করেছে প্রতিটা row ৬৪ মিলিসেকেন্ডের মধ্যে অন্তত একবার refresh হতে হবে (উচ্চ তাপমাত্রায় leakage বেড়ে যায় বলে কিছু ডিভাইসে এই সীমা 32ms-এ নেমে আসে)। এটা কোনো নির্বিচার সংখ্যা না — এটা একটা নিরাপত্তা margin: worst-case (সবচেয়ে বেশি leaky) cell-ও 64ms-এর মধ্যে decay করে sense threshold-এর নিচে পৌঁছায় না, এমনভাবে ডিজাইন আর নির্বাচন (process/testing-এ বাদ পড়া) করা হয়।
দুইটা cell, পাশাপাশি — এক নজরে
┌──────────────── SRAM (6T) ────────────────┐ ┌────── DRAM (1T1C) ──────┐
│ │ │ │
│ Vdd Vdd │ │ WL │
│ │ │ │ │ │ │
│ ─┴─ ─┴─ │ │ BL ──┤├──┬── │
│ │M2│ │M4│ ← ৪টা transistor │ │ │ │ │
│ Q ─┤ ├── ✕ ────┤ ├─ Q̄ ← দুইটা inverter │ │ ═══ ← capacitor │
│ │M1│ │M3│ cross-coupled │ │ │ │
│ ─┬─ ─┬─ │ │ GND │
│ │ │ │ │ │
│ GND GND │ │ ২টা উপাদান │
│ │ │ (active feedback নেই) │
│ +M5,M6 access transistor = মোট ৬টা │ │ │
└────────────────────────────────────────────┘ └──────────────────────────┘
সংরক্ষণ: সক্রিয় feedback loop সংরক্ষণ: passive capacitor charge
Refresh: লাগে না Refresh: প্রতি ~64ms
Read: non-destructive Read: destructive (rewrite দরকার)
ব্যবহার: cache, register file ব্যবহার: main memory, GPU memoryTrade-off table — কেন দুটোই দরকার
| বৈশিষ্ট্য | SRAM | DRAM |
|---|---|---|
| Cell গঠন | 6 transistor (cross-coupled inverter + 2 access) | 1 transistor + 1 capacitor |
| প্রতি bit area | বড় (৬–৮× DRAM cell-এর তুলনায়) | ক্ষুদ্রতম সম্ভব |
| Cost per bit | বেশি | কম |
| গতি | দ্রুত (~1 ns বা তার কম access) | ধীর (~10–50 ns access) |
| Refresh প্রয়োজন | না | হ্যাঁ, প্রতি ~64ms-এ |
| Read destructive? | না | হ্যাঁ (কিন্তু স্বয়ংক্রিয়ভাবে rewrite হয়) |
| Power (idle) | কম (feedback ধরে রাখতে সামান্য current) | বেশি (ক্রমাগত refresh-এর খরচ) |
| সাধারণ ব্যবহার | CPU register file, L1/L2/L3 cache | Main memory (DIMM), GPU memory |
এই table-টাই Level 3 আর Level 11-এর memory hierarchy-র বীজ — কেন CPU একটা একক, সমান-গতির memory ব্যবহার না করে ছোট-দ্রুত-দামি (SRAM cache) থেকে বড়-ধীর-সস্তা (DRAM main memory) পর্যন্ত একটা সিঁড়ি বানায়, সেটার শারীরিক কারণ এখানেই — cell-লেভেলের এই trade-off। “Cache কেন আছে” প্রশ্নের উত্তরের একটা অংশ আজই দিয়ে দিলাম: কারণ SRAM দ্রুত কিন্তু ব্যয়বহুল বলে অল্প রাখা যায়, DRAM সস্তা কিন্তু ধীর বলে বেশি রাখা যায় — দুটোর মাঝামাঝি ভারসাম্যই memory hierarchy।
বাস্তব সংখ্যায় speed gap
তত্ত্বীয় trade-off-কে সংখ্যায় দেখলে পার্থক্যটা আরও স্পষ্ট হয় — এইগুলো আনুমানিক (typical, vendor/generation-নির্ভর) মান:
| Memory tier | প্রযুক্তি | আনুমানিক access time | আনুমানিক আকার |
|---|---|---|---|
| Register file | SRAM (multi-port) | সাব-ns (CPU clock-এর সাথে) | কয়েক শত বাইট |
| L1 cache | SRAM | ~1 ns | 32-64 KB |
| L2 cache | SRAM | ~3-10 ns | 256KB-1MB |
| L3 cache | SRAM | ~10-40 ns | কয়েক থেকে কয়েক দশ MB |
| Main memory | DRAM | ~50-100 ns | 8-64 GB |
প্রতিটা ধাপে access time বাড়ছে প্রায় এক ক্রম মাত্রা (order of magnitude) করে, আর সাথে সাথে আকারও বাড়ছে — ঠিক এই লেসনের speed-vs-density trade-off-এর পূর্বাভাস অনুযায়ী। এই table-টাই Level 3-এ “memory wall” আর cache miss penalty আলোচনার সরাসরি ভিত্তি হবে।
শব্দকোষ — এই লেসনের পরিভাষা এক নজরে
| পরিভাষা | সংক্ষেপে অর্থ |
|---|---|
| Cell | একটা একক bit ধরে রাখার সার্কিট (SRAM: 6T, DRAM: 1T1C) |
| Word line (WL) | একটা সম্পূর্ণ row-এর access transistor একসাথে চালু করা signal |
| Bit line (BL/BL̄) | Cell আর sense amplifier-এর মধ্যে ডেটা বহনকারী তার |
| Sense amplifier | ক্ষুদ্র ভোল্টেজ পার্থক্যকে পূর্ণ 0/1-এ বিবর্ধিত করা সার্কিট |
| Precharge | Access-এর আগে bit line-কে একটা পরিচিত অবস্থায় প্রস্তুত করা |
| Refresh | DRAM-এ decay-এর আগেই প্রতিটা cell read-rewrite করা |
| Row decoder | Row address থেকে একটা WL assert করা decoder (লেসন ৭) |
| Column mux | অনেক bit line থেকে একটা বেছে নেওয়া mux (লেসন ৭) |
| Bank | একটা DRAM chip-এর ভেতরে স্বাধীনভাবে কাজ করতে পারা উপ-অংশ |
ভেতরে কী ঘটছে
Address কীভাবে একটা নির্দিষ্ট bit খুঁজে বের করে
এখন পর্যন্ত আমরা একটা মাত্র cell দেখেছি। বাস্তব memory-তে লক্ষ লক্ষ, কোটি কোটি cell একটা grid-এ সাজানো থাকে — আর একটা address দিয়ে ঠিক একটা cell (বা একটা group) খুঁজে বের করতে হয়। এখানেই লেসন ৭-এর decoder আর multiplexer কাজে ফিরে আসে।
Grid হিসেবে memory
একটা memory array-কে কল্পনা করুন একটা দ্বিমাত্রিক grid হিসেবে — সারি (row) আর কলাম (column)। প্রতিটা row-এর সব cell একটা একই word line-এ যুক্ত (যেটা assert হলে পুরো row-এর সব access transistor একসাথে চালু হয়)। প্রতিটা column-এর সব cell একই bit line-এ যুক্ত।
column 0 column 1 column 2 ... column 1023
│ │ │ │
WL(row 0) ────●───┼──────●───┼──────●───┼────── ... ───●───
cell cell cell cell
WL(row 1) ────●───┼──────●───┼──────●───┼────── ... ───●───
cell cell cell cell
⋮
WL(row 1023) ─●───┼──────●───┼──────●───┼────── ... ───●───
│ │ │ │
BL0 BL1 BL2 ... BL1023
│ │ │ │
└──────────┴──────────┴────── ... ─────┘
│
[ Column mux / decoder ] ← 10-bit column address
│
Data out (1 bit)
Row address (10 bit) ──▶ [ Row decoder ] ──▶ ঠিক একটা WL assertRow decoder — একটা পুরো row একসাথে “খোলা”
Row address-এর n বিট একটা n-to-2^n decoder-এ (লেসন ৭) যায়। ঠিক একটা output লাইন 1 হয় — সেটাই সেই row-এর word line। WL assert হওয়া মাত্র সেই পুরো row-এর সব cell একসাথে তাদের bit line-এর সাথে যুক্ত হয়ে যায় — একসাথে হাজার হাজার cell “খুলে” যায়, প্রতিটা নিজের bit line-এ নিজের মান পাঠায়।
Column mux — হাজার হাজার থেকে একটা বেছে নেওয়া
কিন্তু এতগুলো bit line-এর মধ্যে আমরা তো একটা মাত্র bit (বা একটা word) চাই। এখানে column address একটা multiplexer-এ (লেসন ৭) যায় — সব bit line input হিসেবে নিয়ে, column address অনুযায়ী ঠিক একটা bit line-এর মান output-এ পাঠায়।
সংক্ষেপে: address → row decoder → একটা WL assert → পুরো row bit line-এ আসে → column mux → নির্দিষ্ট একটা bit বাছাই → data out।
একটা বাস্তব উদাহরণ — কেন row+column, শুধু একটা flat decoder নয়
কল্পনা করুন একটা 1 Megabit memory (1,048,576 bit, 1 bit করে addressable — বাস্তবে ১৯৮০-এর দশকের একটা DRAM chip ঠিক এভাবেই সংগঠিত হতো, “1M×1” নামে পরিচিত)।
একটা flat decoder দিয়ে সরাসরি এক ধাপে address করতে গেলে লাগত একটা 20-to-1,048,576 decoder — কার্যত অসম্ভব রকম জটিল ও ধীর wiring।
তার বদলে array-টাকে প্রায় বর্গাকার করে সাজানো হয় — 1024 row × 1024 column (1024 × 1024 = 1,048,576)। 20-বিট address ভাগ হয়:
- উপরের ১০ বিট → row address →
10-to-1024row decoder → একটা WL assert - নিচের ১০ বিট → column address →
1024-to-1column mux → একটা bit output
SRAM-এও একই ধারণা কাজ করে — শুধু cell আলাদা, addressing scheme একই: row decoder + column mux। CPU cache-এর মতো ছোট SRAM array-তে row/column অনুপাত ভিন্ন হতে পারে (কারণ area/speed trade-off ভিন্ন), কিন্তু মূলনীতি অভিন্ন।
Cell size-কে মাপার একটা প্রমিত একক — F²
Chip fabrication-এ cell density তুলনা করার জন্য একটা প্রমিত (normalized) একক ব্যবহার হয় — F মানে সেই generation-এর ন্যূনতম lithographic feature size (যত ছোট process node, তত ছোট F)। যেকোনো cell-এর area প্রকাশ করা হয় F²-এর গুণিতক হিসেবে, যাতে ভিন্ন ভিন্ন প্রজন্মের চিপ তুলনীয় হয়:
| Cell টাইপ | সাধারণ area | ব্যাখ্যা |
|---|---|---|
| DRAM (1T1C) | ~6F²–8F² | Access transistor + capacitor, অত্যন্ত compact layout |
| SRAM (6T) | ~100F²–150F² | ৬টা transistor + isolation spacing, অনেক বড় |
এই সংখ্যাগুলোই এই লেসনের trade-off table-এর “area/cost” সারির পেছনের প্রকৃত ভিত্তি — SRAM cell DRAM cell-এর তুলনায় প্রায় ১৫-২০ গুণ বেশি জায়গা নেয়, স্বাধীনভাবে কোন process node ব্যবহার হচ্ছে তার থেকে। F যত ছোট হয় (নতুন process node), দুটোই সমানুপাতে ছোট হয়, কিন্তু তাদের মধ্যেকার অনুপাত প্রায় স্থির থাকে — কারণ এটা transistor সংখ্যার একটা কাঠামোগত (structural) পার্থক্য, শুধু manufacturing precision-এর না।
DRAM-এর প্রজন্ম — async থেকে DDR5 পর্যন্ত
RAS/CAS-ভিত্তিক asynchronous DRAM ছিল শুরুর বিন্দু। তারপর থেকে প্রতিটা প্রজন্ম মূলত একই cell (1T1C) রেখে interface-টা দ্রুততর করেছে:
| প্রজন্ম | আনুমানিক সময় | মূল পরিবর্তন |
|---|---|---|
| Asynchronous DRAM | ১৯৭০-এর দশক | RAS/CAS strobe দিয়ে সরাসরি control, কোনো clock নেই |
| Fast Page Mode (FPM) | ১৯৮০-এর দশক | একই row-তে একাধিক CAS — নতুন RAS ছাড়াই |
| EDO DRAM | ১৯৯০-এর দশক শুরু | পরের access-এর সাথে আগেরটার overlap |
| SDRAM | ১৯৯০-এর দশক মাঝামাঝি | পুরো interface clock-synchronized (লেসন ১১-এর clock ধারণা এখানে প্রয়োগ) |
| DDR SDRAM | ২০০০ | Clock-এর ওঠা ও নামা — দুই edge-এই ডেটা transfer |
| DDR2 / DDR3 / DDR4 | ২০০৩ / ২০০৭ / ২০১৪ | Prefetch buffer বাড়িয়ে (৪n থেকে ৮n বিট) কার্যকর transfer rate বৃদ্ধি |
| DDR5 | ২০২০-এর দশক | দুইটা স্বাধীন 32-বিট চ্যানেল প্রতি DIMM-এ, আরও উঁচু rate |
“Double Data Rate” মানে ঠিক কী — এটা সরাসরি লেসন ১১-এর clock edge ধারণার প্রয়োগ। সাধারণ synchronous logic শুধু clock-এর rising edge-এ ডেটা latch করে (প্রতি cycle-এ একবার)। DDR memory rising এবং falling — দুই edge-এই ডেটা transfer করে, তাই একই clock frequency-তে দ্বিগুণ কার্যকর data rate পাওয়া যায়। এই কারণেই 3200 MT/s (mega-transfers/sec) DDR4-এর প্রকৃত clock frequency মাত্র 1600 MHz।
Bank — কেন একটা বড় array না, অনেকগুলো ছোট bank
বাস্তব DRAM chip-এ পুরো ক্ষমতাটা একটামাত্র বিশাল grid না — বরং কয়েকটা স্বাধীন bank-এ ভাগ করা থাকে (সাধারণত 4, 8, বা 16-টা)। প্রতিটা bank নিজের row decoder, column mux, আর sense amplifier-এর নিজস্ব সেট রাখে।
কেন: একটা row activate করা, আর তারপর precharge করে বন্ধ করা — এই প্রক্রিয়ায় কিছু সময় লাগে, যেই সময় সেই bank নতুন কোনো request নিতে পারে না। একাধিক bank থাকলে memory controller একটা bank-কে refresh/precharge অবস্থায় রেখেই আরেকটা bank-এ সমান্তরালে একটা নতুন request পাঠাতে পারে — কাজের overlap, ঠিক যেমন lesson ১২-এর FSM-এ আমরা দেখেছি একাধিক state সমান্তরালভাবে ভিন্ন কাজ সামলাতে পারে। এই bank-ভিত্তিক সমান্তরালতার বিস্তারিত কৌশল (bank interleaving, row buffer hit/miss) Level 3/11-এর মেমরি কন্ট্রোলার আলোচনায় ফিরে আসবে — এখানে শুধু এইটুকু জানা যথেষ্ট: memory ভেতরে একটামাত্র grid না, বরং একাধিক স্বাধীন grid-এর সমষ্টি।
একটা DRAM bank নিজেই একটা FSM
লেসন ১২-তে আমরা FSM শিখেছি — কয়েকটা state, আর সংকেত অনুযায়ী state-এর মধ্যে transition। একটা DRAM bank-কে ঠিক এভাবেই মডেল করা যায়:
ACTIVATE command
┌────────────────────────┐
│ ▼
┌─────────┐ ┌──────────┐
│ Idle │ │ Active │
│(কোনো row │ │(একটা row │
│ খোলা নেই)│ │ খোলা আছে,│
└─────────┘ │ read/write│
▲ │ সম্ভব) │
│ └────┬─────┘
│ PRECHARGE command │
└──────────────────────────┘
│
▼
┌─────────────┐
│ Precharging │──── কিছু সময় পর ──▶ Idle-এ ফিরে
└─────────────┘| State | অর্থ | এই অবস্থায় কী করা যায় |
|---|---|---|
| Idle | কোনো row খোলা নেই, bit line precharge করা আছে | নতুন ACTIVATE command গ্রহণযোগ্য |
| Active | ACTIVATE-এর ফলে একটা row-এর word line assert, sense amp সক্রিয় | সেই row-এর যেকোনো column-এ READ/WRITE (একাধিকবার — এটাই “page mode”) |
| Precharging | PRECHARGE command bit line-কে আবার সমান করছে | নতুন request গ্রহণযোগ্য নয়, Idle-এ ফেরার অপেক্ষা |
এই তিনটা state-ই লেসন ১২-এর ভাষায় একটা Moore FSM — memory controller যেই command পাঠায় সেটাই input, current state অনুযায়ী bank কী করতে পারে সেটাই output। আধুনিক memory controller-এর ভেতরে ঠিক এরকম একটা FSM (প্রতিটা bank-এর জন্য আলাদা করে) প্রকৃতপক্ষে চলমান থাকে, প্রতিটা bank কখন ACTIVATE, READ/WRITE, বা PRECHARGE command নিতে পারবে তার হিসাব রাখতে।
Self-refresh — কেন ল্যাপটপ “sleep”-এ থেকেও RAM মনে রাখে
Refresh-এর একটা প্রতিদিন-অভিজ্ঞতার সংযোগ আছে — আপনার ল্যাপটপের sleep mode (Windows-এ “Sleep”, macOS-এ ঢাকনা বন্ধ করা, Linux-এ S3 suspend)।
সাধারণ অবস্থায় memory controller (CPU-র অংশ) বাইরে থেকে refresh command পাঠায়, প্রতি ~7.8μs-এ একবার। কিন্তু sleep mode-এ CPU নিজেই বন্ধ হয়ে যায় — তাহলে refresh command কে পাঠাবে?
DRAM চিপ নিজেই একটা self-refresh mode সমর্থন করে — একটা internal oscillator (একটা ছোট, কম-নির্ভুল অভ্যন্তরীণ clock circuit) চালু হয়ে যায়, যেটা বাইরের memory controller ছাড়াই নিজে থেকে refresh চালিয়ে যেতে পারে। এই মোডে DRAM এত কম power খরচ করে (শুধু refresh চালানোর যতটুকু দরকার) যে পুরো সিস্টেম কার্যত বন্ধ থাকলেও ব্যাটারি ধীরে ধীরে ফুরাতে থাকে — এই কারণেই ল্যাপটপ sleep mode-এ কয়েক ঘণ্টা বা কয়েকদিন পর ব্যাটারি শেষ হয়ে যেতে পারে, কিন্তু জাগলে সাথে সাথেই আগের অবস্থায় ফিরে আসে (RAM-এর কিছুই হারায়নি, শুধু refresh চলছিল)।
Sleep (S3):
RAM ─── power সরবরাহ চালু থাকে ─── self-refresh mode সক্রিয়
→ RAM-এর সব ডেটা অক্ষত থাকে, জাগলে তাৎক্ষণিক
→ ব্যাটারি ধীরে ধীরে খরচ হয় (refresh চালিয়ে রাখার জন্য)
Hibernate (S4):
RAM ─── পুরো content disk-এ লেখা হয় ─── power সম্পূর্ণ বন্ধ
→ RAM সম্পূর্ণ power হারায়, সব ডেটা স্বাভাবিকভাবেই হারিয়ে যায়
→ জাগতে ধীর (disk থেকে ফিরিয়ে আনতে হয়), কিন্তু ব্যাটারি খরচ শূন্যHibernate-এ উল্টো ঘটনা — RAM-এর পুরো বিষয়বস্তু disk-এ (non-volatile storage-এ) কপি করে RAM-কে সম্পূর্ণ power বন্ধ করে দেওয়া হয়। যেহেতু power সম্পূর্ণ বন্ধ, self-refresh চলারও দরকার নেই — আর ঠিক সেই কারণেই RAM-এর সব ডেটা স্বাভাবিকভাবেই হারিয়ে যায়, আবার জাগার সময় disk থেকে ফিরিয়ে আনতে হয় (তাই ধীর, কিন্তু ব্যাটারি একদম খরচ হয় না)।
লক্ষ্য করুন — এই দুইটা familiar ল্যাপটপ ফিচারের পার্থক্য একদম সরাসরি এই লেসনের মূল বিষয় থেকে আসে: DRAM volatile, আর তাকে সজীব রাখতে বিদ্যুৎ ও refresh দুটোই লাগে।
PSRAM — দুই জগতের সীমারেখা ইচ্ছাকৃতভাবে ঝাপসা করা
একটা শেষ, চমৎকার হাইব্রিড উদাহরণ: PSRAM (Pseudo-Static RAM)। ভেতরে এটা আসলে খাঁটি DRAM cell (1T1C) — কিন্তু চিপের ভেতরেই একটা built-in refresh controller বসানো থাকে, যেটা নিজে থেকেই ক্রমাগত refresh চালিয়ে যায়, বাইরের memory controller-কে কোনো refresh command পাঠাতে হয় না।
ফলাফল: বাইরে থেকে তাকালে PSRAM ঠিক SRAM-এর মতো আচরণ করে (শুধু address দিন, data পান — refresh নিয়ে ভাবতে হয় না), কিন্তু ভেতরে DRAM-এর ঘনত্ব ও কম দাম বজায় থাকে। ছোট embedded system-এ (যেমন ESP32-এর মতো microcontroller-এ external PSRAM module) এটা খুব জনপ্রিয় — ডিজাইনার সাধারণ DRAM-এর জটিল controller লজিক নিজে বানাতে চান না, কিন্তু DRAM-এর সস্তা ক্ষমতাও চান।
- address আসেযেমন CPU থেকে, ২০ বিট
- row address বিভক্তউপরের ১০ বিট → row decoder
- word line assertএকটা row-এর ১০২৪ cell একসাথে সক্রিয়
- bit line-এ ভোল্টেজSRAM: সরাসরি push; DRAM: charge sharing
- sense amplifierক্ষুদ্র পার্থক্য amplify করে পূর্ণ 0/1
- column muxনিচের ১০ বিট column address দিয়ে ১টা bit বাছাই
- data outএকটা bit — অথবা DRAM হলে সেই সাথে rewrite
উদাহরণ
সংখ্যায় দেখা — একটা 4 Mbit array
ধরুন একটা 4 Megabit (4,194,304 bit) memory array আছে, 2048 × 2048 grid হিসেবে সাজানো (2048 × 2048 = 4,194,304)।
2048 = 2^11→ row address লাগবে ১১ বিট2048 = 2^11→ column address লাগবে ১১ বিট- মোট address:
11 + 11 = 22বিট →2^22 = 4,194,304— ঠিক মিলে যায়।
Row decoder: 11-to-2048 — 11 বিট ইনপুট নিয়ে 2048-টা output লাইনের ঠিক একটাকে 1 করে।
Column mux: 2048-to-1 — 2048-টা bit line থেকে 11-বিট select signal দিয়ে ঠিক একটা বাছাই করে।
Address-এর bit layout:
21 20 19 18 ... 11 10 9 8 ... 1 0
┌───────────────────────┬───────────────────────┐
│ row address (১১ বিট) │ column address (১১ বিট)│
└───────────────────────┴───────────────────────┘
▲ ▲
row decoder-এ যায় column mux-এ যায়
(11-to-2048) (2048-to-1)একটা read operation-এর সময়রেখা (SRAM):
| ধাপ | কী ঘটে |
|---|---|
| ১ | 22-বিট address আসে, ভাগ হয় 11+11-এ |
| ২ | Row decoder সেই একটা WL assert করে — 2048-টা cell একসাথে সক্রিয় |
| ৩ | 2048-টা bit line-এ ভোল্টেজ পরিবর্তন শুরু হয় (SRAM cell সরাসরি push করে) |
| ৪ | 2048-টা sense amplifier (প্রতি column-এ একটা) একযোগে amplify করে |
| ৫ | Column mux 11-বিট column address দিয়ে সেই 2048-এর মধ্যে ১টা বাছাই করে |
| ৬ | Data out পিনে সেই ১ বিট বেরিয়ে আসে |
লক্ষ্য করুন — যদিও শেষে মাত্র ১ বিট চাই, ভেতরে পুরো row-এর 2048-টা cell-ই “জেগে ওঠে” আর sense amplify হয়। এই কারণেই বাস্তব memory chip-এ একবারে একটা bit না নিয়ে পুরো word (৮, ১৬, ৩২, বা ৬৪ বিট) একসাথে read করা হয় — যেহেতু row-টা এমনিতেই পুরোপুরি activate হয়ে গেছে, বাড়তি bit-গুলোও প্রায় বিনামূল্যে পাওয়া যায়। এটাই cache line-এর ধারণার প্রথম বীজ, যেটা Level 3/11-এ পুরোপুরি খুলবে।
DRAM হলে একই সময়রেখায় বাড়তি একটা ধাপ যোগ হয় — ধাপ ৪-এর ঠিক পরে, sense amplifier-এর amplified মান সেই একই row-এর সব cell-এ ফিরিয়ে লেখা হয় (rewrite-after-read), কারণ charge sharing মূল মানকে দুর্বল করে দিয়েছিল।
দ্বিতীয় উদাহরণ — একটা বাস্তব SRAM চিপ: 6116 (2K×8)
তত্ত্বকে আরেকটু concrete করার জন্য একটা প্রকৃত, ইতিহাসখ্যাত চিপ দেখি: 6116 — 2048 word × 8 বিট static RAM, ১৯৮০-এর দশকে ৮-বিট কম্পিউটারে (Commodore 64-সহ অনেক মেশিনে) ব্যাপকভাবে ব্যবহৃত হয়েছিল। এটাই লেসন ১৫-তে যেই “small memory” আমরা datapath-এ wire করব, তার একটা বাস্তব পূর্বসূরি।
- মোট ক্ষমতা:
2048 × 8 = 16,384বিট (16কিলোবিট) - Word width:
8বিট (একবারে একটা পূর্ণ byte address হয়, উপরের “word-oriented organization” অংশের ঠিক প্রয়োগ) - Address pin:
11-টা (2^11 = 2048word addressable) - Data pin:
8-টা (bidirectional — read-এ output, write-এ input) - Control pin:
CS̄(chip select),OĒ(output enable),WĒ(write enable) — প্রতিটাই active-low (নিচু হলে সক্রিয়)
ভেতরের সংগঠন: 2048-টা row থাকলে (প্রতি row-এ একটা 8-বিট word), হয়তো 128 × 16 grid হিসেবে সাজানো (128 × 16 = 2048 word, প্রতি word-এ 8 bit-plane)। প্রকৃত internal floorplan vendor-নির্ভর — কিন্তু নীতিটা অভিন্ন: address ভাগ হয়ে row decoder ও column mux-এ যায়, ঠিক আগের উদাহরণের মতোই।
Read cycle, pin দিয়ে:
| Pin | Read-এ মান | অর্থ |
|---|---|---|
A0–A10 | ঠিকানা | কোন word চাই |
CS̄ | 0 | চিপ সক্রিয় |
OĒ | 0 | Output driver চালু |
WĒ | 1 | Write না, read |
D0–D7 | (output) | সেই word-এর ৮ বিট |
পিন ডায়াগ্রাম (সরলীকৃত DIP প্যাকেজ):
┌─────∪─────┐
A7 ──┤ 1 24├── Vcc
A6 ──┤ 2 23├── A8
A5 ──┤ 3 22├── A9
A4 ──┤ 4 21├── WĒ
A3 ──┤ 5 20├── OĒ
A2 ──┤ 6 6116 19├── A10
A1 ──┤ 7 18├── CS̄
A0 ──┤ 8 17├── D7
D0 ──┤ 9 16├── D6
D1 ──┤10 15├── D5
D2 ──┤11 14├── D4
GND ──┤12 13├── D3
└───────────┘11-টা address pin (A0–A10), 8-টা data pin (D0–D7), তিনটা control pin (CS̄, OĒ, WĒ) — ঠিক এই লেসনের addressing মডেলের একটা বাস্তব, স্পর্শযোগ্য রূপ। মোট 24-পিন প্যাকেজ, 1980-এর দশকের একটা সাধারণ IC-র আকার।
কোনো clock pin নেই — এটা asynchronous SRAM: address স্থির রাখলেই একটা নির্দিষ্ট বিলম্বের (access time, সাধারণত ~100-200ns এই generation-এ) পর data pin-এ সঠিক মান স্থিতিশীল হয়ে যায়। আধুনিক SRAM cache (CPU-এর ভেতরে) সাধারণত clock-synchronized (synchronous SRAM, SSRAM), কিন্তু cell-লেভেল principle অভিন্ন।
কয়েকটা ঐতিহাসিক মেমরি চিপের তুলনা — সংখ্যাগুলো দেখায় density কীভাবে বছরের পর বছর বেড়েছে, একই মূলনীতি (SRAM 6T অথবা DRAM 1T1C) বজায় রেখে:
| চিপ | প্রযুক্তি | ধারণক্ষমতা | সংগঠন | আনুমানিক সাল |
|---|---|---|---|---|
| Intel 1103 | DRAM | 1 Kbit | 1024 × 1 | ১৯৭০ |
| 4116 | DRAM | 16 Kbit | 16384 × 1 | ১৯৭৬ |
| 41256 | DRAM | 256 Kbit | 256K × 1 | ১৯৮২ |
| 6116 | SRAM | 16 Kbit | 2048 × 8 | ১৯৮০-এর দশক |
| একটা আধুনিক DDR5 die | DRAM | কয়েক Gbit | বহু bank, ২-চ্যানেল | ২০২০-এর দশক |
মূল পাঠ: 1970-এর 1 কিলোবিট থেকে আজকের Gbit-স্কেল (এক Gbit = 10^6 কিলোবিট) — প্রায় দশ লক্ষ গুণ density বৃদ্ধি, কিন্তু প্রতিটা DRAM cell-এর মূল গঠন (1 transistor + 1 capacitor) অপরিবর্তিত। যা বদলেছে তা হলো manufacturing process — transistor আর capacitor কতটা ছোট বানানো যায় (Moore’s Law-এর সরাসরি ফলাফল, যেটা Level 11-এ ফিরে আসবে)।
নিজে চালিয়ে দেখুন
Digital/Logisim-এ একটা RAM block-এর addressing দেখুন
আমরা transistor-স্তরে SRAM cell simulate করব না (Logisim gate-level abstraction ব্যবহার করে) — বরং built-in RAM component দিয়ে addressing-এর আচরণ যাচাই করব, যেটা এই লেসনের মূল প্রকৌশলগত শিক্ষা।
- Digital/Logisim খুলুন, একটা নতুন circuit বানান।
- Component library থেকে RAM টেনে আনুন — সাধারণত “Memory” category-তে থাকে। Size সেট করুন
16 words × 4 bit(মোট64বিট)। - একটা
4-বিট input বাস (address) RAM-এরA(address) পিনে যুক্ত করুন। - একটা
4-বিট input বাস (data in)D_in-এ যুক্ত করুন। - একটা button/switch
WE(write enable) পিনে যুক্ত করুন। D_out-এ একটা output display (LED বা hex display) যুক্ত করুন।- Clock-টা RAM-এর
clk-এ যুক্ত করুন (যদি synchronous RAM মডেল হয়)।
পরীক্ষা:
১. address = 0000, data_in = 1010, WE = 1, clock pulse দিন → লেখা হলো
২. address = 0101, data_in = 0011, WE = 1, clock pulse দিন → লেখা হলো
৩. WE = 0 করুন
৪. address = 0000 করুন → D_out = 1010 দেখা উচিত
৫. address = 0101 করুন → D_out = 0011 দেখা উচিত
৬. address = 0001 করুন (যেটাতে কখনো লেখা হয়নি) → D_out = অনির্দিষ্ট/0 (simulator-নির্ভর)যা লক্ষ্য করার: আপনি কখনোই সরাসরি row/column দেখছেন না — RAM component-টা তার ভেতরের decoder+mux logic লুকিয়ে রেখেছে। কিন্তু আচরণটা ঠিক এই লেসনে বর্ণিত মডেলের সাথে মেলে: address বদলালেই ভিন্ন cell “select” হয়ে যায়, আর ঠিক সেই cell-এর মান বেরিয়ে আসে — বাকি সব cell অপরিবর্তিত থাকে। ৪-বিট address দিয়ে ১৬টা আলাদা location addressable, যা 2^4 = 16-এর সাথে মেলে।
বাড়তি: RAM size 256 words-এ বাড়িয়ে address bus 8-বিট করুন, আর হিসাব করুন যদি এটা 16×16 grid হিসেবে ভেতরে সংগঠিত হতো, তাহলে row/column address কত বিট করে হতো (√256 = 16 = 2^4, তাই 4+4 = 8 বিট — মিলে যায়)।
একটা built-in RAM component-এর আচরণ থেকে row/column addressing-এর ফলাফল সরাসরি চোখে দেখা যায় — যদিও ভেতরের transistor স্তর simulator-এ দেখানো হয় না।
আপনার নিজের মেশিনের RAM কোন প্রযুক্তি, আর কত দ্রুত
# RAM module-এর টাইপ, গতি, প্রস্তুতকারক দেখুন
sudo dmidecode --type 17
# আউটপুট-এ খুঁজুন:
# Type: DDR4
# Speed: 3200 MT/s
# Configured Memory Speed: 3200 MT/sdmidecode মাদারবোর্ডের SMBIOS/DMI table থেকে সরাসরি hardware তথ্য পড়ে — এটা কোনো অনুমান না, motherboard firmware নিজে যা জানে তাই রিপোর্ট করছে।
# CPU cache (SRAM) সাইজ দেখুন — তুলনার জন্য
lscpu | grep -i cache
# অথবা
cat /sys/devices/system/cpu/cpu0/cache/index*/sizeতুলনা করুন: L1 cache সাধারণত 32–64 KB, L2 256 KB–1 MB, L3 কয়েক MB থেকে কয়েক দশ MB — সবই SRAM। আপনার main memory (DRAM) সম্ভবত 8–64 GB — cache-এর চেয়ে হাজার গুণ বড়, ঠিক যেমন এই লেসনের trade-off table পূর্বাভাস দেয়: DRAM সস্তা ও ঘন বলে বেশি রাখা যায়, SRAM দামি বলে অল্প রাখা হয়।
Configured Memory Speed: 3200 MT/s মানে সেকেন্ডে 3.2 বিলিয়ন data transfer — কিন্তু এটা DRAM cell-এর নিজের access latency না, এটা bus-এর transfer rate; আসল cell-level latency (tRCD, tCL ইত্যাদি) আরও বিস্তারিত timing parameter, যেগুলো Level 3/11-এ memory controller নিয়ে আলোচনায় ফিরে আসবে।
এই লেসনের তত্ত্ব একটা বিমূর্ত মডেল না — আপনার নিজের কম্পিউটারে বসানো আসল DRAM chip-এর নির্দিষ্ট timing number আছে, যেগুলো JEDEC standard মেনে চলে।
নিজের মেশিনে memory hierarchy-র speed jump মাপুন
ধারণা: একটা array-তে বারবার stride দিয়ে access করি (যাতে hardware prefetcher সাহায্য করতে না পারে), array-এর আকার ধীরে ধীরে বাড়াই। যতক্ষণ পুরো array cache-এর কোনো একটা স্তরে (L1/L2/L3, সবই এই লেসনের SRAM) আঁটে, per-access সময় প্রায় স্থির থাকবে। যেই মুহূর্তে array সেই স্তরের সীমা ছাড়িয়ে যাবে, per-access সময়ে একটা স্পষ্ট লাফ দেখা যাবে — কারণ এখন access DRAM (main memory) পর্যন্ত যেতে হচ্ছে।
import time
def measure_stride_access(size_bytes, stride=64, iterations=2_000_000):
"""একটা byte array-তে stride-ভিত্তিক access — cache miss আদায় করার জন্য"""
n = size_bytes
arr = bytearray(n)
idx = 0
t0 = time.perf_counter()
for _ in range(iterations):
arr[idx] = (arr[idx] + 1) & 0xFF
idx = (idx + stride) % n
dt = time.perf_counter() - t0
return dt / iterations # সেকেন্ড প্রতি access
sizes_kb = [4, 16, 32, 64, 128, 256, 512, 1024, 4096, 16384, 65536]
print(f"{'আকার (KB)':>10} {'ns/access':>12}")
for kb in sizes_kb:
t = measure_stride_access(kb * 1024)
print(f"{kb:>10,} {t*1e9:>12.2f}")সাধারণ (illustrative) ফলাফল একটা টিপিক্যাল মেশিনে:
আকার (KB) ns/access
4 1.20 ← L1-এ আঁটে (~32-64 KB সাধারণত)
16 1.25
32 1.30 ← L1-এর কিনারা
64 2.80 ← L2-তে ঢুকেছে (লাফ!)
128 3.10
256 3.40 ← L2-এর কিনারা (~256KB-1MB সাধারণত)
512 8.50 ← L3-তে ঢুকেছে (লাফ!)
1024 9.20
4096 10.50 ← L3-এর কিনারা (কয়েক MB থেকে কয়েক দশ MB)
16384 35.00 ← main memory/DRAM-এ ঢুকেছে (বড় লাফ!)
65536 42.00Python-এর interpreter overhead প্রকৃত সংখ্যাগুলো ঢেকে দেয় — তাই ধাপগুলো (steps) দেখাই আসল লক্ষ্য, নিখুঁত ns মান না। C দিয়ে চালালে ধাপগুলো আরও তীক্ষ্ণ দেখা যাবে, আর perf stat -e cache-misses দিয়ে সরাসরি cache miss সংখ্যা মেলানো যায়।
এটাই এই লেসনের কেন্দ্রীয় দাবির সরাসরি পরিমাপ: SRAM (cache-এর প্রতিটা স্তর) DRAM-এর (main memory) চেয়ে বহুগুণ দ্রুত — শুধু তত্ত্ব না, আপনার নিজের মেশিনে মাপা যায়। এই “ধাপে ধাপে লাফ”-টাই Level 3/11-এর memory hierarchy লেসনগুলোর কেন্দ্রীয় চিত্র — সেখানে আমরা প্রতিটা লাফের পেছনের cache organization (associativity, replacement policy) বিস্তারিত দেখব।
Working set যখন L1 → L2 → L3 → main memory (DRAM)-এর সীমা পার হয়, তখন per-access latency-তে স্পষ্ট, ধাপে ধাপে লাফ দেখা যায় — এই লেসনের SRAM/DRAM speed পার্থক্যের দাবিটা তাত্ত্বিক না, বাস্তবে পরিমাপযোগ্য।
নিজে বানান
Capacitor Leakage সিমুলেটর — কেন ঠিক ৬৪ms?
- একটা DRAM cell-এর ভোল্টেজ সময়ের সাথে exponential decay মডেল করুন
- বিভিন্ন leakage resistance-এর জন্য কখন ভোল্টেজ sense threshold-এর নিচে নামে সেটা বের করুন
- সবচেয়ে "leaky" cell-টাই refresh interval নির্ধারণ করে — সেটা দেখান
- তাপমাত্রা বাড়লে leakage বাড়ে এই effect যোগ করে refresh interval-এর উপর প্রভাব দেখান
লক্ষ্য: শুধু “৬৪ms” সংখ্যাটা মুখস্থ না করে, সেটা কেন এই মানটা — সিমুলেশন দিয়ে সেটা অনুভব করা।
import math
def voltage_at(t_seconds, v0=1.0, r_ohm=1e13, c_farad=30e-15):
"""RC discharge model: V(t) = V0 * e^(-t/RC)"""
tau = r_ohm * c_farad
return v0 * math.exp(-t_seconds / tau)
def time_to_threshold(v0, threshold, r_ohm, c_farad):
"""কখন V(t) থ্রেশহোল্ডের নিচে নামবে — বীজগণিতে সমাধান করে"""
tau = r_ohm * c_farad
# V0 * e^(-t/tau) = threshold → t = -tau * ln(threshold/V0)
return -tau * math.log(threshold / v0)
# ── বেসলাইন: টিপিক্যাল cell ──────────────────────────────
V0 = 1.0 # পূর্ণ চার্জ = লজিক 1
THRESHOLD = 0.5 # sense amp-এর ন্যূনতম শনাক্তযোগ্য মান (সরলীকৃত)
C = 30e-15 # 30 femtofarad — একটা টিপিক্যাল DRAM cell capacitance
print(f"{'R (leakage, ohm)':>20} {'time to threshold':>20}")
for r in [1e12, 5e12, 1e13, 5e13, 1e14]:
t = time_to_threshold(V0, THRESHOLD, r, C)
print(f"{r:>20.0e} {t*1000:>17.2f} ms")প্রত্যাশিত ফলাফল (order-of-magnitude — বাস্তব ভ্যালু process/vendor-নির্ভর):
R (leakage, ohm) time to threshold
1e+12 0.02 ms
5e+12 0.10 ms
1e+13 0.21 ms
5e+13 1.04 ms
1e+14 2.08 msলক্ষ্য করুন R (leakage resistance) যত বড়, cell তত কম “leaky”, আর decay হতে তত বেশি সময় লাগে। বাস্তব DRAM cell-এর effective leakage resistance আরও অনেক বড় (~10^15–10^16 ohm রেঞ্জ, engineering effort দিয়ে minimize করা), যেটা time to threshold-কে দশ থেকে শত মিলিসেকেন্ডে নিয়ে যায় — আর তার উপর একটা safety margin যোগ করে JEDEC 64ms (বা high-temp-এ 32ms) নির্ধারণ করে।
তাপমাত্রার effect যোগ করুন:
def leakage_resistance_at_temp(r_25c, temp_celsius):
"""সরলীকৃত মডেল — leakage current প্রতি ১০°C-এ প্রায় দ্বিগুণ হয়,
তাই resistance (current-এর বিপরীত) প্রায় অর্ধেক হয়"""
doublings = (temp_celsius - 25) / 10
return r_25c / (2 ** doublings)
R_25C = 1e14
for temp in [25, 45, 65, 85]:
r = leakage_resistance_at_temp(R_25C, temp)
t = time_to_threshold(V0, THRESHOLD, r, C)
print(f"{temp}°C → effective R = {r:.2e} ohm → time to threshold = {t*1000:.2f} ms")25°C → effective R = 1.00e+14 ohm → time to threshold = 2.08 ms
45°C → effective R = 2.50e+13 ohm → time to threshold = 0.52 ms
65°C → effective R = 6.25e+12 ohm → time to threshold = 0.13 ms
85°C → effective R = 6.25e+11... (leakage বেড়ে চলে) → আরও দ্রুত decayসিদ্ধান্ত: গরম DRAM দ্রুত leak করে — এই কারণেই সার্ভার/data center-এর মেমরি মডিউলে temperature sensor থাকে, আর কিছু controller গরম হলে refresh interval স্বয়ংক্রিয়ভাবে ছোট করে দেয় (64ms → 32ms) — এটাই “refresh rate doubling at high temperature” নামে পরিচিত বাস্তব JEDEC ফিচার। আপনার সিমুলেশন এই decision-এর পেছনের ভৌত কারণটা সংখ্যায় দেখিয়ে দিলো।
নিজে বাড়ান: সিমুলেশনে ১০০০টা cell তৈরি করুন, প্রতিটার R-এ সামান্য random variation (manufacturing tolerance) যোগ করুন, আর দেখুন সবচেয়ে “দুর্বল” (worst-case) cell-টাই কীভাবে পুরো chip-এর refresh interval নির্ধারণ করে — একটা chip ঠিক ততটাই “ভালো” যতটা তার সবচেয়ে খারাপ cell।
Address Decoder Visualizer — row/column কীভাবে ভাগ হয় সেটা দেখুন
- একটা memory array-র মাত্রা (rows × columns) থেকে দরকারি address bit সংখ্যা বের করুন
- একটা পূর্ণসংখ্যা address-কে row address আর column address-এ ভাঙুন
- একটা text grid এঁকে দেখান কোন WL assert হচ্ছে আর কোন column select হচ্ছে
- কয়েকটা ভিন্ন address দিয়ে চালিয়ে দেখুন প্রতিটা কীভাবে ভিন্ন cell "select" করে
লক্ষ্য: “row decoder + column mux” ধারণাটা শুধু prose না, নিজের হাতে কোড করে দেখা — একটা address কীভাবে যান্ত্রিকভাবে দুই ভাগে ভেঙে যায় আর একটা নির্দিষ্ট cell নির্দেশ করে।
import math
def address_to_row_col(address, n_rows, n_cols):
"""একটা flat address-কে row+column-এ ভাঙে — ঠিক row decoder+column mux যা করে"""
row_bits = n_rows.bit_length() - 1 # log2(n_rows), ধরে নিচ্ছি n_rows একটা 2-এর ঘাত
col_bits = n_cols.bit_length() - 1
assert (1 << row_bits) == n_rows, "n_rows অবশ্যই 2^k হতে হবে"
assert (1 << col_bits) == n_cols, "n_cols অবশ্যই 2^k হতে হবে"
col = address & (n_cols - 1) # নিচের col_bits বিট
row = (address >> col_bits) & (n_rows - 1) # তার উপরের row_bits বিট
return row, col, row_bits, col_bits
def draw_grid(n_rows, n_cols, selected_row, selected_col, max_show=16):
"""সিলেক্টেড WL আর column হাইলাইট করে একটা ছোট গ্রিড আঁকে"""
rows_to_show = min(n_rows, max_show)
cols_to_show = min(n_cols, max_show)
print(f"\n (দেখানো হচ্ছে {rows_to_show}×{cols_to_show}, "
f"পূর্ণ গ্রিড {n_rows}×{n_cols})")
header = " " + "".join(
"▼ " if c == selected_col else "· " for c in range(cols_to_show)
)
print(header)
for r in range(rows_to_show):
marker = "WL→" if r == selected_row else " "
line = "".join(
"█ " if (r == selected_row and c == selected_col) else
("▓ " if r == selected_row else "· ")
for c in range(cols_to_show)
)
print(f" {marker} {line}")
# ── উদাহরণ: 4 Mbit array, 2048 × 2048 (এই লেসনের example section-এর মতোই) ──
N_ROWS, N_COLS = 2048, 2048
for test_address in [0, 1, 5, 2049, 4_194_303]:
row, col, rbits, cbits = address_to_row_col(test_address, N_ROWS, N_COLS)
print(f"\naddress = {test_address:>7,} (বাইনারিতে {test_address:022b})")
print(f" → row address ({rbits} বিট) = {row:>4} → row decoder সেই একটা WL assert করে")
print(f" → col address ({cbits} বিট) = {col:>4} → column mux সেই bit line বাছে")
draw_grid(N_ROWS, N_COLS, row, col)প্রত্যাশিত আউটপুট (সংক্ষিপ্ত, একটা address-এর জন্য):
address = 5 (বাইনারিতে 0000000000000000000101)
→ row address (11 বিট) = 0 → row decoder সেই একটা WL assert করে
→ col address (11 বিট) = 5 → column mux সেই bit line বাছে
(দেখানো হচ্ছে 16×16, পূর্ণ গ্রিড 2048×2048)
· · · · · ▼ · · · · · · · · · ·
WL→ ▓ ▓ ▓ ▓ ▓ █ ▓ ▓ ▓ ▓ ▓ ▓ ▓ ▓ ▓ ▓
· · · · · · · · · · · · · · · ·
⋮█ চিহ্নটা ঠিক সেই cell যেখানে row (WL) আর column দুটোই মেলে — সেটাই আসল output। ▓ মানে সেই row-এর বাকি সব cell “জেগে” আছে (row activate হয়েছে) কিন্তু column mux তাদের বাদ দিয়েছে।
নিজে বাড়ান:
address = 2049দিয়ে চালিয়ে দেখুন row কীভাবে1-এ বদলে যায় (2049 = 2048 + 1, আর column bit-এর সংখ্যা2048 = 2^11, তাই এক row বাড়ে)।n_rows,n_cols-এর সংখ্যা পরিবর্তন করে অ-বর্গাকার (non-square) array-তে (যেমন4096 × 1024) কী পরিবর্তন হয় দেখুন — row বিট আর column বিট আর সমান থাকবে না।- একটা “word-oriented” সংস্করণ বানান যেখানে একটা address একসাথে
8-টা পাশাপাশি bit-plane থেকে ৮ বিট output দেয় (উপরের “word-oriented organization” অংশের সরাসরি প্রয়োগ)।
বাস্তব সিস্টেমে
SRAM/DRAM বাস্তব সিস্টেমে
CPU register file ও L1/L2/L3 cache — সবচেয়ে দ্রুত tier, SRAM দিয়ে বানানো। Register file সবচেয়ে দ্রুত (CPU-এর নিজের clock speed-এ কাজ করে, ~সাব-ns), তারপর L1 (~1ns, 32-64 KB), L2 (~3-10ns, 256KB-1MB), L3 (~10-40ns, কয়েক থেকে কয়েক দশ MB) — প্রতিটা স্তর একটু ধীর কিন্তু বড়। এই পুরো সিঁড়িটাই SRAM-এর “দ্রুত কিন্তু দামি” trade-off-এর সরাসরি স্থাপত্যগত ফলাফল, আর এই লেসনের আগের “নিজের মেশিনে মাপুন” experiment-এ এই সিঁড়ির প্রতিটা ধাপই সরাসরি পরিমাপযোগ্য।
DDR4/DDR5 DIMM — আপনার ল্যাপটপ/ডেস্কটপের main memory, DRAM দিয়ে বানানো। 16-64 GB সহজলভ্য দামে সম্ভব শুধু DRAM cell ক্ষুদ্র বলে — একই capacity SRAM দিয়ে বানাতে গেলে চিপের আকার আর দাম দুটোই ব্যবহারিকভাবে অসম্ভব হয়ে যেত (Q6-এর হিসাব দ্রষ্টব্য)।
GDDR6 ও HBM (High Bandwidth Memory) — GPU-তে ব্যবহৃত DRAM variant, কিন্তু bandwidth-অপটিমাইজড (অনেক প্রশস্ত bus, উঁচু transfer rate)। HBM বিশেষভাবে আকর্ষণীয় — DRAM die-গুলো GPU-র ঠিক পাশেই স্তরে স্তরে (3D stacking) বসানো হয়, wire-এর দৈর্ঘ্য কমিয়ে বিশাল bandwidth পাওয়ার জন্য। মূলনীতি অভিন্ন থাকে (1T1C cell, refresh প্রয়োজন), শুধু packaging/interface ভিন্ন।
FPGA Block RAM (BRAM) — FPGA চিপের ভেতরে embedded ছোট SRAM block, ডিজাইনার নিজের logic-এ যেভাবে খুশি ব্যবহার করতে পারেন (buffer, lookup table, ছোট cache)। SRAM বেছে নেওয়া হয়েছে কারণ FPGA-তে refresh controller-এর জটিলতা যোগ করা অবাস্তব, আর BRAM সাধারণত ছোট (কয়েক কিলোবাইট থেকে কয়েক মেগাবাইট) হওয়ায় SRAM-এর area খরচ মানিয়ে নেওয়া যায়। এই লেসনের Logisim experiment-এ যেই RAM component ব্যবহার করেছেন, সেটাও কার্যত এই একই ধারণার একটা simplified মডেল।
eDRAM (embedded DRAM) — একটা চমৎকার মাঝামাঝি উদাহরণ। IBM POWER7/POWER8 প্রসেসর তাদের L3 cache-এ SRAM-এর বদলে eDRAM ব্যবহার করেছিল — DRAM-এর ঘনত্বের কাছাকাছি সুবিধা পেতে, অথচ CPU চিপের ভেতরেই বসিয়ে সাধারণ (off-chip) DRAM-এর চেয়ে দ্রুত access পেতে। refresh প্রয়োজন এখনও থাকে, কিন্তু chip-এর ভেতরের controller সেটা লুকিয়ে রাখে। প্রমাণ করে speed-density spectrum-টা আসলে বাইনারি (SRAM অথবা DRAM) না, একটা continuum — ইঞ্জিনিয়াররা যেকোনো বিন্দুতে বসতে পারেন যদি সঠিক trade-off বেছে নেওয়া যায়।
Rowhammer — একটা নিরাপত্তা দুর্বলতা যেটা সরাসরি DRAM-এর ঘনত্ব থেকে জন্মায়। Cell-গুলো এত কাছাকাছি বসানো যে একটা row-কে বারবার দ্রুত activate করলে (হাজার হাজার বার প্রতি refresh cycle-এ) পাশের row-এর capacitor-এ electrical interference (coupling) হয়ে তার charge অস্বাভাবিকভাবে দ্রুত leak করে যায় — normal 64ms refresh সময়ের অনেক আগেই bit flip ঘটে। ২০১৪-এ Google Project Zero প্রথম দেখায় এই bit flip দিয়ে privilege escalation সম্ভব — শুধু সফটওয়্যার দিয়ে বারবার নির্দিষ্ট মেমরি address access করেই। Level 10 (Security)-এ এটা বিস্তারিত ফিরে আসবে, কিন্তু মূল কারণটা সম্পূর্ণভাবে এই লেসনের — cell density বাড়ানোর একটা অনিচ্ছাকৃত পার্শ্বপ্রতিক্রিয়া।
Register file-এর multi-port SRAM — CPU register file আসলে একটা বিশেষায়িত multi-port SRAM array (উপরের “Multi-port SRAM” অংশ দ্রষ্টব্য), যেখানে একসাথে একাধিক read port আর write port থাকে (একই cycle-এ একাধিক register পড়া/লেখা দরকার হয়) — লেসন ১৫-এ এটাই datapath-এর কেন্দ্রীয় উপাদান হবে।
ECC (Error-Correcting Code) memory — সার্ভার-গ্রেড DRAM-এ প্রতি 64 বিট ডেটার সাথে বাড়তি 8 বিট (Hamming code) যোগ করা হয়, যাতে leakage বা cosmic-ray-induced bit flip স্বয়ংক্রিয়ভাবে ধরা ও (single-bit হলে) সংশোধন করা যায়। এটা refresh-এর ব্যর্থতা বা তাৎক্ষণিক soft error-এর বিরুদ্ধে একটা দ্বিতীয় স্তরের প্রতিরক্ষা — refresh নিজেই একদম নিখুঁত না, তাই একটা backup mechanism দরকার হয়।
LPDDR (মোবাইল ডিভাইসে) — স্মার্টফোন/ট্যাবলেটে সাধারণ DDR-এর বদলে LPDDR (Low Power DDR) ব্যবহার হয়, যেখানে refresh-এর energy খরচ বিশেষভাবে কমানো হয়েছে (temperature-compensated refresh rate, deep power-down mode-এ self-refresh)। ব্যাটারি-চালিত ডিভাইসে refresh-এর “চলমান খরচ” সরাসরি ব্যাটারি লাইফের সাথে সম্পর্কিত — এই লেসনের “self-refresh” আলোচনার একটা সরাসরি প্রকৌশলগত পরিণতি।
যে ভুলগুলো সবাই করে
“DRAM আসলে SRAM-এরই একটা ধীর/সস্তা সংস্করণ।”
ভুল — এরা সম্পূর্ণ ভিন্ন সংরক্ষণ পদ্ধতি, শুধু speed grade আলাদা না।
SRAM একটা feedback loop দিয়ে সক্রিয়ভাবে নিজের মান ধরে রাখে (দুইটা inverter একে অপরকে ক্রমাগত “মনে করিয়ে দেয়”)। DRAM একটা passive capacitor-এ charge জমিয়ে রাখে — কোনো সক্রিয় feedback নেই, শুধু একটা ভৌত property (charge storage) যেটা স্বাভাবিকভাবেই leak করে।
এই মৌলিক পার্থক্যের কারণেই DRAM-এর refresh লাগে আর SRAM-এর লাগে না — এটা “ধীর বলে refresh লাগে” না, বরং “ভিন্ন mechanism বলে refresh লাগে বা লাগে না।”
“'Static' মানে SRAM কখনো ডেটা হারায় না — এটা কি non-volatile?”
না — SRAM এখনও volatile। “Static” শব্দটার অর্থ শুধু এটুকু: power চালু থাকা অবস্থায় সক্রিয় refresh লাগে না (feedback loop নিজেই কাজ চালিয়ে যায়)। কিন্তু power off হলে feedback loop-এর energy হারিয়ে যায়, দুইটা inverter কোনো একটা অনির্দিষ্ট (বা random) অবস্থায় settle করে — SRAM-এর ডেটা মুছে যায়, ঠিক DRAM-এর মতোই।
Non-volatile memory (যেমন flash, বা আধুনিক MRAM/ReRAM) সম্পূর্ণ ভিন্ন প্রযুক্তি — সেখানে ডেটা একটা ভৌত অবস্থা (floating gate charge, magnetic orientation) হিসেবে সংরক্ষিত হয় যেটা power ছাড়াই স্থায়ী থাকে। এই লেসনে আমরা সেটা কভার করিনি — SRAM ও DRAM দুটোই volatile, শুধু volatile হওয়ার “খরচ” আলাদা (DRAM-এর ক্রমাগত refresh বনাম SRAM-এর ক্রমাগত power draw)।
“Refresh একটা মাঝেমধ্যে ঘটা রক্ষণাবেক্ষণ কাজ, যেমন disk defragmentation-এর মতো।”
না — refresh একটা অবিরাম, উচ্চ-ফ্রিকোয়েন্সি ব্যাকগ্রাউন্ড প্রক্রিয়া, memory চালু থাকা প্রতি মুহূর্তে চলতে থাকে। 8192-row একটা array-তে 64ms window মানে গড়ে প্রতি ~7.8 microsecond-এ একটা refresh command — সেকেন্ডে প্রায় ১,২৮,০০০ বার। এটা memory bandwidth-এর একটা ধ্রুবক, চলমান খরচ, “মাঝেমধ্যে একবার” ঘটা কোনো maintenance টাস্ক না।
“বেশি transistor মানে সবসময় ভালো/বেশি সক্ষম memory।”
এখানে ঠিক উল্টো ঘটে। SRAM-এর ৬টা transistor তাকে দ্রুত ও রিফ্রেশ-মুক্ত করে, কিন্তু DRAM-এর মাত্র ১টা transistor তাকে ঘনত্বে ও দামে জয়ী করে। “বেশি জটিলতা = বেশি সক্ষমতা” — এই স্বজ্ঞা এখানে খাটে না; বরং কম transistor = কম জায়গা = বেশি bit প্রতি চিপে, যেটাই মূল memory-র জন্য আসল লক্ষ্য। Engineering সবসময় trade-off — প্রতিটা প্রযুক্তি একটা নির্দিষ্ট optimization target-এর জন্য ডিজাইন করা, “বেশি ভালো” কোনো universal দিক নেই।
বুঝেছেন কি না দেখুন
1কেন SRAM-এ refresh লাগে না কিন্তু DRAM-এ লাগে? দুইটার সংরক্ষণ পদ্ধতির পার্থক্য থেকে ব্যাখ্যা করুন।
যুক্তি
SRAM cell দুইটা cross-coupled inverter দিয়ে একটা সক্রিয় feedback loop তৈরি করে — প্রতিটা inverter অন্যটার output-কে নিজের input হিসেবে নিয়ে ক্রমাগত সেই মান “পুনরায় নিশ্চিত” করে। যতক্ষণ Vdd সরবরাহ থাকে, এই loop নিজে থেকেই স্থিতিশীল থাকে — কোনো বাহ্যিক হস্তক্ষেপ ছাড়াই।
DRAM cell একটা passive capacitor-এ charge জমা রাখে, কোনো active feedback নেই। বাস্তব capacitor কখনো নিখুঁত insulator না — access transistor-এর subthreshold leakage, junction leakage, dielectric leakage — এসবের কারণে charge ধীরে ধীরে বেরিয়ে যায় (V(t) = V_0 · e^(-t/RC))। কিছু সময় পর ভোল্টেজ sense threshold-এর নিচে নেমে গেলে মূল মান আর নির্ভরযোগ্যভাবে পড়া যায় না — তাই সময়মতো পড়ে-আবার-লিখে (refresh) সেই decay ঠেকাতে হয়।
মূল পার্থক্য: feedback (active, self-sustaining) বনাম charge storage (passive, decaying)।
2একটা DRAM chip-এর refresh window 64ms, আর তাতে 8192-টা row আছে। গড়ে প্রতি row refresh করতে কত সময় ব্যবধানে (tREFI) command পাঠাতে হবে?
প্রয়োগ
64ms, আর তাতে 8192-টা row আছে। গড়ে প্রতি row refresh করতে কত সময় ব্যবধানে (tREFI) command পাঠাতে হবে?মানে গড়ে প্রতি ৭.৮১ মাইক্রোসেকেন্ডে একটা refresh command পাঠাতে হবে যাতে 64ms-এর মধ্যে সব 8192-টা row অন্তত একবার refresh হয়ে যায়। এটাই JEDEC DDR SDRAM standard-এ tREFI নামে সংজ্ঞায়িত timing parameter — একটা বাস্তব সংখ্যা যেটা memory controller প্রতিটা DRAM chip-এর জন্য মেনে চলতে বাধ্য।
বাড়তি প্রসঙ্গ: প্রতিটা refresh command নিজে সম্পন্ন হতে একটা নির্দিষ্ট সময় লাগে, যেটাকে tRFC (Refresh Cycle time) বলা হয় — এই সময়টায় সেই row (এবং সাধারণত পুরো bank) সাধারণ read/write-এর জন্য অনুপলব্ধ থাকে। তাই refresh-এর প্রকৃত bandwidth খরচ শুধু “কত ঘনঘন” (tREFI) না, “প্রতিবার কতক্ষণ” (tRFC)-ও নির্ভর করে। বড় density-র চিপে tRFC বড় হতে থাকে (একসাথে বেশি cell refresh করতে বেশি সময় লাগে), যেটা ঘনত্ব বাড়ার সাথে সাথে refresh overhead-কেও ধীরে ধীরে বাড়িয়ে দেয় — density আর refresh overhead-এর মধ্যে এই টানাপোড়েনটাও DRAM ডিজাইনের একটা বাস্তব বিবেচনা।
3একটা 4 Megabit memory array-কে 2048 × 2048 grid হিসেবে সাজানো হয়েছে। Row address আর column address-এর জন্য কত বিট করে লাগবে, আর মোট address বিট কত?
প্রয়োগ
4 Megabit memory array-কে 2048 × 2048 grid হিসেবে সাজানো হয়েছে। Row address আর column address-এর জন্য কত বিট করে লাগবে, আর মোট address বিট কত?2048 = 2^11, তাই:
- Row address: ১১ বিট (
11-to-2048decoder সেই একটা word line assert করবে) - Column address: ১১ বিট (
2048-to-1mux দিয়ে একটা bit line বাছাই হবে) - মোট address:
11 + 11 =২২ বিট
যাচাই: 2^22 = 4,194,304 = 4 Megabit — ঠিক মিলে যায়। লক্ষ্য করুন array-টাকে (প্রায়) বর্গাকার (2048 × 2048) রাখলে row+column decoder-এর মোট জটিলতা সর্বনিম্ন হয় — একটা flat 22-to-4194304 decoder ব্যবহারিকভাবে অসম্ভব হতো।
4কেন CPU-এর L1 cache SRAM দিয়ে বানানো হয়, main memory DRAM দিয়ে — flash memory দিয়ে নয়? তিনটার মধ্যে trade-off ব্যাখ্যা করুন।
ডিজাইন
তিনটাই ভিন্ন optimization target-এ ডিজাইন করা:
SRAM (L1/L2/L3 cache): সবচেয়ে দ্রুত (~1ns বা তার কম), কিন্তু cell প্রতি ৬টা transistor লাগে বলে জায়গা/দাম বেশি — তাই অল্প পরিমাণে (কিলোবাইট থেকে কয়েক মেগাবাইট) ব্যবহার হয়, যেখানে গতি সবচেয়ে বেশি গুরুত্বপূর্ণ (প্রতি instruction-এ বারবার access হয়)।
DRAM (main memory): মাঝারি গতি (~10-50ns), কিন্তু cell প্রতি মাত্র ১টা transistor + ১টা capacitor বলে অনেক ঘন ও সস্তা — তাই গিগাবাইট পরিমাণে ব্যবহার করা যায়, যেখানে ক্ষমতা (capacity) বেশি গুরুত্বপূর্ণ। খরচ: প্রতি ~64ms-এ refresh, আর SRAM-এর চেয়ে ধীর।
Flash (SSD/storage, এই লেসনে কভার করা হয়নি): সম্পূর্ণ ভিন্ন প্রযুক্তি (floating-gate transistor) — অনেক ধীর (microsecond থেকে millisecond স্কেল), কিন্তু non-volatile — power off হলেও ডেটা থাকে। এই কারণেই এটা RAM (working memory) হিসেবে না, persistent storage হিসেবে ব্যবহৃত হয়।
সংক্ষেপে: speed vs density vs persistence — তিনটা ভিন্ন অক্ষ, তিনটা ভিন্ন প্রযুক্তি প্রতিটা একটা অক্ষে optimize করা। একটা single memory technology দিয়ে সব প্রয়োজন মেটানো সম্ভব না বলেই CPU/computer-এ memory hierarchy-র একাধিক স্তর থাকে — এটাই Level 3-এ পূর্ণাঙ্গভাবে আলোচিত হবে।
5DRAM-এর read কেন “destructive” বলা হয়, আর সেই সমস্যা কীভাবে সামলানো হয়?
যুক্তি
DRAM cell-এর capacitor অত্যন্ত ছোট (~30fF), কিন্তু bit line-এর নিজস্ব parasitic capacitance তুলনায় অনেক বড়। Read করার সময় word line assert হলে cell-এর capacitor bit line-এর সাথে সরাসরি যুক্ত হয়ে যায় আর তাদের মধ্যে charge sharing ঘটে — এই প্রক্রিয়ায় cell-এর নিজের charge redistribute হয়ে দুর্বল/পরিবর্তিত হয়ে যায়। তাই read operation নিজেই মূল সংরক্ষিত মানকে “নষ্ট” করে দেয় — এখান থেকেই “destructive read” নাম।
সমাধান: sense amplifier যেই bit line-এর ক্ষুদ্র ভোল্টেজ পরিবর্তন থেকে মূল মান (0/1) নির্ণয় করে, সাথে সাথে সেই amplified, পূর্ণ-শক্তির মানটাই আবার cell-এ ফিরিয়ে লিখে দেয় (rewrite-after-read) — এই rewrite DRAM-এর read সার্কিটেই built-in, memory controller-এর আলাদা কিছু করতে হয় না। ফলে বাইরের দিক থেকে ডেটা অক্ষুণ্ণ থাকে, যদিও ভেতরে প্রতিটা read একটা write-ও ঘটাচ্ছে।
6আপনাকে একটা on-chip buffer ডিজাইন করতে বলা হয়েছে যেটা মাত্র 2 KB (খুব ছোট), কিন্তু প্রতি clock cycle-এ access হতে হবে (অত্যন্ত দ্রুত)। SRAM নাকি DRAM বাছবেন, আর কেন? বিপরীত পরিস্থিতিতে (8 GB, কিন্তু access speed গুরুত্বপূর্ণ না) কী পরিবর্তন হয়?
ডিজাইন
2 KB (খুব ছোট), কিন্তু প্রতি clock cycle-এ access হতে হবে (অত্যন্ত দ্রুত)। SRAM নাকি DRAM বাছবেন, আর কেন? বিপরীত পরিস্থিতিতে (8 GB, কিন্তু access speed গুরুত্বপূর্ণ না) কী পরিবর্তন হয়?প্রথম case (2KB, প্রতি cycle access): SRAM। ক্ষুদ্র আকার (2KB) মানে ৬T cell-এর area overhead কোনো সমস্যা না — মোট transistor সংখ্যা এখনও ব্যবস্থাপনাযোগ্য (2KB × 8 × 6 = ~98,000 transistor, আধুনিক চিপে তুচ্ছ)। আর “প্রতি cycle access” মানে গতিই সবচেয়ে গুরুত্বপূর্ণ চাহিদা — DRAM-এর ~10-50ns latency আর refresh-জনিত সাময়িক বন্ধ থাকা (busy period) এই ব্যবহারে মেনে নেওয়া যাবে না।
দ্বিতীয় case (8GB, গতি মুখ্য না): DRAM। 8GB-কে SRAM দিয়ে বানাতে গেলে (8 × 10^9 × 8 × 6 = ~384 বিলিয়ন transistor শুধু cell-এর জন্য) ব্যবহারিকভাবে অসম্ভব দামি ও বড়। যেহেতু গতি এখানে মুখ্য বিবেচনা না, DRAM-এর ধীরগতি ও refresh overhead মেনে নেওয়া যায়, বিনিময়ে বিশাল ক্ষমতা কম খরচে পাওয়া যায়।
সাধারণ নীতি: ছোট + দ্রুত-প্রয়োজন → SRAM। বড় + ক্ষমতা-প্রয়োজন → DRAM। বাস্তব সিস্টেমে এই দুইয়ের মাঝে একাধিক স্তর (L1/L2/L3 cache, তারপর main memory) রেখে দুই world-এর সুবিধাই নেওয়া হয় — এটাই memory hierarchy-র মূল যুক্তি।
এরপর কী
এরপর কী
এই লেসনে আমরা memory-কে একটা isolated component হিসেবে দেখেছি — একটা cell কীভাবে bit ধরে রাখে (SRAM feedback, DRAM charge), আর একটা array-তে address কীভাবে সেই bit-কে খুঁজে বের করে (row decoder + column mux)।
দ্রুত recap — এগুলো মনে আছে কি না যাচাই করুন:
- SRAM cell ৬টা transistor — দুইটা cross-coupled inverter (feedback) + দুইটা access transistor
- DRAM cell ১টা transistor + ১টা capacitor — কোনো active feedback নেই, শুধু charge storage
- Refresh লাগে কারণ capacitor leak করে (
V(t) = V_0 · e^(-t/RC)), না লাগলে DRAM ডেটা হারাবে 64msrefresh window একটা safety margin, worst-case leaky cell-এর decay time-এর নিচে- Address = row address + column address; row decoder একটা WL assert করে, column mux একটা bit বাছে
- SRAM: দ্রুত, দামি, ছোট আকারে ব্যবহার (cache, register file); DRAM: ধীর, সস্তা, বড় আকারে ব্যবহার (main memory)
যদি এই ছয়টা পয়েন্ট পরিষ্কার মনে থাকে, আপনি পরের লেসনের জন্য প্রস্তুত — সেখানে memory আর এতদিন শেখা প্রতিটা component একসাথে বসবে।
এই মডিউলে এখন পর্যন্ত কোথায় আছি:
| লেসন | বিষয় | এই লেসনে কীভাবে ব্যবহৃত হলো |
|---|---|---|
| ১-৩ | Transistor → CMOS gate | SRAM/DRAM cell-এর transistor-গুলো এই একই মৌলিক building block |
| ৪-৮ | Adder → ALU | (পরের লেসনে সরাসরি ব্যবহৃত হবে) |
| ৭ | Decoder, MUX | Row decoder, column mux — এই লেসনের addressing-এর মেরুদণ্ড |
| ৯ | Latch, flip-flop | SRAM cell-এর cross-coupled feedback একই ধারণা |
| ১০ | Register file | Multi-port SRAM-এর সরাসরি পূর্বসূরি |
| ১১ | Clock, timing | Read/write timing diagram, DDR-এর ডাবল-এজ ধারণা |
| ১২ | FSM | DRAM bank-এর Idle/Active/Precharging state model |
| ১৪ (আজ) | SRAM, DRAM | Cell physics, refresh, addressing |
লক্ষ্য করুন — memory একা বসে কিছু করে না। উপরের টেবিলের প্রতিটা টুকরোই এখনও আলাদা আলাদা: gate, adder/ALU, flip-flop/register, clock, FSM, আর এখন memory।
পরের লেসনে আমরা এই সবগুলো টুকরোকে একসাথে wire করব — register file, ALU, memory, আর কিছু multiplexer, একটা bus system দিয়ে যুক্ত করে, আর তার উপর একটা FSM (control unit) বসিয়ে বলে দেব কোন cycle-এ কোন signal assert হবে। যখন সেই পুরো জিনিসটা একসাথে দাঁড়িয়ে যাবে, আপনি প্রথমবার দেখবেন এটা আসলে কী — এটাকে বলা হয় CPU-এর datapath আর control unit। আর একদম শেষে, মডিউলের শেষ লেসনে, পুরো জিনিসটাকে Verilog-এ লিখে দেখব।
আরও পড়ুন
- Computer Organization and Design (RISC-V Edition), Chapter 5 — David A. Patterson, John L. Hennessy · Memory hierarchy আর DRAM organization-এর প্রামাণ্য আলোচনা
- Memory Systems: Cache, DRAM, Disk — Bruce Jacob, Spencer Ng, David Wang · DRAM cell আর refresh mechanism-এর গভীর প্রকৌশল বিবরণ
- JEDEC DDR4 SDRAM Standard (JESD79-4) — JEDEC Solid State Technology Association · বাস্তব refresh timing (tREFI, tRFC) সংজ্ঞায়িত করে
- Digital — a logic simulator — Helmut Neemann · RAM component দিয়ে addressing experiment করার জন্য