রেজিস্টার কন্ট্রোলের জন্য বিট ম্যানিপুলেশন
এই পাঠে যা শিখবেন
- কেন এমবেডেড রেজিস্টার নিয়ন্ত্রণে সবসময় বিট-লেভেল অপারেশন ব্যবহার করা হয়, পুরো ওভাররাইট নয়
- set/clear/toggle/read — এই চারটি মৌলিক বিট অপারেশনের বিটওয়াইজ ফর্মুলা ও কারণ
- একাধিক বিট নিয়ে গঠিত বিট-ফিল্ড mask+shift দিয়ে কীভাবে read/write করতে হয়
- একটি সম্পূর্ণ, সত্যিকারের চলমান সিমুলেশন — প্রতিটি ধাপে
format(reg, '08b')দিয়ে রেজিস্টারের অবস্থা ট্রেস করা
১ · কেন পুরো রেজিস্টার ওভাররাইট করা যায় না
Computer Architecture কোর্সে রেজিস্টার সাধারণভাবে কী তা
দেখানো হয়েছে — এখানে আমরা এমবেডেড-স্পেসিফিক বাস্তবতায় যাচ্ছি। একটি মাইক্রোকন্ট্রোলারের কন্ট্রোল/স্ট্যাটাস
রেজিস্টার প্রায়ই একটি ৮, ১৬ বা ৩২-বিট মান, যার প্রতিটি বিট (বা কয়েক বিটের একটি গ্রুপ)
সম্পূর্ণ স্বতন্ত্র একটি হার্ডওয়্যার ফিচার নিয়ন্ত্রণ করে — যেমন bit7 হয়তো একটি পিনের DIRECTION ঠিক করে, bit3
একটি পেরিফেরাল ENABLE করে, আর bit1-bit0 মিলে একটি MODE বেছে নেয়। এই সব বিট একই রেজিস্টারে
একসাথে থাকে বলে, যদি আপনি নতুন মান reg = 0b00001000 লিখে সরাসরি পুরো রেজিস্টার বসিয়ে দেন, তাহলে
অন্য বিটগুলোর (DIR, MODE) আগের মান হারিয়ে যাবে — যা হয়তো অন্য কোনো কোড বা ইন্টারাপ্ট হ্যান্ডলার সেট করে
রেখেছিল। তাই এমবেডেড C-তে প্রায় সবসময় বিটওয়াইজ অপারেটর (|, &, ^,
~, <<, >>) দিয়ে শুধু নির্দিষ্ট বিট বদলানো
হয়, বাকিগুলো অক্ষত রেখে।
২ · চারটি মৌলিক বিট অপারেশন
ধরা যাক reg একটি রেজিস্টারের মান এবং আমরা এর n-তম বিট নিয়ে কাজ করছি।
Set bit (বিটটিকে ১ করা, বাকি বিট অক্ষত রেখে) — 1 << n দিয়ে শুধু সেই
অবস্থানে ১ বসানো একটি মাস্ক তৈরি হয়, তারপর OR করলে সেই বিট ১ হয়ে যায় আর বাকি সব বিট নিজের মান
ধরে রাখে (কারণ x OR 0 = x):
$$ \text{reg} \leftarrow \text{reg} \;\lor\; (1 \ll n) $$
Clear bit (বিটটিকে ০ করা) — ~(1 << n) দিয়ে সেই এক অবস্থান বাদে বাকি সব
জায়গায় ১ থাকা একটি মাস্ক তৈরি হয়, তারপর AND করলে শুধু সেই বিট ০ হয়ে যায় (কারণ
x AND 1 = x):
$$ \text{reg} \leftarrow \text{reg} \;\land\; \lnot(1 \ll n) $$
Toggle bit (বিটটি উল্টে দেওয়া — ০ হলে ১, ১ হলে ০) — XOR ব্যবহার করা হয়, কারণ
x XOR 1 = \bar{x} কিন্তু x XOR 0 = x:
$$ \text{reg} \leftarrow \text{reg} \;\oplus\; (1 \ll n) $$
Read bit (শুধু সেই বিটের মান জানা, বাকি রেজিস্টার না ঘেঁটে) — প্রথমে n ঘর
ডানদিকে শিফট করে সেই বিটকে সর্ব-ডানে আনা হয়, তারপর AND 1 দিয়ে বাকি সব উঁচু বিট বাদ দেওয়া হয়:
$$ \text{bit\_value} = (\text{reg} \gg n) \;\land\; 1 $$
৩ · একাধিক বিট নিয়ে বিট-ফিল্ড
একক বিট যথেষ্ট নয় যখন কোনো সেটিং-এর একাধিক সম্ভাব্য মান থাকে — যেমন একটি ২-বিট MODE ফিল্ড
চারটি মান ধারণ করতে পারে (0, 1, 2, 3)। এক্ষেত্রে একটি মাস্ক (ফিল্ডের প্রস্থ যতগুলো ১-বিট,
ততগুলো নিয়ে গঠিত, যেমন ২-বিট ফিল্ডের জন্য 0b11) এবং একটি শিফট (ফিল্ডটি
রেজিস্টারের কোন বিট-পজিশন থেকে শুরু, উদাহরণে bit0 থেকে) দুটোই লাগে — লেখার সময় প্রথমে সেই ফিল্ডের পুরনো মান
মুছে (mask দিয়ে AND-NOT) তারপর নতুন মান শিফট করে বসাতে হয়, যাতে ফিল্ডের বাইরের অন্য কোনো বিট স্পর্শ না হয়।
৪ · সম্পূর্ণ সিমুলেশন — set, clear, toggle, read ও একটি বিট-ফিল্ড
নিচের কোড সেলটি উপরের চারটি একক-বিট অপারেশন এবং একটি ২-বিট MODE ফিল্ড read/write — সবকিছু একই ৮-বিট
রেজিস্টারের উপর, ধাপে ধাপে format(reg, '08b') দিয়ে ট্রেস করে দেখায়।
def show(label, r):
print(f"{label:42s} -> {format(r, '08b')}")
# --- একটি ৮-বিট কন্ট্রোল রেজিস্টার, শুরুতে সব বিট 0 ---
reg = 0b00000000
show("প্রাথমিক অবস্থা", reg)
BIT_DIR = 7 # bit7 -- একক ফ্ল্যাগ: পিন ডিরেকশন
BIT_ENABLE = 3 # bit3 -- একক ফ্ল্যাগ: পেরিফেরাল এনাবল
# --- SET বিট ---
reg = reg | (1 << BIT_ENABLE)
show(f"bit{BIT_ENABLE} SET (ENABLE ON)", reg)
reg = reg | (1 << BIT_DIR)
show(f"bit{BIT_DIR} SET (DIR = output)", reg)
# --- CLEAR বিট -- শুধু ENABLE বিট মুছে ফেলা, DIR অক্ষত থাকা উচিত ---
reg = reg & ~(1 << BIT_ENABLE)
show(f"bit{BIT_ENABLE} CLEAR (ENABLE OFF)", reg)
# --- TOGGLE বিট -- দুইবার টগল করলে মূল মানে ফিরে আসা উচিত ---
reg = reg ^ (1 << BIT_DIR)
show(f"bit{BIT_DIR} TOGGLE #1 (DIR উল্টে গেল)", reg)
reg = reg ^ (1 << BIT_DIR)
show(f"bit{BIT_DIR} TOGGLE #2 (DIR আবার আগের মানে)", reg)
# --- READ বিট ---
dir_value = (reg >> BIT_DIR) & 1
print(f"bit{BIT_DIR} (DIR) পড়া হলো: {dir_value}")
print()
print("--- বিট-ফিল্ড: bit1-bit0 মিলে ২-বিটের MODE ফিল্ড ---")
MODE_SHIFT = 0
MODE_MASK = 0b11 # ২-বিট ফিল্ডের জন্য মাস্ক (0,1,2,3 ধারণ করতে পারে)
def set_mode_field(r, mode_value):
r = r & ~(MODE_MASK << MODE_SHIFT) # ধাপ ১: পুরনো ফিল্ড-মান মুছে ফেলা
r = r | ((mode_value & MODE_MASK) << MODE_SHIFT) # ধাপ ২: নতুন মান শিফট করে বসানো
return r
def read_mode_field(r):
return (r >> MODE_SHIFT) & MODE_MASK
reg = set_mode_field(reg, 0b10) # MODE = 2
show("MODE ফিল্ড = 2 (0b10) সেট করার পর", reg)
print(f"MODE ফিল্ড পড়া হলো: {read_mode_field(reg)} ({format(read_mode_field(reg), '02b')})")
reg = set_mode_field(reg, 0b01) # MODE = 1 -- DIR (bit7) স্পর্শ না হওয়া উচিত
show("MODE ফিল্ড = 1 (0b01)-এ বদলানোর পর", reg)
print(f"MODE ফিল্ড পড়া হলো: {read_mode_field(reg)} ({format(read_mode_field(reg), '02b')})")
print(f"bit{BIT_DIR} (DIR) এখনও: {(reg >> BIT_DIR) & 1} -- বিট-ফিল্ড আপডেটে DIR অক্ষত ছিল কিনা যাচাই")
bit7
(DIR) ঠিক ১ রয়ে গেল, কারণ প্রতিটি বিট-ফিল্ড অপারেশনের মাস্ক (MODE_MASK <<
MODE_SHIFT) শুধু bit1-bit0 স্পর্শ করে, bit7 নয়। এটাই বিটওয়াইজ অপারেশনের মূল সুবিধা — একই রেজিস্টারে
পাশাপাশি বসে থাকা বিভিন্ন কন্ট্রোল একে অপরকে না ঘেঁটে স্বাধীনভাবে বদলানো যায়।
| দিয়ে set, & ~ দিয়ে clear, ^ দিয়ে toggle, >> &
1 দিয়ে read — এই চারটি প্যাটার্ন এমবেডেড C-তে রেজিস্টার নিয়ন্ত্রণের ভিত্তি। একাধিক বিট নিয়ে গঠিত
ফিল্ডের জন্য একই নীতি প্রসারিত হয় — একটি মাস্ক দিয়ে পুরনো মান মুছে, তারপর শিফট করা নতুন মান বসানো। পরের
পাঠে (L11) দেখা যাবে কীভাবে এই একই রেজিস্টার আসলে একটি নির্দিষ্ট মেমরি ঠিকানায় বসানো থাকে এবং C পয়েন্টার
দিয়ে সরাসরি অ্যাক্সেস করা হয়।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।
প্র ০১
Clear bit অপারেশনে reg & (1 << n) (টিল্ড ছাড়া) লিখলে কী ভুল হবে?
টিল্ড (~) ছাড়া 1 << n মাস্কে শুধু n-তম বিট ১, বাকি সব ০।
তাই reg & (1 << n) আসলে বাকি সব বিট মুছে ফেলে এবং শুধু
n-তম বিটের (পুরনো) মান রেখে দেয় — এটি "clear" নয়, বরং "শুধু সেই বিট পড়ার মতো একটি ভুল
এক্সপ্রেশন যেটি পুরো রেজিস্টার ধ্বংস করে দেয়"। সঠিক clear-এর জন্য মাস্কটি উল্টো হওয়া দরকার —
~(1 << n) — যেখানে শুধু n-তম বিট ০, বাকি সব ১, যাতে AND করলে শুধু সেই
একটি বিট মুছে যায়।
প্র ০২
কোড সেলে MODE_MASK = 0b11 ও MODE_SHIFT = 0 — যদি MODE ফিল্ডটি bit3-bit2
(bit0 নয়) থেকে শুরু হতো, এই দুটো ভ্যালু কী হতো?
মাস্কের প্রস্থ ফিল্ডের বিট-সংখ্যার উপর নির্ভর করে, অবস্থানের উপর নয় — তাই ২-বিট ফিল্ডের জন্য
MODE_MASK এখনও 0b11-ই থাকবে। কিন্তু MODE_SHIFT বদলে
2 হবে (কারণ ফিল্ডটি bit2 থেকে শুরু), অর্থাৎ read হতো
(reg >> 2) & 0b11 দিয়ে, আর write-এর মাস্কও 0b11 << 2 (=
0b1100) হতো, যাতে bit3-bit2 নিয়ে কাজ হয় আর bit1-bit0 অক্ষত থাকে।
প্র ০৩ ডায়াগ্রামে bit6, bit5, bit4, bit2-কে "—" দিয়ে দেখানো হয়েছে। বাস্তব চিপে এগুলোর কী হতে পারে?
বাস্তব ডেটাশিটে প্রতিটি বিটের একটি নির্দিষ্ট অর্থ থাকে — কিন্তু কিছু বিট "reserved" (ভবিষ্যতের জন্য সংরক্ষিত, লেখার সময় ০ রাখতে হয়) বা নির্দিষ্ট চিপ ভ্যারিয়েন্টে ব্যবহৃত হয় না বলে চিহ্নিত থাকতে পারে। এই লেসনের সিমুলেশনে সরলতার জন্য শুধু তিনটি অর্থপূর্ণ অংশ (DIR, ENABLE, MODE) বেছে নেওয়া হয়েছে — বাস্তব মাইক্রোকন্ট্রোলার রেজিস্টারে সাধারণত ৮ বা ৩২টি বিটের প্রায় প্রতিটিরই একটি নথিভুক্ত অর্থ থাকে।
অনুশীলন
-
চিন্তা করুন: কোড সেলে শেষ পর্যন্ত
reg-এর মান কত (বাইনারিতে) থাকবে বলে আপনার ধারণা, এবং তা দশমিকে কত?শেষে bit7 (DIR) = 1 এবং MODE ফিল্ড (bit1-bit0) = 1 (0b01), বাকি সব বিট 0 — অর্থাৎ
10000001, যা দশমিকে $128 + 1 = 129$। -
পরীক্ষা করুন: কোড সেলে একটি নতুন লাইন যোগ করুন যা
BIT_ENABLEবিট আবার SET করে (reg = reg | (1 << BIT_ENABLE)), তারপরshow()কল করে দেখুন এবং চিন্তা করুন MODE ফিল্ড ও DIR বিট এই অপারেশনে প্রভাবিত হয় কিনা।এই SET অপারেশন শুধু bit3 (ENABLE)-কে ১ করে — মাস্ক
1 << 3-এ শুধু bit3 ১, বাকি সব ০, আর OR অপারেশনে অন্য বিটের মান বদলায় না (x OR 0 = x)। তাই চূড়ান্ত মান10001001(দশমিকে ১৩৭) হবে — DIR (bit7=1) ও MODE ফিল্ড (bit1-bit0=01) দুটোই অক্ষত থাকবে, শুধু bit3 নতুন করে ১ হবে।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৭টি পাঠ মাইক্রোপ্রসেসর আর্কিটেকচার, এমবেডেড C, GPIO, টাইমার/PWM/ADC, সিরিয়াল প্রোটোকল, RTOS, সেন্সর/অ্যাকচুয়েটর, IoT আর্কিটেকচার, ওয়্যারলেস প্রোটোকল, MQTT/CoAP ও IoT সিকিউরিটি — বাকি পাঠগুলো শীঘ্রই যুক্ত হবে।
- Computer Architecture & Digital Logic কোর্স সহোদর কোর্স রেজিস্টার ও ALU-এর সাধারণ ভিত্তি সেই কোর্সেই তৈরি হয়েছে — এই কোর্স এমবেডেড রেজিস্টার-কন্ট্রোলের প্র্যাকটিক্যাল দিকে গভীরে যায়।
- সব Courses দেখুন ABCL TECH C, C++, Python, Java, JavaScript, DSA, DBMS, Discrete Mathematics, System Design, Cybersecurity, Cloud Computing & DevOps, Computer Networks, Operating Systems, Computer Architecture, Design and Analysis of Algorithms ও আরও অনেক কোর্স — সব এক জায়গায়।