পাঠ ১০ · ৫৭-এর মধ্যে · মডিউল ৩
Home / Courses / Microprocessors, Embedded Systems & IoT / বিট ম্যানিপুলেশন

রেজিস্টার কন্ট্রোলের জন্য বিট ম্যানিপুলেশন

Bit manipulation for register control
৯ মিনিট পড়া মধ্যম · Intermediate Python সিমুলেশনসহ সম্পূর্ণ বাংলায়

এই পাঠে যা শিখবেন

  • কেন এমবেডেড রেজিস্টার নিয়ন্ত্রণে সবসময় বিট-লেভেল অপারেশন ব্যবহার করা হয়, পুরো ওভাররাইট নয়
  • 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-তে প্রায় সবসময় বিটওয়াইজ অপারেটর (|, &, ^, ~, <<, >>) দিয়ে শুধু নির্দিষ্ট বিট বদলানো হয়, বাকিগুলো অক্ষত রেখে।

৮-বিট কন্ট্রোল রেজিস্টার (bit7 → bit0, MSB → LSB) bit7 DIR bit6 — bit5 — bit4 — bit3 ENABLE bit2 — bit1 MODE[1] bit0 MODE[0] bit7=DIR ও bit3=ENABLE স্বতন্ত্র সিঙ্গল-বিট ফ্ল্যাগ · bit1-bit0 মিলে ২-বিটের MODE বিট-ফিল্ড (সবুজ ড্যাশ)
এই একই রেজিস্টারে তিন ধরনের নিয়ন্ত্রণ পাশাপাশি বসে থাকে — তাই একটি বদলাতে গিয়ে বাকিগুলো স্পর্শ করা যাবে না।

২ · চারটি মৌলিক বিট অপারেশন

ধরা যাক 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') দিয়ে ট্রেস করে দেখায়।

Python
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 অক্ষত ছিল কিনা যাচাই")

    
লক্ষ্য করুন শেষ লাইনে — MODE ফিল্ড ৩ বার বদলানো হলো (0 → 2 → 1), অথচ পুরো সময় ধরে bit7 (DIR) ঠিক ১ রয়ে গেল, কারণ প্রতিটি বিট-ফিল্ড অপারেশনের মাস্ক (MODE_MASK << MODE_SHIFT) শুধু bit1-bit0 স্পর্শ করে, bit7 নয়। এটাই বিটওয়াইজ অপারেশনের মূল সুবিধা — একই রেজিস্টারে পাশাপাশি বসে থাকা বিভিন্ন কন্ট্রোল একে অপরকে না ঘেঁটে স্বাধীনভাবে বদলানো যায়।
মূল কথা · Key takeaway

| দিয়ে 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) বেছে নেওয়া হয়েছে — বাস্তব মাইক্রোকন্ট্রোলার রেজিস্টারে সাধারণত ৮ বা ৩২টি বিটের প্রায় প্রতিটিরই একটি নথিভুক্ত অর্থ থাকে।

অনুশীলন

  1. চিন্তা করুন: কোড সেলে শেষ পর্যন্ত reg-এর মান কত (বাইনারিতে) থাকবে বলে আপনার ধারণা, এবং তা দশমিকে কত?

    শেষে bit7 (DIR) = 1 এবং MODE ফিল্ড (bit1-bit0) = 1 (0b01), বাকি সব বিট 0 — অর্থাৎ 10000001, যা দশমিকে $128 + 1 = 129$।

  2. পরীক্ষা করুন: কোড সেলে একটি নতুন লাইন যোগ করুন যা 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 ও আরও অনেক কোর্স — সব এক জায়গায়।
আগের পাঠ
এমবেডেড C ফান্ডামেন্টাল ও volatile