এই পর্বে যা শিখবেন
- State, input, output আর transition দিয়ে একটি বাস্তব সমস্যাকে state diagram আর state table-এ রূপ দেওয়া
- Moore আর Mealy machine-এর পার্থক্য — output কখন আসে, কতগুলো state লাগে, আর কেন
- “1011” sequence detector (overlapping ও non-overlapping, দুই মডেলেই), serial parity আর ৩ দিয়ে বিভাজ্যতা যাচাইয়ের FSM
- Partition আর implication table দিয়ে state কমানো, binary/Gray/one-hot encoding-এর দর-কষাকষি, আর D ও JK flip-flop-এর সমীকরণ
- অব্যবহৃত state, synchronous বনাম asynchronous reset, Verilog-এ synthesizable FSM লেখা আর coverage দিয়ে পরীক্ষা
১ · State machine কী — যে circuit অতীত মনে রাখে
মডিউল ২-এর circuit-গুলোর output শুধু এই মুহূর্তের input দেখত — একে বলে combinational circuit. কিন্তু বহু কাজে আগে কী ঘটেছে তা মনে রাখতে হয়। মোবাইল ব্যাংকিং অ্যাপে ভুল PIN দিলে অ্যাপ বলে “আর ২ বার সুযোগ আছে” — অর্থাৎ সে গুনে রেখেছে আগে কতবার ভুল হয়েছে। এই গোনা একটি স্মৃতি। স্মৃতির প্রতিটি সম্ভাব্য অবস্থাকে বলে state, আর যে যন্ত্র নির্দিষ্টসংখ্যক state-এর একটিতে থাকে আর input অনুযায়ী state বদলায়, তাকে বলে finite state machine (FSM).
প্রতিটি FSM চারটি জিনিস দিয়ে পুরো বর্ণনা করা যায়:
- State-এর তালিকা — সসীম (finite), তাই নাম “finite”. যেমন: ভুল ০ বার, ১ বার, ২ বার, খোলা, বন্ধ (locked).
- Input — বাইরে থেকে যা আসে: সঠিক PIN, ভুল PIN, logout.
- Output — যন্ত্র যা জানায় বা করে: “২ বার সুযোগ আছে”, “স্বাগতম”, “অ্যাকাউন্ট বন্ধ”।
- Transition-এর নিয়ম — কোন state-এ কোন input এলে কোন state-এ যাবে। একটি transition মানে এক state থেকে আরেক state-এ যাওয়া।
একটি অফিসভবনের লিফটের কথা ভাবুন। লিফটের “মন” আসলে কয়েকটি অবস্থা: থেমে আছে দরজা খোলা, থেমে আছে দরজা বন্ধ, ওপরে যাচ্ছে, নিচে যাচ্ছে। Input হলো বোতাম চাপা, তলার sensor, দরজার sensor. লিফট কখনো “ওপরে যাচ্ছে” অবস্থা থেকে সোজা “দরজা খোলা”-য় যায় না — আগে থামতে হয়। এই “কোন অবস্থা থেকে কোন অবস্থায় যাওয়া চলে” — নিয়মের তালিকাটিই FSM. নিয়মের বাইরে কিছু ঘটে না, তাই লিফট নিরাপদ।
সবচেয়ে ছোট উদাহরণ মেট্রোরেলের প্রবেশ-গেট বা টোকেন গেট (turnstile). দুটি state: বন্ধ আর খোলা. টোকেন বা কার্ড ছোঁয়ালে বন্ধ থেকে খোলা; কেউ ঢুকে গেলে (ধাক্কা) খোলা থেকে আবার বন্ধ। টোকেন ছাড়া ধাক্কা দিলে বন্ধই থাকে। এই তথ্য ছবিতে আঁকলে হয় state diagram — প্রতিটি state একটি বৃত্ত, প্রতিটি transition একটি তীর:
একই তথ্য টেবিলেও লেখা যায় — একে বলে state table. ছবি মানুষের বোঝার জন্য, টেবিল হিসাবের জন্য:
| বর্তমান state | input = টোকেন | input = ধাক্কা | output (গেটের তালা) |
|---|---|---|---|
| বন্ধ | খোলা | বন্ধ | তালা লাগানো |
| খোলা | খোলা | বন্ধ | তালা খোলা |
PIN-এর উদাহরণে state পাঁচটি: WRONG0, WRONG1, WRONG2 (কতবার ভুল হয়েছে), UNLOCKED আর LOCKED. WRONG2-তে আরেকবার ভুল এলে LOCKED, আর LOCKED থেকে সঠিক PIN দিলেও আর খোলে না — শুধু গ্রাহকসেবা বা নির্দিষ্ট নিয়মে reset হলে ফেরে। এই নকশাটি অংশ ৯-এ একটি C প্রোগ্রামে চালিয়ে দেখবেন। খেয়াল করুন, FSM-এর state-এ পুরো ইতিহাস থাকে না — শুধু ভবিষ্যতের সিদ্ধান্তের জন্য যতটুকু দরকার ততটুকু। কোন ভুল PIN দেওয়া হয়েছিল তা মনে রাখার দরকার নেই, শুধু কতবার।
State হলো অতীতের সারাংশ: অতীতের দুটি ভিন্ন ইতিহাস যদি ভবিষ্যতের সব input-এ একই আচরণ ঘটায়, তাদের একই state-এ রাখা যায়। এই ভাবনাই পরে state কমানোর (অংশ ৫) মূল ভিত্তি।
২ · Hardware-এ FSM-এর গঠন — register আর দুই টুকরো logic
Digital circuit-এ FSM প্রায় সবসময় synchronous: state বদলায় শুধু clock-এর সক্রিয় ধারে। গঠন তিন টুকরো:
- State register: কয়েকটি D flip-flop, যা বর্তমান state-এর বিট-নকশা ধরে রাখে। n বিটে সর্বোচ্চ ২nটি state. Flip-flop-এর ভেতরের গঠন পর্ব ১৫-এ (Latch আর flip-flop), আর register-এর বিস্তারিত পর্ব ১৬-এ।
- Next-state logic: বর্তমান state Q আর input x থেকে পরের state হিসাব করে — সাধারণ combinational circuit. এর output যায় flip-flop-এর D-তে; পরের clock ধারে সেটিই নতুন state.
- Output logic: output z হিসাব করে। এখানেই দুই মডেলের পার্থক্য।
গাণিতিকভাবে: state-এর সেট S, input-এর সেট I, output-এর সেট O, শুরুর state s0, আর transition function δ : S × I → S. Output function দুই রকম:
Moore machine
λ : S → O. Output শুধু বর্তমান state-এর। State diagram-এ output লেখা হয় বৃত্তের ভেতরে (যেমন S4/1). নাম Edward F. Moore-এর নামে — একে বলে Moore machine.
z = λ(Q)Mealy machine
λ : S × I → O. Output বর্তমান state আর বর্তমান input দুটির। Output লেখা হয় তীরের গায়ে, input/output আকারে (যেমন 1/1). নাম George H. Mealy-র নামে — Mealy machine.
z = λ(Q, x)রেস্তোরাঁর দুই রকম ওয়েটারের কথা ভাবুন। একজন (Moore) টেবিলে এসে প্রথমে খাতায় অর্ডার লেখেন, রান্নাঘরে দেন, পরের বার এসে খাবার দেন — সাড়া দেন একটু পরে, কিন্তু সবসময় খাতা দেখে, তাই ভুল কম। আরেকজন (Mealy) আপনার কথা শোনামাত্র তখনই কিছু একটা হাতে তুলে দেন (যেমন পানির গ্লাস) — সাড়া তাৎক্ষণিক, কিন্তু আপনি কথার মাঝে মত বদলালে তাঁর হাতের জিনিসও বদলে যায়।
৩ · নকশার ধাপ ১–২ · কথা থেকে state diagram — “1011” detector
FSM নকশার পূর্ণ পদ্ধতি সাত ধাপের — এই পর্বের বাকিটা এই ক্রমেই চলবে:
- কথার সমস্যা → state diagram (প্রতিটি state-এর অর্থ এক লাইনে লিখে রাখা)
- State table
- State minimisation — সমতুল্য state একত্র করা (অংশ ৫)
- State assignment — প্রতিটি state-কে বিট দেওয়া (অংশ ৬)
- Next-state আর output সমীকরণ — K-map দিয়ে (অংশ ৬)
- Circuit — flip-flop আর gate জোড়া
- Simulation দিয়ে যাচাই
উদাহরণ হিসেবে নিন পরীক্ষার সবচেয়ে প্রচলিত প্রশ্নটি: একটি serial তারে প্রতি clock-এ একটি বিট x আসে। যখনই শেষ চারটি বিট 1011 হয়, output z = 1. এই ধরনের নকশাকে বলে sequence detector. প্রথমে একটি প্রশ্নের উত্তর ঠিক করতে হয়: একটি মিলের শেষ অংশ কি পরের মিলের শুরু হতে পারবে? যেমন 1011011-এ দুটি মিল, মাঝের 1টি দুজনেরই। এটি গুনলে overlapping, না গুনলে non-overlapping. প্রশ্নে স্পষ্ট না থাকলে নিজের ধারণাটি লিখে দেওয়া ভালো অভ্যাস।
পদ্ধতি: প্রতিটি state-এর অর্থ হবে “লক্ষ্যের শুরুর কতটুকু এই মুহূর্তে মিলে আছে”। তাই A = কিছুই মেলেনি, B = 1, C = 10, D = 101. নতুন বিট এলে প্রশ্ন একটাই: এখন পর্যন্ত দেখা লেখার শেষ অংশের সবচেয়ে লম্বা কোন টুকরো 1011-এর শুরুর সাথে মেলে? নিচের stepper-এ Mealy নকশাটি state ধরে ধরে বানানো হলো:
| A (কিছু মেলেনি) — x = 0 | |
| A — x = 1 | |
| B (“1”) — x = 0 | |
| B — x = 1 | |
| C (“10”) — x = 0 | |
| C — x = 1 | |
| D (“101”) — x = 0 | |
| D — x = 1 |
- শুরুর state A. কিছুই মেলেনি। 0 এলে লাভ নেই, কারণ লক্ষ্য শুরু হয় 1 দিয়ে — A-তেই থাকি। 1 এলে লক্ষ্যের প্রথম বিট মিলল — B-তে যাই। Output এখনো 0.
- B = “1” মিলেছে। 0 এলে “10” — দুই বিট মিলল, C. 1 এলে দেখা লেখা “11”; লক্ষ্যের শুরু “10”, তাই “11” মেলে না, কিন্তু শেষের “1”টি নতুন শুরু হতে পারে — B-তেই থাকি। নতুনদের একটি প্রচলিত ভুল এখানে A-তে ফিরে যাওয়া।
- C = “10”. 1 এলে “101” — D. 0 এলে “100”: এর শেষ অংশ “00” বা “0” — কোনোটিই 1 দিয়ে শুরু নয়, তাই একেবারে শুরুতে, A.
- D-তে 1 = লক্ষ্য পূর্ণ। “1011” এসেছে, তাই এই তীরেই output z = 1 (Mealy — output তীরের গায়ে)। পরের state কী? “1011”-এর শেষ অংশগুলো: “011”, “11”, “1” — এর মধ্যে শুধু “1” লক্ষ্যের শুরুর সাথে মেলে। তাই overlapping নিয়মে B.
- D-তে 0. দেখা লেখা “1010”. শেষ অংশ “010” মেলে না, কিন্তু “10” মেলে — তাই C, A নয়। এই ঘরটিও পরীক্ষায় প্রায়ই ভুল হয়।
- সম্পূর্ণ। ৪টি state × ২টি input = ৮টি ঘর, প্রতিটি ঘরে পরের state আর output. Non-overlapping চাইলে শুধু D-তে 1-এর ঘরটি বদলায়: মিলের পর সব ভুলে A-তে ফেরা, তাই D --1/1--> A. বাকি সাতটি ঘর একই।
এই “শেষ অংশের সবচেয়ে লম্বা টুকরো যা লক্ষ্যের শুরুর সাথে মেলে” — নিয়মটি string matching-এর KMP অ্যালগরিদমের failure function-এর সাথে হুবহু এক; আগ্রহী হলে DSA কোর্সের string matching পর্ব দেখতে পারেন। নিচে একই Mealy নকশার ছবি:
একই detector, Moore মডেলে
Moore-এ output state-এর গায়ে থাকে, তাই “1011 পূর্ণ হয়েছে” — এই খবরের জন্য একটি আলাদা state লাগে। S0 = কিছু মেলেনি, S1 = 1, S2 = 10, S3 = 101, আর নতুন S4 = 1011 এইমাত্র এসেছে (output 1). S4 থেকে পরের transition-গুলো ঠিক Mealy-র B-এর মতো, কারণ overlapping নিয়মে “1011”-এর শেষ “1” নতুন শুরু:
| State (অর্থ) | x = 0 | x = 1 | z |
|---|---|---|---|
| S0 (কিছু না) | S0 | S1 | 0 |
| S1 (“1”) | S2 | S1 | 0 |
| S2 (“10”) | S0 | S3 | 0 |
| S3 (“101”) | S2 | S4 | 0 |
| S4 (“1011” পূর্ণ) | S2 | S1 | 1 |
S4-এ 0 এলে “10110”-এর শেষ “10” মেলে, তাই S2; 1 এলে “10111”-এর শেষ “1”, তাই S1. Non-overlapping Moore-এ S4-এর সারি হবে S0 আর S1 (মিলের পর নতুন করে শুরু; তবু নতুন 1টি প্রথম বিট হিসেবে গোনা যায়)।
৪ · Moore বনাম Mealy — output কখন আসে, state কত লাগে
দুই নকশাকে একই input দিয়ে চালালে আসল পার্থক্য চোখে পড়ে। আগে Moore detector-কে 1101011 দিয়ে cycle ধরে ধরে দেখুন। প্রতি cycle-এ output হলো বর্তমান state-এর output; clock ধারে state বদলায়:
| cycle | |
| এখন পর্যন্ত আসা বিট | |
| এই cycle-এর input x | |
| Moore বর্তমান state | |
| Moore z (state থেকে) | |
| ধারের পর Moore state | |
| Mealy state / z |
- Cycle ০. Reset-এর পর S0, তাই z = 0. Input x = 1 আসছে; clock ধারে S1-এ যাবে। Mealy-ও A-তে, z = 0.
- Cycle ১ — S1. আবার 1. “11”-এর শেষ “1” নতুন শুরু, তাই ধারের পর S1-এই থাকে। এই ধাপে বহু হাতে-করা উত্তর ভুল করে S0-তে ফেরে।
- Cycle ২ — S1, x = 0. “110”-এর শেষ “10” মেলে, তাই পরের state S2.
- Cycle ৩ — S2, x = 1. “1101”-এর শেষ “101” — S3-এর দিকে। এখনো z = 0.
- Cycle ৪ — S3, x = 0. লক্ষ্য ছিল 1, এল 0. সব হারায়নি: “11010”-এর শেষ “10” মেলে, তাই S2 (S0 নয়)।
- Cycle ৫ — S2, x = 1. আবার “101” — S3. দেখুন, ভুল বিটের পরেও যন্ত্র দুই বিট এগিয়ে থেকে আবার চেষ্টা করছে।
- Cycle ৬ — S3, x = 1. “1011” পূর্ণ হলো এই cycle-এর input-এ। Moore-এর z এখনো 0, কারণ সে শুধু state দেখে, আর state এখনো S3. কিন্তু Mealy (D-তে x = 1) এই cycle-এই z = 1 দিচ্ছে।
- Cycle ৭ — S4, z = 1. ধারের পর Moore S4-এ, আর এখন z = 1 — Mealy-র চেয়ে ঠিক এক cycle পরে, আর পুরো একটি cycle জুড়ে স্থির। Input যা-ই আসুক, এই cycle-এ Moore-এর output বদলাবে না।
এবার একটি ছোট simulator দিয়ে তিনটি নকশা — Moore, Mealy আর non-overlapping Mealy — একই input 10110110-এ পাশাপাশি চালানো যাক। Simulator-টি সাধারণ: যেকোনো state table আর বিট-স্ট্রিং দিলে প্রতিটি cycle ছাপে:
// Generic synchronous FSM simulator: give it a state table, it prints every clock cycle.
// Moore: out[state]. Mealy: out[state][x]. One input bit x is sampled per clock edge.
const moore = { kind: "Moore", start: "S0",
next: { S0: ["S0", "S1"], S1: ["S2", "S1"], S2: ["S0", "S3"], S3: ["S2", "S4"], S4: ["S2", "S1"] },
out: { S0: 0, S1: 0, S2: 0, S3: 0, S4: 1 } }; // only S4 ("1011 seen") says 1
const mealy = { kind: "Mealy", start: "A",
next: { A: ["A", "B"], B: ["C", "B"], C: ["A", "D"], D: ["C", "B"] },
out: { A: [0, 0], B: [0, 0], C: [0, 0], D: [0, 1] } }; // output on the D --1--> B arc
const noOv = { ...mealy, kind: "Mealy-nonoverlap",
next: { ...mealy.next, D: ["C", "A"] } }; // after a hit, start again from A
function step(m, s, x) { // one clock cycle
const z = m.kind === "Moore" ? m.out[s] : m.out[s][x]; // output during this cycle
return { z, next: m.next[s][x] }; // state after the clock edge
}
function simulate(machines, bits) {
const st = machines.map(m => m.start), zs = machines.map(() => "");
console.log(("cyc x | " + machines.map(m => m.kind.padEnd(17)).join("| ")).trimEnd());
[...bits].forEach((ch, t) => {
const x = +ch, cells = machines.map((m, i) => {
const r = step(m, st[i], x), cell = `${st[i]}->${r.next} z=${r.z}`;
st[i] = r.next; zs[i] += r.z; return cell.padEnd(17);
});
console.log((` ${t} ${x} | ` + cells.join("| ")).trimEnd());
});
machines.forEach((m, i) => console.log(`${m.kind.padEnd(16)} z = ${zs[i]}`));
}
simulate([moore, mealy, noOv], "10110110");আউটপুট (নির্ধারিত — প্রতিবার একই):
cyc x | Moore | Mealy | Mealy-nonoverlap
0 1 | S0->S1 z=0 | A->B z=0 | A->B z=0
1 0 | S1->S2 z=0 | B->C z=0 | B->C z=0
2 1 | S2->S3 z=0 | C->D z=0 | C->D z=0
3 1 | S3->S4 z=0 | D->B z=1 | D->A z=1
4 0 | S4->S2 z=1 | B->C z=0 | A->A z=0
5 1 | S2->S3 z=0 | C->D z=0 | A->B z=0
6 1 | S3->S4 z=0 | D->B z=1 | B->B z=0
7 0 | S4->S2 z=1 | B->C z=0 | B->C z=0
Moore z = 00001001
Mealy z = 00010010
Mealy-nonoverlap z = 00010000
তিনটি জিনিস লক্ষ করুন। এক: cycle ৩-এ চতুর্থ বিট (1) এসে “1011” পূর্ণ করে। Mealy সেই cycle-এই z = 1 দেয় (D->B z=1), কিন্তু Moore দেয় cycle ৪-এ (S4->S2 z=1) — এক cycle পরে। দুই: cycle ৬-এ আবার মিল — overlapping, কারণ cycle ৩-এর 1টি দ্বিতীয় “1011”-এরও প্রথম বিট। Mealy-র z = 00010010-এ দুটি 1, Moore-এর 00001001-এ একই দুটি 1, শুধু এক ঘর ডানে সরানো। তিন: non-overlapping নকশা মিলের পর A-তে ফিরে নতুন করে শোনে (D->A), তাই দ্বিতীয় মিলটি গোনে না: z = 00010000. নিজে চালিয়ে দেখুন: শেষ লাইনে input বদলে "1011011011" দিন, বা noOv-এর D সারিতে অন্য কিছু বসিয়ে দেখুন কোন মিল হারায়।
কেন Moore-এ state বেশি লাগে — একটি ছোট প্রমাণ
দাবি: একই input-output আচরণের জন্য (Moore-এর এক cycle দেরি মেনে নিয়ে) সবচেয়ে ছোট Mealy machine-এর state-সংখ্যা সবচেয়ে ছোট Moore machine-এর চেয়ে বেশি নয়।
- Moore → Mealy, state একই: যেকোনো Moore machine নিন। প্রতিটি তীর s --x--> t-এর গায়ে output হিসেবে λ(t) লিখুন — অর্থাৎ গন্তব্য state-এর output. ফল একটি Mealy machine, state-সংখ্যা একই, আর Moore যে output পরের cycle-এ দিত, এটি সেটিই এই cycle-এ দেয়। তাই Mealy-র ন্যূনতম state-সংখ্যা ≤ Moore-এর।
- Mealy → Moore, state বাড়তে পারে: একটি Mealy state-এ যদি ভিন্ন output-ওয়ালা তীর এসে পৌঁছায় (যেমন B-তে A --1/0--> B আর D --1/1--> B), Moore-এ সেই state-কে output অনুযায়ী ভাগ করতে হয় — B0 আর B1. সবচেয়ে খারাপ ক্ষেত্রে state-সংখ্যা |S| × |O| পর্যন্ত হয়। আমাদের detector-এ শুধু B ভাগ হয়েছে: B1 = S4, তাই ৪ থেকে ৫।
| দিক | Moore | Mealy |
|---|---|---|
| Output নির্ভর করে | শুধু state | state + input |
| সাড়া | এক cycle পরে | একই cycle-এ |
| “1011” detector-এ state / flip-flop (binary) | ৫ / ৩ | ৪ / ২ |
| Output-এর স্থিরতা | পুরো cycle স্থির; input-এর glitch output-এ যায় না | input cycle-এর মাঝে বদলালে output-ও বদলায় |
| Timing | Output-এর পথ ছোট: register → output logic | Input → output সরাসরি combinational পথ; কয়েকটি Mealy পরপর জুড়লে পথ লম্বা হয়, এমনকি combinational loop-এর ঝুঁকি |
বাস্তবে নকশাকারীরা প্রায়ই মাঝামাঝি পথ নেন: Mealy-তে হিসাব করে output-টিকে একটি flip-flop-এ ধরে রাখা (registered output). তখন আচরণ Moore-এর মতো এক cycle দেরিতে, কিন্তু state কম। Timing-এর এই হিসাব — setup, hold আর critical path — বিস্তারিত পর্ব ১৮-এ (Timing আর clock).
৫ · ধাপ ৩ · State minimisation — সমতুল্য state একত্র করা
প্রথমবার state diagram আঁকলে প্রায়ই অপ্রয়োজনীয় state থেকে যায় — বিশেষ করে বড় সমস্যায়, বা কেউ “প্রতিটি ঘটনার জন্য একটি নতুন state” নিয়ম মেনে আঁকলে। কম state মানে কম flip-flop (বা একই flip-flop-এ বেশি don't care) আর প্রায়ই ছোট logic. তাই ধাপ ৩: state minimisation.
সংজ্ঞা: দুটি state p আর q equivalent (p ≡ q), যদি যেকোনো input-ধারা p থেকে চালালে যে output-ধারা আসে, q থেকে চালালেও ঠিক সেটিই আসে। বাইরে থেকে এদের আলাদা করার কোনো পরীক্ষা নেই, তাই একটিকে মুছে তার দিকের সব তীর অন্যটিতে ঘুরিয়ে দেওয়া যায়। সরাসরি “সব input-ধারা” পরীক্ষা অসম্ভব (অসীম), তাই ধাপে ধাপে ভাবা হয়:
- p আর q k-equivalent, যদি ১ থেকে k দৈর্ঘ্যের সব input-ধারায় output এক। ১-equivalent মানে প্রতিটি একক input-এ output এক — এটিই শুরুর ভাগ, যাকে এই পর্বে P0 বলা হয়েছে (কিছু বই একে P1 বলে)। Moore-এ শুরুর ভাগ হয় state-এর নিজের output দিয়ে।
- মূল সূত্র: p আর q (k+1)-equivalent ⇔ এদের output প্রতিটি input-এ এক, আর প্রতিটি input x-এ δ(p, x) আর δ(q, x) k-equivalent.
- প্রতিটি ধাপে দলগুলো শুধু ভাঙতে পারে, জোড়া লাগে না; আর n state-এর বেশি দল হতে পারে না। তাই সর্বোচ্চ n − ১ ধাপে এমন একটি ধাপ আসে যেখানে কিছু ভাঙে না। তখন থেকে আর কখনো ভাঙবে না (পরের ধাপ একই সূত্রে একই দল থেকে হিসাব হয়) — সেই দলগুলোই আসল equivalence-এর দল।
এই পদ্ধতির নাম partition refinement (বইভেদে partition method বা Moore-এর algorithm). একটি ৭-state Mealy machine নিন, যা কেউ বাড়তি state রেখে এঁকেছেন:
| State | x = 0: পরের / z | x = 1: পরের / z |
|---|---|---|
| A (শুরু) | A / 0 | B / 0 |
| B | C / 0 | E / 0 |
| C | G / 0 | D / 0 |
| D | F / 0 | E / 1 |
| E | F / 0 | B / 0 |
| F | A / 0 | D / 0 |
| G | G / 0 | E / 0 |
| দলের ভাগ | |
| A | |
| B | |
| C | |
| D | |
| E | |
| F | |
| G |
- P0 — output দিয়ে প্রথম ভাগ। প্রতিটি state-এর output-সারি (x = 0, x = 1) দেখুন। শুধু D-এর সারি “0 1”, বাকি ছয়টির “0 0”. তাই P0 = {A,B,C,E,F,G} {D}. ভিন্ন দলের দুটি state কখনো equivalent নয় — একটি এক-বিটের input-ই তাদের আলাদা করে।
- স্বাক্ষর হিসাব। বড় দল I-এর প্রতিটি state-এর জন্য লিখুন, x = 0 আর x = 1-এ পরের state কোন দলে। C যায় (G, D) = (I, II), F যায় (A, D) = (I, II); বাকি চারটি (I, I). স্বাক্ষর আলাদা মানে আলাদা ভবিষ্যৎ: C বা F থেকে “1” দিলে D-তে পৌঁছায়, তারপর আরেকটি “1” দিলে z = 1 — অন্যদের থেকে তা হয় না।
- P1 = {A,B,E,G} {C,F} {D}. নতুন দল দিয়ে আবার স্বাক্ষর: B যায় (C, E) = (β, α), E যায় (F, B) = (β, α); কিন্তু A যায় (A, B) = (α, α), G যায় (G, E) = (α, α). তাই α দুই ভাগে ভাঙে। β-র C আর F দুজনেই (α, γ) — অটুট।
- P2 = {A,G} {B,E} {C,F} {D}. আবার পরীক্ষা: A (AG, BE) আর G (AG, BE) মেলে; B আর E দুজনেই (CF, BE); C আর F দুজনেই (AG, D). কোনো দল ভাঙল না, তাই P3 = P2 — থামুন। মোট তিনটি ধাপে স্থির।
- ছোট machine. প্রতিটি দল থেকে একটি নাম রাখুন: G → A, E → B, F → C. নতুন টেবিল: A: A/0, B/0 · B: C/0, B/0 · C: A/0, D/0 · D: C/0, B/1. চিনতে পারছেন? এটি অংশ ৩-এর “1011” overlapping Mealy detector-ই — বাড়তি তিনটি state শুধু নকল ছিল।
একই কাজ implication table দিয়ে
পরীক্ষায় অনেক সময় implication table চাওয়া হয়। প্রতিটি state-জোড়ার একটি ঘর (৭টি state-এ ৭ × ৬ / ২ = ২১টি)। ধাপ: (১) output ভিন্ন হলে ঘরে X. (২) নইলে ঘরে লিখুন, এই জোড়া equivalent হতে হলে কোন কোন জোড়াকে equivalent হতে হবে (পরের state-এর জোড়া)। (৩) বারবার পুরো টেবিল ঘুরে দেখুন: কোনো ঘরের শর্তে X-ওয়ালা জোড়া থাকলে সেই ঘরেও X. আমাদের machine-এ:
| ধাপ | যে জোড়াগুলোয় X পড়ল | কারণ |
|---|---|---|
| শুরু | AD, BD, CD, DE, DF, DG | D-এর output (x = 1-এ 1) বাকিদের থেকে আলাদা |
| পাস ১ | AC, BC, CE, AF, BF, EF, CG, FG | প্রত্যেকের শর্তে একটি D-জোড়া আছে, যেমন AC চায় BD, CG চায় DE |
| পাস ২ | AB, AE, BG, EG | AB চায় AC আর BE — AC এখন X; AE চায় AF — X |
| পাস ৩ | নতুন কিছু নয় — থামুন | বাকি ঘর: AG (চায় BE), BE (চায় CF), CF (চায় AG) |
যে তিনটি ঘর X-মুক্ত রইল — AG, BE, CF — সেগুলোই equivalent জোড়া, partition-এর ফলের সাথে হুবহু এক। লক্ষ করুন, বাকি তিনটি শর্ত একে অন্যের ওপর চক্রাকারে নির্ভর করে (AG চায় BE, BE চায় CF, CF চায় AG) — কোনো বিরোধ নেই বলে তিনটিই টিকে যায়। নিচের প্রোগ্রাম partition refinement চালিয়ে প্রতিটি ধাপ ছাপে, তারপর মূল আর ছোট machine-কে ৮ বিট পর্যন্ত দৈর্ঘ্যের সব input-ধারায় চালিয়ে মেলায়:
// State minimisation by partition refinement on a 7-state Mealy machine.
// M[s][x] = [next state, output]. Start state A.
const M = { A: [["A", 0], ["B", 0]], B: [["C", 0], ["E", 0]], C: [["G", 0], ["D", 0]],
D: [["F", 0], ["E", 1]], E: [["F", 0], ["B", 0]], F: [["A", 0], ["D", 0]],
G: [["G", 0], ["E", 0]] };
const S = Object.keys(M), show = P => P.map(g => "{" + g.join(",") + "}").join(" ");
function split(keyOf) { // group states that have the same key
const g = {}; S.forEach(s => (g[keyOf(s)] ??= []).push(s)); return Object.values(g);
}
let P = split(s => "out" + M[s].map(c => c[1]).join("")), k = 0; // P0: same output row
for (;;) {
console.log(`P${k}: ${show(P)}`);
const id = {}; P.forEach((g, i) => g.forEach(s => (id[s] = i)));
const Q = split(s => id[s] + ":" + M[s].map(c => id[c[0]]).join(",")); // same block AND same next-blocks
if (Q.length === P.length) { console.log(`P${k + 1} = P${k}: stable`); break; }
P = Q; k++;
}
const rep = {}; P.forEach(g => g.forEach(s => (rep[s] = g[0]))); // name each block by its first state
const R = {}; P.forEach(g => (R[g[0]] = M[g[0]].map(([n, z]) => [rep[n], z])));
console.log("reduced table (state: x=0 next/z, x=1 next/z):");
for (const s in R) console.log(` ${s}: ${R[s][0].join("/")} ${R[s][1].join("/")}`);
function outputs(T, bits) { // output string of a machine on an input string
let s = "A", z = "";
for (const ch of bits) { z += T[s][+ch][1]; s = T[s][+ch][0]; }
return z;
}
let tested = 0, bad = 0;
for (let len = 1; len <= 8; len++)
for (let v = 0; v < 1 << len; v++) {
const bits = v.toString(2).padStart(len, "0"); tested++;
if (outputs(M, bits) !== outputs(R, bits)) bad++;
}
console.log(`${S.length} states -> ${P.length} states; ${tested} input strings checked, ${bad} differ`);আউটপুট:
P0: {A,B,C,E,F,G} {D}
P1: {A,B,E,G} {C,F} {D}
P2: {A,G} {B,E} {C,F} {D}
P3 = P2: stable
reduced table (state: x=0 next/z, x=1 next/z):
A: A/0 B/0
B: C/0 B/0
C: A/0 D/0
D: C/0 B/1
7 states -> 4 states; 510 input strings checked, 0 differ
প্রথম চার লাইন ঠিক stepper-এর চারটি ধাপ: P0-এ শুধু output দিয়ে ভাগ, P1-এ C আর F আলাদা হলো, P2-এ A-G আর B-E আলাদা হলো, আর P3 = P2 বলে থামা। কোডের মূল লাইনটি split(s => id[s] + ":" + …) — একটি state-এর “চাবি” হলো তার নিজের দল আর দুই পরের state-এর দল; একই চাবির state-গুলো এক দলে যায়। তারপর ছোট টেবিলটি হুবহু “1011” detector. শেষ লাইন 510 input strings checked, 0 differ: ১ থেকে ৮ দৈর্ঘ্যের মোট ২ + ৪ + … + ২৫৬ = ৫১০টি ধারায় দুই machine-এর output এক। এটি প্রমাণ নয়, যাচাই — প্রমাণটি ওপরের k-equivalence-এর যুক্তি; তবে টেবিলে একটি ভুল ঢুকিয়ে দেখুন (যেমন G-এর x = 1-এ ["D", 0]), সাথে সাথে partition বদলাবে।
সাধারণ ভুল: শুধু “একই output, একই পরের state” দেখে জোড়া মেলানো (row matching). এটি নিরাপদ কিন্তু অসম্পূর্ণ — B আর E-এর পরের state (C, E) আর (F, B) হুবহু এক নয়, তবু তারা equivalent. চক্রাকার নির্ভরতা ধরতে partition বা implication table লাগে। আরেকটি ভুল: Moore machine-এ শুরুর ভাগ করতে ভুলে Mealy-র মতো তীরের output দেখা — Moore-এ ভাগ হয় state-এর নিজের output দিয়ে।
৬ · ধাপ ৪–৭ · State assignment, K-map থেকে সমীকরণ আর যাচাই
ধাপ ৪ · কোন state পাবে কোন বিট
A, B, C, D নামগুলো hardware বোঝে না; প্রতিটিকে একটি বিট-নকশা দিতে হয়। এই সিদ্ধান্তকে বলে state assignment বা state encoding. n-টি state-এর জন্য প্রধান তিনটি পথ:
| Encoding | ৪টি state-এ উদাহরণ | Flip-flop | সুবিধা | অসুবিধা |
|---|---|---|---|---|
| Binary | 00, 01, 10, 11 | ⌈log2 n⌉ | সবচেয়ে কম flip-flop | Next-state logic অনেক বিটের ওপর নির্ভর করতে পারে |
| Gray | 00, 01, 11, 10 | ⌈log2 n⌉ | ক্রমানুসারে চলা machine-এ প্রতি ধারে এক বিট বদলায় — কম toggle, কম শক্তি | শাখা-প্রশাখার machine-এ সুবিধা কম, logic বড়ও হতে পারে |
| One-hot | 1000, 0100, 0010, 0001 | n | প্রতিটি next-state সমীকরণ ছোট আর অগভীর; দ্রুত; ডিবাগ সহজ (কোন বিট 1, সেটিই state) | বেশি flip-flop; ২n − n টি অবৈধ নকশা — reset আর নিরাপত্তার যত্ন লাগে |
One-hot-এর সমীকরণ লেখা প্রায় যান্ত্রিক: “এই state-এর flip-flop পরের ধারে 1 হবে, যদি এখন এমন কোনো state সক্রিয় থাকে যার তীর এখানে আসে, আর সেই তীরের input মেলে”। যেমন “1011” detector-এ C-তে আসে B --0--> আর D --0-->, তাই DC = QBx′ + QDx′. FPGA-তে প্রতিটি LUT-এর পাশে flip-flop প্রায় বিনামূল্যে থাকে, আর এমন ছোট সমীকরণ একটি LUT-এই ধরে যায় — তাই FPGA-র synthesis tool প্রায়ই নিজে থেকে FSM-কে one-hot-এ বদলে নেয় (tool আর সেটিংসভেদে)। ASIC-এ flip-flop তুলনায় দামি, তাই ছোট-মাঝারি FSM-এ binary বা নকশাকারীর বাছা encoding বেশি দেখা যায়।
Binary-র ভেতরেও কোন state কোন কোড পাবে, তাতে logic বদলায়। ৪টি state-এ ৪! = ২৪ রকম assignment, আর বড় machine-এ সংখ্যাটি বিশাল — তাই পুরোনো পাঠ্যবইয়ে হাতে-খাটানো নিয়ম আছে: যে দুটি state-এর একই পরের state, বা যারা একই state-এর পরের state, তাদের পাশাপাশি (এক বিট ভিন্ন) কোড দিন — এতে K-map-এ 1-গুলো পাশাপাশি পড়ে বড় দল হয়। আধুনিক tool এই খোঁজ heuristic দিয়ে করে।
ধাপ ৫–৭ · K-map থেকে সমীকরণ, circuit আর যাচাই
Binary assignment নিন: A = 00, B = 01, C = 10, D = 11 (বিট Q1Q0). প্রতিটি সারিতে বর্তমান Q1Q0 আর x থেকে পরের Q1+Q0+ আর z লিখুন। D flip-flop-এ Q+ = D, তাই পরের state-এর বিটই সরাসরি D ইনপুট — একে বলে transition table:
| State | Q1 Q0 x | পরের state | D1 D0 | z |
|---|---|---|---|---|
| A | 0 0 0 | A | 0 0 | 0 |
| A | 0 0 1 | B | 0 1 | 0 |
| B | 0 1 0 | C | 1 0 | 0 |
| B | 0 1 1 | B | 0 1 | 0 |
| C | 1 0 0 | A | 0 0 | 0 |
| C | 1 0 1 | D | 1 1 | 0 |
| D | 1 1 0 | C | 1 0 | 0 |
| D | 1 1 1 | B | 0 1 | 1 |
এবার প্রতিটি কলাম আলাদা একটি ৩-চলকের Boolean function — পর্ব ০৯-এর K-map দিয়ে সরল করুন (এই পৃষ্ঠায় complement লেখা হয়েছে প্রাইম চিহ্নে: x′ মানে NOT x; কোডের আউটপুটে একই জিনিস ASCII ' দিয়ে):
- D1 = Σm(2, 5, 6). ঘর ২ (010) আর ৬ (110) পাশাপাশি — দল Q0x′. ঘর ৫ (101) একা — Q1Q0′x. তাই D1 = Q0x′ + Q1Q0′x.
- D0 = Σm(1, 3, 5, 7) — x = 1-এর চারটি ঘরই। এক দলে: D0 = x. অর্থ স্পষ্ট: শেষ বিট 1 হলেই পরের state B বা D (দুটিরই Q0 = 1).
- z = Σm(7) = Q1Q0x — state D আর x = 1. Mealy বলে x আছে।
ধাপ ৬, circuit: দুটি D flip-flop (একই clock); D0-এ সরাসরি x-এর তার; D1-এ দুটি AND (২ আর ৩ ইনপুটের) আর একটি OR; z-এর জন্য একটি ৩-ইনপুট AND; আর x′ ও Q0′-এর জন্য দুটি inverter. সব মিলিয়ে কয়েকটি gate — ৪টি product term, ৯টি literal. Encoding বদলালে এই হিসাব কেমন বদলায়, আর সমীকরণগুলো আসলেই state table মেনে চলে কি না (ধাপ ৭), নিচের প্রোগ্রাম দেখায়। এটি ছোট একটি brute-force minimiser চালিয়ে binary আর Gray-তে ন্যূনতম SOP খোঁজে, one-hot-এ তীর গুনে সমীকরণ লেখে, তারপর তিনটি circuit-কে ২৫৬ cycle চালিয়ে টেবিলের সাথে মেলায়:
// Minimised "1011" Mealy detector -> D flip-flop and output equations under three encodings.
const T = { A: [["A", 0], ["B", 0]], B: [["C", 0], ["B", 0]], C: [["A", 0], ["D", 0]], D: [["C", 0], ["B", 1]] };
const S = Object.keys(T), lits = c => [...c].filter(ch => ch !== "-").length;
const has = (c, m, n) => [...c].every((ch, i) => ch === "-" || +ch === ((m >> (n - 1 - i)) & 1));
function minSOP(n, f) { // f(m) = 1 or 0; brute-force smallest SOP (n <= 3)
const all = [...Array(1 << n).keys()], on = all.filter(m => f(m)), cubes = [];
for (let v = 0; v < 3 ** n; v++) { let c = ""; for (let i = 0, w = v; i < n; i++, w = (w - w % 3) / 3) c += "01-"[w % 3]; cubes.push(c); }
const imp = cubes.filter(c => all.every(m => !has(c, m, n) || f(m)) && on.some(m => has(c, m, n)));
let best = [], cost = Infinity; // try every subset of implicants
for (let mask = 0; mask < 2 ** imp.length; mask++) { // cost = literals, then number of terms
const pick = imp.filter((_, i) => Math.floor(mask / 2 ** i) % 2), c = pick.reduce((a, p) => a + lits(p), 0) * 100 + pick.length;
if (c < cost && on.every(m => pick.some(p => has(p, m, n)))) { best = pick; cost = c; }
}
return best; }
function design(label, code, names, oneHot) { // code[state] = bits; one-hot = OR of the arcs entering each state
const k = code.A.length, n = k + 1, dec = {}; S.forEach(s => (dec[code[s]] = s));
const row = m => T[dec[(m >> 1).toString(2).padStart(k, "0")]][m & 1];
const arcs = want => S.flatMap(s => [0, 1].filter(x => want(T[s][x])).map(x => code[s].replace(/0/g, "-") + x));
const eqs = [...Array(k).keys()].map(i => oneHot ? arcs(([nx]) => code[nx][i] === "1") : minSOP(n, m => +code[row(m)[0]][i]));
const zq = oneHot ? arcs(([, z]) => z === 1) : minSOP(n, m => row(m)[1]);
const sop = e => e.map(c => [...c].map((ch, i) => ch === "-" ? "" : names[i] + (ch === "0" ? "'" : "")).join("")).join(" + ") || "0";
const total = [...eqs, zq].flat(); console.log(`${label}: ${k} flip-flops, ${total.length} product terms, ${total.reduce((a, c) => a + lits(c), 0)} literals`);
eqs.forEach((e, i) => console.log(` D${names[i]} = ${sop(e)}`)); console.log(` z = ${sop(zq)}`);
let s = "A", q = code.A, ok = 0, x = 1, seen = new Set(); // verify: equations vs table, 256 clocks
for (let t = 0; t < 256; t++, x = (x * 13 + 7) % 32) {
const b = x >> 4, m = parseInt(q + b, 2), z = +zq.some(c => has(c, m, n));
const nq = eqs.map(e => +e.some(c => has(c, m, n))).join("");
if (z === T[s][b][1] && nq === code[T[s][b][0]]) ok++;
seen.add(s + b); s = T[s][b][0]; q = nq;
}
console.log(` check: ${ok}/256 cycles match the table, ${seen.size}/8 transitions exercised`);
}
design("binary A=00 B=01 C=10 D=11", { A: "00", B: "01", C: "10", D: "11" }, ["Q1", "Q0", "x"]);
design("gray A=00 B=01 C=11 D=10", { A: "00", B: "01", C: "11", D: "10" }, ["Q1", "Q0", "x"]);
design("one-hot A=1000 B=0100 C=0010 D=0001", { A: "1000", B: "0100", C: "0010", D: "0001" }, ["QA", "QB", "QC", "QD", "x"], true);আউটপুট:
binary A=00 B=01 C=10 D=11: 2 flip-flops, 4 product terms, 9 literals
DQ1 = Q0x' + Q1Q0'x
DQ0 = x
z = Q1Q0x
check: 256/256 cycles match the table, 8/8 transitions exercised
gray A=00 B=01 C=11 D=10: 2 flip-flops, 7 product terms, 18 literals
DQ1 = Q1Q0'x' + Q1'Q0x' + Q1Q0x
DQ0 = Q0'x + Q1Q0' + Q1'Q0
z = Q1Q0'x
check: 256/256 cycles match the table, 8/8 transitions exercised
one-hot A=1000 B=0100 C=0010 D=0001: 4 flip-flops, 9 product terms, 18 literals
DQA = QAx' + QCx'
DQB = QAx + QBx + QDx
DQC = QBx' + QDx'
DQD = QCx
z = QDx
check: 256/256 cycles match the table, 8/8 transitions exercised
Binary-এ প্রোগ্রামের ফল হাতে করা K-map-এর সাথে মেলে: DQ1 = Q0x' + Q1Q0'x, DQ0 = x, z = Q1Q0x — ২টি flip-flop, ৯টি literal. Gray (A = 00, B = 01, C = 11, D = 10)-এ literal দ্বিগুণ, ১৮টি — কারণ এই detector ক্রমানুসারে চলে না, পেছনে লাফায় (C → A, D → B), তাই Gray-এর “এক বিট বদল” সুবিধা এখানে কাজে লাগে না। One-hot-এ ৪টি flip-flop আর ১৮টি literal, কিন্তু প্রতিটি term মাত্র দুই literal-এর — প্রতিটি সমীকরণ অগভীর, আর বড় machine-এ (ধরুন ২০টি state) binary-র সমীকরণ যেখানে ৫টি state-বিট আর input মিলিয়ে বড় হয়ে যায়, one-hot-এর প্রতিটি সমীকরণ তখনো শুধু আগত তীরের সংখ্যার সমান ছোট থাকে। তিন ক্ষেত্রেই 256/256 cycles match the table, 8/8 transitions exercised: সমীকরণ থেকে বানানো circuit প্রতি cycle-এ টেবিলের মতোই আচরণ করেছে, আর আটটি তীরের প্রতিটি অন্তত একবার চলেছে। শেষ সংখ্যাটি গুরুত্বপূর্ণ: এই প্রোগ্রামের প্রথম খসড়ায় একটি ছোট-চক্রের ছদ্ম-এলোমেলো input ব্যবহার করা হয়েছিল, যাতে 1010 কখনো আসত না — তখন D --0--> C তীরটি একবারও চলেনি (৭/৮), অথচ “256/256 match” ঠিকই দেখাত। এজন্যই অংশ ৮-এ coverage মাপার কথা আসবে।
একটি JK flip-flop উদাহরণ
পরীক্ষায় অনেক সময় JK বা T flip-flop দিয়ে নকশা চাওয়া হয়। তখন এক ধাপ বাড়ে: প্রতিটি সারিতে “Q থেকে Q+-এ যেতে J আর K-তে কী দিতে হবে” — এটি আসে excitation table থেকে (পর্ব ১৫-এ বিস্তারিত)। JK flip-flop-এর excitation: 0 → 0: J = 0, K = X; 0 → 1: J = 1, K = X; 1 → 0: J = X, K = 1; 1 → 1: J = X, K = 0. অনেক X (don't care) থাকায় K-map-এ দল বড় হয়। একই binary detector-এ:
| Q1 Q0 x | Q1+ Q0+ | J1 K1 | J0 K0 |
|---|---|---|---|
| 0 0 0 | 0 0 | 0 X | 0 X |
| 0 0 1 | 0 1 | 0 X | 1 X |
| 0 1 0 | 1 0 | 1 X | X 1 |
| 0 1 1 | 0 1 | 0 X | X 0 |
| 1 0 0 | 0 0 | X 1 | 0 X |
| 1 0 1 | 1 1 | X 0 | 1 X |
| 1 1 0 | 1 0 | X 0 | X 1 |
| 1 1 1 | 0 1 | X 1 | X 0 |
K-map থেকে (X-কে দরকারমতো 1 ধরে): J1 = Q0x′, K1 = Q0′x′ + Q0x (অর্থাৎ Q0 ⊙ x, XNOR), J0 = x, K0 = x′. যাচাই: JK-র সূত্র Q+ = JQ′ + K′Q-তে বসালে Q0+ = xQ0′ + xQ0 = x — D-নকশার D0 = x-এর সাথে মেলে। (এই সমীকরণগুলো একটি আলাদা scratch script-এ brute-force minimiser দিয়েও মিলিয়ে নেওয়া হয়েছে।)
Moore সংস্করণের হিসাব: ৫-state Moore detector-এ binary-তে ৩টি flip-flop লাগে (S0 = 000 … S4 = 100), আর 101, 110, 111 অব্যবহৃত — এগুলোকে don't care ধরলে D2 = Q1Q0x, D1 = Q0x′ + Q2x′ + Q1Q0′x, D0 = Q0′x + Q1′x, আর z = Q2 — output-এ কোনো gate-ই লাগে না, সরাসরি একটি flip-flop. Mealy-র চেয়ে একটি flip-flop বেশি, কিন্তু output পরিষ্কার। (একই scratch script-এ যাচাই করা।)
৭ · আরও দুটি উদাহরণ, অব্যবহৃত state আর reset
(ক) Serial even parity — একটি T flip-flop
একটি তারে বিট আসছে; এখন পর্যন্ত আসা 1-এর সংখ্যা জোড় হলে z = 1 (Moore). দুটি state যথেষ্ট — EVEN (z = 1) আর ODD (z = 0); 1 এলে state উল্টায়, 0 এলে থাকে। Q = 0 মানে EVEN ধরলে: D-তে D = Q ⊕ x, আর T flip-flop-এ আরও সহজ — T = x (1 এলে toggle), z = Q′. Network-এর parity বিট এভাবেই হিসাব হয় (Computer Networks কোর্সের error detection পর্ব)।
(খ) ৩ দিয়ে বিভাজ্য কি না — serial বিটে
একটি binary সংখ্যা MSB আগে করে একটি একটি বিট আসছে। প্রতি মুহূর্তে বলতে হবে, এখন পর্যন্ত আসা সংখ্যাটি ৩ দিয়ে বিভাজ্য কি না। পুরো সংখ্যা মনে রাখার দরকার নেই — শুধু ৩ দিয়ে ভাগশেষ r. যুক্তি: এখন পর্যন্ত সংখ্যা N হলে নতুন বিট x আসার পর সংখ্যা 2N + x; তাই নতুন ভাগশেষ r+ = (2r + x) mod 3, যা শুধু r আর x-এর ওপর নির্ভর করে। ৩টি state: R0, R1, R2; z = 1 শুধু R0-তে (Moore).
| State (কোড Q1Q0) | x = 0 (2r) | x = 1 (2r + 1) | z |
|---|---|---|---|
| R0 (00) | R0 | R1 | 1 |
| R1 (01) | R2 | R0 | 0 |
| R2 (10) | R1 | R2 | 0 |
| অব্যবহৃত (11) | X | X | X |
উদাহরণ: 110110 (= ৫৪)। ভাগশেষ ক্রমে 1, 0, 0, 1, 0, 0 (১, ৩, ৬, ১৩, ২৭, ৫৪-এর ভাগশেষ) — শেষে R0, অর্থাৎ ৫৪ ৩ দিয়ে বিভাজ্য। কোড 11-কে don't care ধরে K-map থেকে: D1 = Q0x′ + Q1x, D0 = Q1x′ + Q1′Q0′x, z = Q1′Q0′ — মোট ৯টি literal.
অব্যবহৃত state — চুপচাপ ফাঁদ
৩টি state-এর জন্য ২টি flip-flop, তাই কোড 11 কোনো state পায়নি — এটি unused state. স্বাভাবিক চলায় সেখানে যাওয়া যায় না, কিন্তু চালু হওয়ার মুহূর্তে flip-flop-এর মান এলোমেলো থাকতে পারে, বা বিদ্যুতের ঝাঁকুনি, তড়িৎ-চৌম্বক শব্দ বা মহাজাগতিক কণার আঘাতে একটি বিট উল্টে যেতে পারে। তখন প্রশ্ন: 11 থেকে machine কোথায় যায়? ওপরের সমীকরণে বসিয়ে দেখুন: x = 0 হলে D1 = 1·1 = 1, D0 = 1·1 = 1 — আবার 11! আর z = 0. অর্থাৎ যতক্ষণ 0 আসতে থাকে, machine 11-এ আটকে থাকে, ভুল output দেয় — একে বলে lock-up. x = 1 এলে 10 (R2)-তে বেরিয়ে আসে, কিন্তু ততক্ষণে হিসাব নষ্ট।
সমাধান তিনটি, খরচ অনুযায়ী:
- স্পষ্ট নিয়ম দেওয়া: don't care না ধরে লিখুন 11 → R0 (দুই input-এই)। নতুন সমীকরণ D1 = Q1′Q0x′ + Q1Q0′x, D0 = Q1Q0′x′ + Q1′Q0′x — ১২টি literal (আগে ৯)। খরচ সামান্য বাড়ল, বদলে machine self-correcting: যেকোনো অবস্থা থেকে এক cycle-এ বৈধ state-এ ফেরে।
- অন্তত যাচাই করা: don't care রেখে সমীকরণ বের করার পর প্রতিটি অব্যবহৃত কোড বসিয়ে দেখুন — কয়েক cycle-এ বৈধ state-এ ফিরলে যথেষ্ট কি না, নকশার প্রয়োজন অনুযায়ী ঠিক করুন। (অংশ ৬-এর ৫-state Moore detector-এ 101, 110, 111 সবই এক cycle-এ বৈধ state-এ যায়।)
- Reset: চালু হওয়ার সময় একটি reset সংকেত সব flip-flop-কে শুরুর state-এ বসায়। এটি প্রায় প্রতিটি নকশায় লাগে — কিন্তু চলার মাঝে বিট উল্টালে reset সাহায্য করে না, তাই নিরাপত্তা-গুরুত্বপূর্ণ নকশায় প্রথম পথটিও লাগে।
Synchronous বনাম asynchronous reset
Synchronous reset
Reset শুধু clock-এর ধারে কাজ করে: always @(posedge clk) if (rst) state <= A; — reset আসলে D-পথে একটি mux. সুবিধা: সবকিছু একই clock-এর ছন্দে, timing হিসাব সহজ। অসুবিধা: clock না চললে reset হয় না, আর reset pulse অন্তত একটি ধার পর্যন্ত টিকতে হয়। একে বলে synchronous reset.
Asynchronous reset
Reset এলেই সঙ্গে সঙ্গে: always @(posedge clk or negedge rst_n) — flip-flop-এর বিশেষ clear pin ব্যবহার হয়। সুবিধা: clock ছাড়াই কাজ করে, চালু হওয়ার সময় নিরাপদ। ঝুঁকি: reset ছাড়ার মুহূর্ত clock ধারের খুব কাছে পড়লে কিছু flip-flop এই ধারে, কিছু পরের ধারে ছাড়া পায় — state ভেঙে যেতে পারে। একে বলে asynchronous reset.
শিল্পে প্রচলিত সমাধান দুটির মিশ্রণ: reset ধরা হয় asynchronously, ছাড়া হয় synchronously — দুই flip-flop-এর একটি ছোট “reset synchronizer” দিয়ে। কোনটি ভালো, তা নিয়ে কোম্পানি আর FPGA-নির্মাতাদের পরামর্শ ভিন্ন; নকশার নিয়মপুস্তক মেনে চলাই নিয়ম। কেন ধারের কাছে বদলানো সংকেত বিপজ্জনক (setup-hold আর metastability), তা পর্ব ১৮-এ; reset ছাড়ার ক্ষেত্রে একই ধরনের সময়সীমার নাম recovery আর removal time.
৮ · Verilog-এ FSM — তিন block-এর রীতি আর পরীক্ষা
পর্ব ১৪-এ দেখেছেন, combinational block-এ কোনো পথে output মান না পেলে latch তৈরি হয়। FSM লেখার প্রচলিত রীতি এই ফাঁদ এড়ায় নকশাটিকে ছবি ১৭.২-এর তিন টুকরোয় আলাদা রেখে: একটি clock-চালিত block (শুধু state register), একটি combinational block (next-state logic) আর output-এর জন্য আরেকটি (বা একটি assign). State-এর নাম দেওয়া হয় localparam দিয়ে:
module det1011 (
input wire clk,
input wire rst_n, // active-low asynchronous reset
input wire x, // one serial bit per clock
output reg z
);
localparam [1:0] A = 2'd0, // nothing useful seen
B = 2'd1, // "1"
C = 2'd2, // "10"
D = 2'd3; // "101"
reg [1:0] state, next;
// (1) state register: the only flip-flops in the design
always @(posedge clk or negedge rst_n)
if (!rst_n) state <= A;
else state <= next;
// (2) next-state logic: combinational, blocking "="
always @(*) begin
next = state; // default first: every path assigns next, so no latch
case (state)
A: if (x) next = B;
B: if (!x) next = C;
C: next = x ? D : A;
D: next = x ? B : C; // overlapping: "1011" ends in "1" -> B
default: next = A; // unreachable here (all 4 codes used) - safe habit
endcase
end
// (3) output logic: Mealy = state AND input
always @(*) begin
z = 1'b0;
if (state == D && x) z = 1'b1;
end
endmoduleকয়েকটি নিয়ম, যা এই ছোট module-এ লুকিয়ে আছে:
next = state;শুরুতেই: যে শাখায় next লেখা হয়নি (যেমন A-তে x = 0), সেখানে “একই state-এ থাকা” — latch নয়, কারণ register তো আছেই। এই এক লাইন বাদ দিলে A আর B শাখায় next কোনো মান পায় না, আর synthesis একটি latch বসায়।- Register block-এ
<=, combinational block-এ=(non-blocking বনাম blocking) — পর্ব ১৪-এর নিয়ম। - Moore হলে output block শুধু state পড়বে: ৫-state নকশায়
assign z = (state == S4);. - Synchronous reset চাইলে sensitivity list থেকে
negedge rst_nসরিয়ে দিন — বাকি সব একই।
SystemVerilog-এ আরও পরিষ্কার: typedef enum logic [1:0] {A, B, C, D} state_t; দিয়ে state-এর নিজস্ব type (enum), আর always_ff / always_comb, যাতে tool নিজে মিলিয়ে দেখে block-টি সত্যিই flip-flop বা combinational. Simulator-এর waveform-এ তখন 2'd3-এর বদলে নাম “D” দেখায়। দুই-block রীতিও প্রচলিত — next-state আর output একই combinational block-এ — তবে output-কে register-এ রাখতে চাইলে (registered output) সেটি clock-চালিত block-এ যায়।
FSM পরীক্ষা — state আর transition coverage
একটি testbench যত cycle-ই চালাক, যদি কোনো তীর একবারও না চলে, সেই তীরের ভুল ধরা পড়বে না — অংশ ৬-এর প্রোগ্রামের প্রথম খসড়ার অভিজ্ঞতাই এর প্রমাণ। তাই FSM-এর পরীক্ষায় দুটি সংখ্যা মাপা হয়:
- State coverage: মোট state-এর কয়টিতে অন্তত একবার পৌঁছানো গেছে। দুর্বল মাপ — “1011” detector-এর চারটি state ছোঁয়া যায় এমন input-এও D --0--> C তীর বাদ পড়তে পারে।
- Transition coverage: state × input-এর কয়টি তীর চলেছে — এখানে ৮টির ৮টি চাই। আরও কড়া মাপ হলো তীরের জোড়া বা ক্রম (যেমন “মিলের ঠিক পরে আবার মিল” — overlapping পরীক্ষা)।
এর সাথে থাকে reset-এর পরের state, প্রতিটি অব্যবহৃত কোড থেকে কী হয়, আর একটি “সোনালি মডেল” (যেমন অংশ ৪-এর JS simulator) — RTL-এর output প্রতি cycle-এ মডেলের সাথে মেলানো। শিল্পে SystemVerilog-এর coverage tool এই গোনা স্বয়ংক্রিয়ভাবে করে, আর formal tool গাণিতিকভাবে প্রমাণ করতে পারে যে কোনো state থেকে ফেরার পথ আছে।
৯ · FSM সবখানে — protocol থেকে CPU, cache আর regex
একবার FSM চিনলে চারপাশে সবখানে দেখবেন। Hardware-এ:
- Protocol controller: একটি UART receiver-এর state সাধারণত IDLE (তার উঁচু) → START (নিচু হলো — start বিট কি না, মাঝখানে আবার দেখা) → DATA (৮টি বিট, প্রতিটির মাঝখানে নমুনা; সময় মাপতে প্রায়ই baud rate-এর ১৬ গুণ গতির একটি counter) → STOP (তার উঁচু কি না; না হলে framing error). USB-এর specification-এ একটি device-এর অবস্থাগুলো (যেমন Default, Address, Configured, Suspended) state machine হিসেবেই বর্ণিত, আর TCP সংযোগের LISTEN, SYN-SENT, ESTABLISHED-এর মতো অবস্থাও একটি বিখ্যাত state diagram (Computer Networks কোর্সের TCP সংযোগ পর্ব)।
- CPU-র control unit: একটি multi-cycle প্রসেসরে প্রতিটি instruction কয়েকটি ধাপে চলে — fetch, decode, execute, memory, write-back — আর কোন ধাপের পর কোন ধাপ, তা ঠিক করে একটি FSM; প্রতিটি state-এ কোন control সংকেত চালু থাকবে, তা Moore-ধাঁচের output. এই নকশা পর্ব ৩৩ (Control unit) আর পর্ব ৩৪ (Multi-cycle datapath আর microprogrammed control)-এ। Counter-ও আসলে একটি সরল FSM — যার input নেই, বা বড়জোর একটি enable; পর্ব ১৬-এ।
- Cache controller: প্রতিটি cache line-এর অবস্থা (Modified, Exclusive, Shared, Invalid) আর অন্য core-এর অনুরোধে তার বদল — MESI protocol — একটি FSM; পর্ব ৫৩-এ।
- Regex engine: তত্ত্বে output-হীন FSM-কে বলে DFA: কিছু state “গ্রহণযোগ্য”, শেষে সেখানে থাকলে লেখাটি নকশার সাথে মেলে। প্রতিটি regular expression-এর সমান একটি DFA আছে, আর “1011” detector আসলে regex
(0|1)*1011-এর DFA. Programming-এ regex ব্যবহার দেখতে পারেন Python কোর্সের regex পর্বে।
Software-এও FSM একটি প্রিয় নকশা-পদ্ধতি: firmware, game-এর চরিত্র, UI-এর পর্দা বদল, network parser. সবচেয়ে পরিষ্কার রূপ টেবিল-চালিত — state × event-এর একটি টেবিল, আর একটি ছোট loop. অংশ ১-এর PIN-লকের নকশা C-তে:
#include <stdio.h>
/* PIN entry that locks after 3 wrong tries, written as a table-driven FSM (Moore style). */
typedef enum { WRONG0, WRONG1, WRONG2, UNLOCKED, LOCKED, NSTATES } State;
typedef enum { OK, BAD, LOGOUT, RESET, NEVENTS } Event;
static const char *sname[NSTATES] = { "WRONG0", "WRONG1", "WRONG2", "UNLOCKED", "LOCKED" };
static const char *ename[NEVENTS] = { "correct PIN", "wrong PIN", "logout", "admin reset" };
static const char *say[NSTATES] = { "enter PIN (3 tries left)", "enter PIN (2 tries left)",
"enter PIN (1 try left)", "welcome", "account locked" };
static const State next[NSTATES][NEVENTS] = {
/* OK BAD LOGOUT RESET */
/* WRONG0 */ { UNLOCKED, WRONG1, WRONG0, WRONG0 },
/* WRONG1 */ { UNLOCKED, WRONG2, WRONG1, WRONG0 },
/* WRONG2 */ { UNLOCKED, LOCKED, WRONG2, WRONG0 },
/* UNLOCK */ { UNLOCKED, UNLOCKED, WRONG0, WRONG0 },
/* LOCKED */ { LOCKED, LOCKED, LOCKED, WRONG0 },
};
static State step(State s, Event e) {
if ((unsigned)s >= (unsigned)NSTATES || (unsigned)e >= (unsigned)NEVENTS)
return LOCKED; /* corrupted value: fall into the safe state */
return next[s][e];
}
int main(void) {
const Event input[] = { BAD, OK, LOGOUT, BAD, BAD, BAD, OK, RESET, OK };
State s = WRONG0; /* reset state */
printf("start %-8s : %s\n", sname[s], say[s]);
for (unsigned i = 0; i < sizeof input / sizeof input[0]; i++) {
State n = step(s, input[i]);
printf("%-11s %-8s -> %-8s : %s\n", ename[input[i]], sname[s], sname[n], say[n]);
s = n;
}
printf("unknown state 7 -> %s\n", sname[step((State)7, OK)]);
return 0;
}আউটপুট:
start WRONG0 : enter PIN (3 tries left)
wrong PIN WRONG0 -> WRONG1 : enter PIN (2 tries left)
correct PIN WRONG1 -> UNLOCKED : welcome
logout UNLOCKED -> WRONG0 : enter PIN (3 tries left)
wrong PIN WRONG0 -> WRONG1 : enter PIN (2 tries left)
wrong PIN WRONG1 -> WRONG2 : enter PIN (1 try left)
wrong PIN WRONG2 -> LOCKED : account locked
correct PIN LOCKED -> LOCKED : account locked
admin reset LOCKED -> WRONG0 : enter PIN (3 tries left)
correct PIN WRONG0 -> UNLOCKED : welcome
unknown state 7 -> LOCKED
প্রথম ভুলে WRONG1 (“2 tries left”), তারপর সঠিক PIN-এ UNLOCKED. Logout-এর পর WRONG0 — ভুলের গোনা আবার শূন্য। তারপর পরপর তিনটি ভুল: WRONG1 → WRONG2 → LOCKED. লক্ষ করুন পরের লাইন: LOCKED অবস্থায় সঠিক PIN দিলেও LOCKED -> LOCKED — টেবিলে LOCKED সারির OK ঘরে LOCKED লেখা, তাই কোনো if-এর ফাঁক দিয়ে ঢোকার সুযোগ নেই। শুধু admin reset-এ WRONG0, তারপর সঠিক PIN-এ আবার UNLOCKED. শেষ লাইনটি অংশ ৭-এর অব্যবহৃত state-এর software সংস্করণ: কোনো কারণে state variable-এ অবৈধ মান 7 এলে step() সোজা নিরাপদ state LOCKED-এ পাঠায় — hardware-এর default: শাখার মতো। টেবিল-চালিত নকশার আরেকটি সুবিধা: পুরো আচরণ এক নজরে দেখা আর পরীক্ষা করা যায় — ৫ × ৪ = ২০টি ঘর, ২০টি transition.
আরও গভীরে: বড় নকশায় একটি বিশাল FSM না বানিয়ে কয়েকটি ছোট FSM একে অন্যকে সংকেত দেয় (communicating FSMs), আর ডেটা রাখা হয় আলাদা datapath-এ — এই জোড়াকে বলে FSMD (FSM + datapath), যা পর্ব ৩২–৩৪-এর প্রসেসর নকশার কাঠামো। মহাকাশ বা চিকিৎসা-যন্ত্রের মতো জায়গায় বিকিরণে বিট উল্টানোর ঝুঁকি বেশি, তাই সেখানে state-কে Hamming কোডে রাখা, তিন কপি রেখে ভোট নেওয়া (triple modular redundancy) বা synthesis tool-এর “safe FSM” বিকল্প ব্যবহারের কথা শোনা যায়। গবেষণায় FSM-এর state assignment আর decomposition বহু দশকের বিষয়, আর formal verification tool এখন নিয়মিতভাবে FSM-এর deadlock বা পৌঁছানো-যায়-না-এমন state খোঁজে।
পরীক্ষা ও ইন্টারভিউতে — কয়েকটি প্রচলিত ধরনের প্রশ্ন আর এক লাইনের উত্তর:
- Moore আর Mealy-র পার্থক্য কী? কোনটিতে state কম লাগে? Moore-এর output শুধু state থেকে (এক cycle পরে, স্থির); Mealy-র state + input থেকে (একই cycle-এ) — Mealy-তে state সমান বা কম।
- “1011” overlapping detector-এ কয়টি state আর flip-flop? Mealy: ৪টি state, ২টি flip-flop; Moore: ৫টি state, ৩টি flip-flop.
- ২০টি state-এর FSM-এ binary আর one-hot-এ কয়টি flip-flop? ⌈log2 ২০⌉ = ৫ বনাম ২০.
- দুটি state কখন equivalent? যেকোনো input-ধারায় দুটি থেকে একই output-ধারা আসলে; output-এ ভাগ করে তারপর পরের state-এর দল দিয়ে বারবার ভাগ করে (partition) বের হয়।
- Verilog FSM-এ latch কেন আসে, কীভাবে এড়াবেন? Next-state-এর combinational block-এ কোনো শাখায় next মান না পেলে; শুরুতে
next = state;আরcase-এdefault.
১০ · AI-এর যুগে — state diagram AI দিয়ে, যাচাই simulation দিয়ে
“1011 detector-এর Verilog লিখে দিন” বললে AI কয়েক সেকেন্ডে উত্তর দেয়, আর দেখতে প্রায়ই নিখুঁত। কিন্তু FSM-এর ভুল সূক্ষ্ম — একটি ভুল তীর শুধু বিশেষ input-ক্রমেই ধরা পড়ে। এই বিষয়ে AI-এর প্রচলিত ভুল:
- ভুল তীর: B-তে 1 এলে A-তে ফেরানো, D-তে 0 এলে A-তে ফেরানো (C হওয়ার কথা) — overlapping আর non-overlapping গুলিয়ে ফেলা।
- Moore আর Mealy মিশিয়ে ফেলা: “Moore” বলে output-এ input ঢুকিয়ে দেওয়া, বা Moore-এর এক cycle দেরি ভুলে testbench-এ ভুল cycle-এ output খোঁজা।
- K-map আর minimisation-এ ভুল: ভুল দল, অব্যবহৃত কোডকে don't care ধরে lock-up তৈরি করা, বা equivalent নয় এমন state একত্র করা।
- Non-synthesizable বা latch-ওয়ালা Verilog: default ছাড়া combinational block, একই block-এ
=আর<=মেশানো, নকশার ভেতরেinitialদিয়ে state বসানো। - বানানো তথ্য: কোনো chip বা protocol-এর state-এর নাম ও সংখ্যা, বা কোনো tool-এর encoding option ভুল বলা।
AI-কে নকশাকার নয়, সহকারী হিসেবে ব্যবহার করুন — সাথে প্রতিটি state-এর অর্থ আর পরীক্ষা চেয়ে নিন:
AI-এর দেওয়া FSM যাচাইয়ের চেকলিস্ট
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন — তারপর “→ উত্তর” চাপুন।
প্র ০১Mealy আর Moore — একই সময়ে দুটি মডেল কেন জন্মাল, আর আজও দুটিই কেন টিকে আছে?
১৯৫০-এর দশকের শুরুতে টেলিফোন এক্সচেঞ্জ আর প্রথম দিকের কম্পিউটারে relay আর vacuum tube দিয়ে বানানো sequential circuit-এর নকশা ছিল অনেকটাই শিল্পকর্ম — অভিজ্ঞ প্রকৌশলীর অনুমাননির্ভর। এটিকে একটি পদ্ধতিতে আনার চেষ্টা থেকেই তত্ত্বের জন্ম। ১৯৫৪ সালে David Huffman (যাঁর নাম Huffman coding-এর জন্যও পরিচিত) sequential switching circuit-এর নকশা নিয়ে একটি প্রভাবশালী প্রবন্ধ প্রকাশ করেন, যেখানে state table আর state কমানোর ধারণা গুরুত্ব পায়। ১৯৫৫ সালে Bell Labs-এর George H. Mealy Bell System Technical Journal-এ “A Method for Synthesizing Sequential Circuits” প্রকাশ করেন — সেখানে output transition-এর সাথে যুক্ত, যা relay circuit-এর বাস্তবতার কাছাকাছি, কারণ relay-এর output সরাসরি input-এর পরিবর্তনে সাড়া দিত।
১৯৫৬ সালে Edward F. Moore-এর “Gedanken-experiments on Sequential Machines” প্রকাশিত হয় Automata Studies নামের সংকলনে। তাঁর প্রশ্ন ছিল আরও দার্শনিক: একটি বন্ধ বাক্স, ভেতরে অজানা machine; বাইরে থেকে input দিয়ে output দেখে আমরা ভেতরের state সম্পর্কে কী জানতে পারি? এখান থেকেই “দুটি state বাইরে থেকে আলাদা করা যায় কি না” — equivalence আর minimisation-এর ধারণা স্পষ্ট রূপ পায়। Moore-এর মডেলে output state-এর গায়ে, যা গাণিতিকভাবে পরিষ্কার।
দুটি মডেল সমান শক্তিশালী — অংশ ৪-এর রূপান্তর দেখায়, একটিকে অন্যটিতে বদলানো যায়, শুধু এক cycle-এর দেরি আর state-সংখ্যার পার্থক্য। তবু দুটিই টিকে আছে, কারণ দুটি আলাদা প্রকৌশল-চাহিদা মেটায়। Mealy কম state আর তাৎক্ষণিক সাড়া দেয় — handshake protocol-এ “অনুরোধ এলেই একই cycle-এ ack” দরকার হলে কাজের। Moore স্থির, glitch-মুক্ত output দেয়, আর কয়েকটি FSM জোড়া লাগালে combinational loop তৈরি হয় না — বড় নকশায় timing নিশ্চিত করা সহজ। আধুনিক RTL নকশায় তাই প্রায়ই মিশ্র রূপ দেখা যায়: কিছু output Moore, কিছু Mealy, আর গুরুত্বপূর্ণ output-গুলো register-এ ধরে রাখা।
মূল উপলব্ধি: মডেলের পছন্দ গণিতের নয়, প্রকৌশলের প্রশ্ন — সাড়ার গতি, state-এর খরচ আর output-এর স্থিরতার মধ্যে দর-কষাকষি।
প্র ০২পূর্ণভাবে নির্দিষ্ট FSM-এর state কমানো সহজ, কিন্তু don't care থাকলে কেন হঠাৎ কঠিন হয়ে যায়?
এই পর্বের partition refinement কাজ করে কারণ “equivalence” একটি সত্যিকারের equivalence relation — p ≡ q আর q ≡ r হলে p ≡ r. তাই state-গুলোকে পরিষ্কার, পরস্পর-বিচ্ছিন্ন দলে ভাগ করা যায়, আর ভাগ শুধু সূক্ষ্ম হতে থাকে। প্রতিটি ধাপ বহুপদী (polynomial) সময়ের, ধাপ সর্বোচ্চ n − ১টি। ১৯৭১ সালে John Hopcroft এমন একটি চতুর algorithm দেন যা কাজটি প্রায় n log n সময়ে করে — আজও DFA minimisation-এর মানক পদ্ধতি। তত্ত্বের দিক থেকে Myhill–Nerode উপপাদ্য বলে, প্রতিটি regular language-এর জন্য একটি অনন্য (নামবদল ছাড়া) ন্যূনতম DFA আছে — অর্থাৎ উত্তর একটাই।
এখন ধরুন কিছু ঘর don't care — কোনো state-এ কোনো input কখনো আসে না, বা এলে output-এ কিছু যায় আসে না। একে বলে incompletely specified machine. তখন “equivalent”-এর বদলে আসে “compatible”: p আর q একসাথে রাখা যায়, যদি যেখানে দুজনেরই মান নির্দিষ্ট সেখানে মেলে। সমস্যা হলো compatibility transitive নয়: p-q compatible, q-r compatible, কিন্তু p-r নয় — কারণ q-এর don't care দুই দিকে দুইভাবে ব্যবহার হয়েছে। ফলে দলগুলো আর বিচ্ছিন্ন নয়, একে অন্যের ওপর পড়ে, আর “কোন দলগুলো বেছে নিলে সব state ঢাকা পড়ে, আর বেছে নেওয়া দলগুলোর পরের state-ও কোনো বেছে নেওয়া দলে থাকে” — এটি একটি জটিল আবরণ-সমস্যা। ১৯৫৯ সালে Paull আর Unger এই সমস্যার পদ্ধতিগত সমাধান (maximal compatible খুঁজে বাছাই) দেন, আর পরে দেখানো হয় যে সাধারণভাবে এটি NP-hard — বড় machine-এ সবচেয়ে ভালো উত্তর নিশ্চিতভাবে দ্রুত পাওয়ার কোনো পরিচিত উপায় নেই।
এটি পর্ব ১০-এর গল্পের পুনরাবৃত্তি: prime implicant বের করা সহজ, কিন্তু ন্যূনতম আবরণ বাছাই NP-hard; সেখানেও Espresso-র মতো heuristic tool এসেছিল। FSM synthesis tool-গুলোও তাই বাস্তবে heuristic আর সীমিত খোঁজ ব্যবহার করে, আর নকশাকারী নিজে বুঝে don't care দেন।
মূল উপলব্ধি: একটি ছোট সংজ্ঞাগত পার্থক্য — transitive হওয়া বা না হওয়া — একটি সমস্যাকে সহজ থেকে কঠিন শ্রেণিতে ঠেলে দিতে পারে; don't care স্বাধীনতা দেয়, কিন্তু খোঁজার জায়গাও বিশাল করে।
প্র ০৩Flip-flop কমানোই যদি লক্ষ্য হয়, তবু FPGA-তে one-hot কেন এত জনপ্রিয়? আর এর ঝুঁকি কোথায়?
Binary encoding শেখার সময় মনে হয় flip-flop কমানোই বুদ্ধিমানের কাজ। কিন্তু খরচের হিসাব নির্ভর করে hardware-এর গঠনের ওপর। ASIC-এ প্রতিটি flip-flop একটি standard cell, যা কয়েকটি NAND gate-এর সমান জায়গা নেয় আর clock-এ বিদ্যুৎ খরচ করে — সেখানে flip-flop কমানো সত্যিই লাভ। FPGA-তে ছবি উল্টো: প্রতিটি logic ব্লকে LUT-এর পাশে এক বা একাধিক flip-flop আগে থেকেই বসানো, ব্যবহার না করলে নষ্ট। সেখানে দামি জিনিস হলো LUT-এর ইনপুট আর logic-এর স্তর, কারণ প্রতিটি স্তর আর routing-এ delay যোগ হয়।
এই অবস্থায় one-hot-এর সুবিধা স্পষ্ট। প্রতিটি state-বিটের next-state সমীকরণ শুধু সেই state-এ আসা তীরের সংখ্যার সমান term — অংশ ৬-এর উদাহরণে সর্বোচ্চ ৩টি দুই-literal-এর term. এমন সমীকরণ প্রায়ই একটি LUT-এ ধরে, তাই এক স্তরের logic — দ্রুত clock. Binary-তে ২০টি state-এর machine-এ প্রতিটি next-state বিট ৫টি state-বিট আর input-এর জটিল function, যা কয়েক স্তরের LUT নেয়। এছাড়া one-hot-এ নতুন state যোগ করলে পুরোনো সমীকরণ প্রায় অপরিবর্তিত থাকে, আর waveform-এ কোন state সক্রিয় তা এক নজরে দেখা যায়। এজন্য প্রধান FPGA-নির্মাতাদের synthesis tool প্রায়ই FSM চিনে নিজে থেকে one-hot বা অন্য উপযুক্ত encoding বেছে নেয় — ঠিক কী করবে তা tool, সংস্করণ আর সেটিংসের ওপর নির্ভর করে।
ঝুঁকিটি অংশ ৭-এর অব্যবহৃত state-এর বড় সংস্করণ। n-বিট one-hot-এ বৈধ নকশা মাত্র nটি, অবৈধ ২n − nটি — যেমন দুটি বিট একসাথে 1, বা সব 0. “তীর গুনে” লেখা সমীকরণ ধরে নেয় ঠিক একটি বিট 1; একটি বিট উল্টে গেলে দুটি state একসাথে সক্রিয় হয়ে দুই দিকের output একসাথে চালু হতে পারে, বা সব 0 হয়ে machine চিরকাল থেমে যেতে পারে। তাই নিরাপত্তা-গুরুত্বপূর্ণ নকশায় অবৈধ নকশা ধরার logic, reset-এ ফেরা, বা tool-এর “safe” FSM বিকল্প ব্যবহার করা হয় — যা কিছু গতি আর জায়গা খরচ করে।
মূল উপলব্ধি: “সবচেয়ে ভালো encoding” বলে কিছু নেই — লক্ষ্য hardware-এর খরচের গঠন (flip-flop বনাম logic বনাম গতি) আর ভুলের ঝুঁকি মিলিয়ে বাছতে হয়।
প্র ০৪Regular expression, DFA আর “ধীর regex” — তত্ত্বের FSM কীভাবে প্রতিদিনের software-এর নিরাপত্তার প্রশ্ন হয়ে উঠল?
Regular expression-এর ধারণা এসেছে Stephen Kleene-এর ১৯৫০-এর দশকের কাজ থেকে, যেখানে তিনি স্নায়ুকোষের McCulloch–Pitts মডেল যে ধরনের “ঘটনা” চিনতে পারে, তা বর্ণনা করতে regular event-এর ভাষা দেন, আর দেখান এগুলো finite automaton দিয়ে চেনা যায়। ১৯৬৮ সালে Ken Thompson Communications of the ACM-এ একটি ছোট প্রবন্ধে দেখান কীভাবে একটি regex-কে সরাসরি machine code-এ রূপান্তর করে লেখার মধ্যে খোঁজা যায় — সব সম্ভাব্য state একসাথে অনুসরণ করে (NFA simulation). এই ধারণা পরে Unix-এর ed আর grep-এর মতো tool-এ আসে বলে জানা যায়।
তত্ত্ব বলে, যেকোনো regex-কে DFA-তে রূপান্তর করলে প্রতিটি অক্ষরে ঠিক একটি টেবিল-দেখা — লেখার দৈর্ঘ্যের সমানুপাতিক সময়, এই পর্বের “1011” detector-এর মতোই। সমস্যা হলো DFA-র state-সংখ্যা কখনো কখনো regex-এর দৈর্ঘ্যের তুলনায় সূচকীয়ভাবে বেড়ে যেতে পারে, তাই অনেক engine তৈরির সময় পুরো DFA বানায় না। আরও বড় কথা, অনেক জনপ্রিয় programming ভাষার regex engine backreference-এর মতো সুবিধা দিতে backtracking ব্যবহার করে — একটি পথ চেষ্টা, ব্যর্থ হলে ফিরে আরেকটি। কিছু নকশা, যেমন (a+)+b, মেলে না এমন লেখায় সূচকীয় সংখ্যক পথ চেষ্টা করে।
এখান থেকে একটি নিরাপত্তা-সমস্যা: কেউ ইচ্ছে করে এমন লেখা পাঠালে server-এর CPU আটকে যায় — একে বলে ReDoS (regular expression denial of service). প্রতিরক্ষার পথগুলো FSM তত্ত্ব থেকেই আসে: Google-এর RE2-এর মতো engine backreference বাদ দিয়ে automaton-ভিত্তিক পদ্ধতিতে রৈখিক সময়ের নিশ্চয়তা দেয়; অন্য engine-এ সময়সীমা বসানো, বিপজ্জনক নকশা এড়ানো, আর ব্যবহারকারীর দেওয়া regex গ্রহণ না করা। Network-এর intrusion detection-এ হাজারো নকশা একসাথে মেলাতে hardware বা FPGA-তে DFA-ভিত্তিক matcher-এর গবেষণাও হয়েছে।
মূল উপলব্ধি: FSM-এর state আর transition-এর সরল হিসাবই বলে দেয় কোন খোঁজ রৈখিক আর কোনটি বিস্ফোরক — তত্ত্ব জানা থাকলে নিরাপদ software লেখা সহজ হয়।
প্র ০৫একটি পুরো কম্পিউটারও কি একটি finite state machine? তাহলে CPU-কে একটি বিশাল FSM হিসেবে নকশা করা হয় না কেন?
কঠোর অর্থে হ্যাঁ। একটি কম্পিউটারের সব register, cache আর মেমরির বিট মিলিয়ে সসীমসংখ্যক বিট আছে; তাই সম্ভাব্য অবস্থার সংখ্যা সসীম — যদিও কল্পনাতীত বড়। ধরুন মাত্র ১ গিগাবাইট মেমরি: ২৩০ বাইট মানে প্রায় ৮৬০ কোটি বিট, আর অবস্থার সংখ্যা ২-এর সেই ঘাত — মহাবিশ্বের পরমাণুর আনুমানিক সংখ্যার চেয়েও বহু বহু গুণ বড়। তত্ত্বে তাই কম্পিউটারকে সাধারণত Turing machine দিয়ে ভাবা হয়, যার অসীম tape আছে, কারণ “মেমরি ফুরিয়ে গেলে আরেকটু যোগ করা যায়” — এই ধারণাই বাস্তবের কাছাকাছি।
নকশার দিক থেকে একটি বিশাল FSM অচল, কারণ state table লেখা, minimise করা বা যাচাই করা অসম্ভব। তাই প্রকৌশলীরা ভাগ করে কাজ করেন: যে তথ্য নিয়মিত আকারের (৩২-বিট সংখ্যা, মেমরির শব্দ), সেগুলো থাকে datapath-এ — register, ALU, multiplexer — যেখানে প্রতিটি বিট একই নিয়মে চলে, আলাদা state হিসেবে গোনার দরকার নেই। আর কখন কোন কাজ হবে, সেই ছোট সিদ্ধান্তগুলো নেয় একটি ছোট control FSM — পর্ব ৩৩–৩৪-এর control unit. Multi-cycle প্রসেসরের control unit-এ হয়তো দশ-বারোটি state, অথচ পুরো CPU-র অবস্থা অগণিত। এই “FSM + datapath” ভাগই আধুনিক digital নকশার মূল কাঠামো।
ইতিহাসেও এই ভাগের চিহ্ন আছে। ১৯৫১ সালে Maurice Wilkes প্রস্তাব করেন, control-এর FSM-কে gate দিয়ে না বানিয়ে একটি ছোট মেমরিতে “microprogram” হিসেবে রাখা যায় — প্রতিটি state একটি মেমরির শব্দ, আর পরের state-এর ঠিকানা সেই শব্দেই লেখা। IBM System/360 পরিবারের অনেক মডেলে এই microprogrammed control ব্যবহার হয়েছিল, আর আজও জটিল CISC instruction-এর জন্য x86 প্রসেসরে microcode আছে বলে জানা যায়। পর্ব ৩৪-এ এটি বিস্তারিত দেখবেন।
মূল উপলব্ধি: FSM শক্তিশালী ধারণা, কিন্তু বড় সিস্টেমে কাজে লাগে ছোট ছোট FSM হিসেবে — নিয়মিত ডেটা datapath-এ, আর সিদ্ধান্তের ছোট স্মৃতি control FSM-এ।
অনুশীলন
কাগজ-কলমে আগে নিজে করুন, তারপর পূর্ণ সমাধান মিলিয়ে নিন।
-
Detector নকশা করুন: একটি Moore machine নকশা করুন, যা serial input x-এ
101(overlapping) এলে z = 1 দেয়। (ক) state diagram ও state table, (খ) binary assignment-এ D flip-flop-এর সমীকরণ আর z, (গ) input0101101-এ প্রতি cycle-এর z (শেষ input-এর পরের cycle-সহ)।(ক) S0 = কিছু না, S1 = “1”, S2 = “10”, S3 = “101” পূর্ণ (z = 1). Transition: S0: 0 → S0, 1 → S1 · S1: 0 → S2, 1 → S1 · S2: 0 → S0, 1 → S3 · S3: 0 → S2 (“1010”-এর শেষ “10”), 1 → S1 (“1011”-এর শেষ “1”). মাত্র ৪টি state, কারণ Moore-এ “পূর্ণ” state-টিই S3.
(খ) S0 = 00, S1 = 01, S2 = 10, S3 = 11. Transition table থেকে D1 = Σm(2, 5, 6), D0 = Σm(1, 3, 5, 7). K-map: D1 = Q0x′ + Q1Q0′x, D0 = x, আর z = Q1Q0 (input নেই — Moore). মজার ব্যাপার: next-state সমীকরণ “1011” Mealy detector-এর হুবহু এক — কারণ দুই machine-এর state-এর অর্থ (কিছু না, 1, 10, 101) আর transition একই; শুধু output-এর নিয়ম আলাদা।
(গ) State ক্রম: S0 →0→ S0 →1→ S1 →0→ S2 →1→ S3 →1→ S1 →0→ S2 →1→ S3. Cycle ০ থেকে ৭-এ z =
0 0 0 0 1 0 0 1— “101” পূর্ণ হয় cycle ৩ আর ৬-এর input-এ, Moore-এর output আসে এক cycle পরে, cycle ৪ আর ৭-এ। (Scratch simulator-এ যাচাই করা।) -
State table ছোট করুন: নিচের Moore machine-এর state কমান (partition বা implication table — যেকোনো একটি), ছোট টেবিল লিখুন, আর বলুন machine-টি আসলে কী করে। শুরু A; প্রতিটি সারিতে x = 0-এ পরের state, x = 1-এ পরের state, আর z:
State x = 0 x = 1 z A A B 1 B C D 0 C E F 0 D A E 1 E F A 0 F B C 0 Partition: P0 (output দিয়ে) = {A, D} {B, C, E, F}. স্বাক্ষর (P0-এর দলে): A → (A, B) = (I, II), D → (A, E) = (I, II) — মেলে। B → (C, D) = (II, I), E → (F, A) = (II, I); C → (E, F) = (II, II), F → (B, C) = (II, II). তাই P1 = {A, D} {B, E} {C, F}. আবার: A (AD, BE), D (AD, BE); B (CF, AD), E (CF, AD); C (BE, CF), F (BE, CF) — কিছু ভাঙল না, থামুন।
Implication table দিয়েও একই: output-এ X: AB, AC, AE, AF, BD, CD, DE, DF. বাকি ঘর: AD চায় BE; BC চায় CE, DF; BE চায় CF, AD; BF চায় BC, CD; CE চায় EF, AF; CF চায় BE; EF চায় BF, AC. পাস ১-এ X: BC (DF X), BF (CD X), CE (AF X), EF (AC X). পাস ২-এ নতুন কিছু নয়। টিকে থাকে AD, BE, CF.
ছোট টেবিল: A: A, B, z = 1 · B: C, A, z = 0 · C: B, C, z = 0. এটি অংশ ৭-এর ৩ দিয়ে বিভাজ্যতার machine (A = R0, B = R1, C = R2) — MSB আগে আসা binary সংখ্যা ৩ দিয়ে বিভাজ্য হলে z = 1. যাচাই: মূল ৬-state machine-কে ০ থেকে ২৫৫ পর্যন্ত সব ৮-বিট সংখ্যায় চালিয়ে শেষ state-এর ভাগশেষ মেলানো হয়েছে — ২৫৬টিতেই ঠিক।
-
আউটপুট অনুমান করুন: “1011” detector-এর তিনটি সংস্করণে input
1011011011(বাঁ থেকে, cycle ০ থেকে ৯) দিলে কোন কোন cycle-এ z = 1 হবে? (ক) Mealy overlapping (খ) Mealy non-overlapping (গ) Moore overlapping (শেষ input-এর পরের cycle ১০-সহ)।(ক) z =
0001001001— cycle ৩, ৬ আর ৯. State-এর ক্রম (প্রতি ধারের পর): B C D B C D B C D B — প্রতিটি মিলের শেষ “1” পরের মিলের শুরু।(খ) z =
0001000001— cycle ৩ আর ৯. Cycle ৩-এর মিলের পর A-তে ফিরে নতুন করে শোনে: বাকি011011-এ প্রথম “0”-তে A-তেই থাকে, তারপর “1”, “1” — B, B; তারপর 0 → C, 1 → D, আর শেষ 1-এ মিল (z = 1, আবার A); অর্থাৎ cycle ৪–৯-এর বিট দিয়ে একটি নতুন “1011” পূর্ণ হয় cycle ৯-এ। State ক্রম: B C D A A B B C D A.(গ) Moore-এর z আসে এক cycle পরে: cycle ৪, ৭ আর ১০ — state ক্রম S0 S1 S2 S3 S4 S2 S3 S4 S2 S3 S4. (তিনটিই অংশ ৪-এর simulator-এর মতো একটি scratch script-এ যাচাই করা।)
-
সমীকরণ বের করুন: ৩ দিয়ে বিভাজ্যতার FSM (R0 = 00, R1 = 01, R2 = 10, কোড 11 don't care) JK flip-flop দিয়ে বানান: J1, K1, J0, K0 বের করুন। তারপর পরীক্ষা করুন, কোনোভাবে state 11-এ গেলে এই JK নকশা কোথায় যায় — D-নকশার মতো আটকে থাকে কি?
Excitation: সারি (Q1Q0x → পরের): 000 → 00, 001 → 01, 010 → 10, 011 → 00, 100 → 01, 101 → 10, 11x → X. Q1-এর জন্য: Q1 = 0 সারিতে J1 = পরের Q1 (0, 0, 1, 0), K1 = X; Q1 = 1 সারিতে J1 = X, K1 = উল্টো (100 → 0 হয়, তাই 1; 101 → 1 থাকে, তাই 0). Q0-এর জন্য একইভাবে।
ফল: J1 = Q0x′, K1 = x′, J0 = Q1x′ + Q1′x (= Q1 ⊕ x), K0 = 1 (Q0 = 1 হলে পরের ধারে সবসময় 0 — R1 থেকে R2 বা R0, দুটিরই Q0 = 0). z = Q1′Q0′.
State 11 থেকে: x = 0 হলে J1 = 1, K1 = 1 → Q1 উল্টে 0; J0 = 1, K0 = 1 → Q0 উল্টে 0 — পরের state 00 (R0). x = 1 হলে J1 = 0, K1 = 0 → Q1 = 1 থাকে; J0 = 0, K0 = 1 → Q0 = 0 — পরের state 10 (R2). তাই JK নকশা এক cycle-এই বৈধ state-এ ফেরে, যেখানে D-নকশা (D1 = Q0x′ + Q1x, D0 = Q1x′ + Q1′Q0′x) x = 0-তে 11-এই আটকে থাকে। শিক্ষা: don't care কীভাবে ব্যবহার হলো তার ওপর অব্যবহৃত state-এর আচরণ নির্ভর করে, তাই প্রতিবার আলাদা করে যাচাই করতে হয়। (দুটি ফলই scratch script-এ যাচাই করা।)
নিজেকে যাচাই করুন
ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।
ক্রমএকটি FSM কথার সমস্যা থেকে যাচাই-করা circuit পর্যন্ত নকশার ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)
- প্রতিটি state-এর অর্থ ঠিক করে state diagram আঁকা
- State table লেখা
- সমতুল্য state একত্র করা (minimisation)
- প্রতিটি state-কে বিট-কোড দেওয়া (state assignment)
- K-map দিয়ে next-state আর output সমীকরণ বের করা
- Circuit বানিয়ে simulation-এ প্রতিটি transition যাচাই করা
একটি synchronous FSM-এর output z কেবল বর্তমান state-এর ওপর নির্ভর করে, input x-এর ওপর সরাসরি নয়। এটি কোন ধরনের machine, আর input বদলালে output কখন সাড়া দেয়?
- Mealy; একই cycle-এ
- Moore; পরের clock ধারে state বদলানোর পর
- Asynchronous machine; সঙ্গে সঙ্গে
- Moore; কখনোই নয়, কারণ output input দেখে না
একটি FSM-এ ১০টি state. Binary encoding আর one-hot encoding-এ যথাক্রমে কয়টি flip-flop লাগবে?
- ৩ আর ১০
- ৪ আর ৮
- ৪ আর ১০
- ১০ আর ৪
“1011” overlapping Mealy detector-এর state: A (কিছু না), B (“1”), C (“10”), D (“101”). State D-তে input 1 এলে output আর পরের state কী?
- z = 1, পরের state B
- z = 1, পরের state A
- z = 0, পরের state C
- z = 0, পরের state একটি নতুন state E
একটি Mealy machine-এর state P আর Q-এর output প্রতিটি input-এ এক। P-এর পরের state (x = 0, x = 1) = (R, S), আর Q-এর = (S, R). কোন শর্তে P আর Q equivalent?
- যেহেতু output এক, তারা সবসময় equivalent
- শুধু তখনই, যদি পরের state-গুলো হুবহু এক হয়
- কখনোই নয়, কারণ পরের state উল্টো ক্রমে
- যদি R আর S নিজেরা equivalent হয়
Verilog-এ FSM-এর combinational next-state block always @(*) begin case (state) A: if (x) next = B; … endcase end-এ কিছু শাখায় next মান পায় না। Latch এড়ানোর সবচেয়ে প্রচলিত উপায় কোনটি?
- Sensitivity list-এ সব সংকেত হাতে লেখা
- Block-এর শুরুতেই
next = state;লেখা - সব
=-কে<=করা initial next = A;লেখা
৩টি state-এর একটি FSM ২টি flip-flop দিয়ে বানানো (কোড 00, 01, 10); কোড 11 অব্যবহৃত আর K-map-এ don't care ধরা হয়েছে। নিচের কোন কথাটি সঠিক?
- Reset থাকলে 11 নিয়ে কখনো ভাবতে হয় না
- Don't care ধরা থাকলে 11 সবসময় পরের ধারে 00-তে যায়
- সমীকরণে 11 বসিয়ে দেখতে হয়; কোনো input-এ এটি 11-এই আটকে থাকতে পারে
- Synthesis tool সবসময় 11-কে নিজে থেকে নিরাপদ state-এ পাঠায়
শব্দকোষ
লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:
মনে রাখুন
- FSM = state + input + output + transition. State অতীতের সারাংশ — ভবিষ্যতের জন্য যতটুকু দরকার। Hardware-এ: state register (D flip-flop) + next-state logic + output logic.
- Moore: z = λ(state) — এক cycle পরে, স্থির; Mealy: z = λ(state, x) — একই cycle-এ, state সমান বা কম। “1011” detector: Moore ৫ state, Mealy ৪.
- Sequence detector-এর নিয়ম: প্রতিটি state = “লক্ষ্যের শুরুর কতটুকু মিলেছে”; ভুল বিটে শেষ অংশের সবচেয়ে লম্বা মিলে-যাওয়া শুরুতে ফেরা। Overlapping বনাম non-overlapping শুধু মিলের পরের তীরে আলাদা।
- Minimisation: output দিয়ে ভাগ, তারপর পরের state-এর দল দিয়ে বারবার ভাগ যতক্ষণ না স্থির (বা implication table-এ X ছড়ানো)। Assignment: binary = কম flip-flop, one-hot = ছোট-দ্রুত logic (FPGA-তে প্রিয়), Gray = ক্রমিক machine-এ কম toggle.
- বাস্তবের নিয়ম: অব্যবহৃত কোড বসিয়ে lock-up যাচাই; reset (ধরা async, ছাড়া sync); Verilog-এ register, next-state, output আলাদা block আর
next = state;default; পরীক্ষায় পূর্ণ transition coverage.
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পর্ব ১৮ · Timing আর clock — propagation delay, setup-hold, critical path আর metastabilityপরবর্তী পর্বFSM কত দ্রুত চলতে পারে, আর asynchronous input থেকে metastability-র ঝুঁকি।
- পর্ব ১৯ · প্রজেক্ট — traffic light আর vending machine controller নকশাপ্রজেক্টএই পর্বের পদ্ধতি দিয়ে দুটি পূর্ণ নকশা।
- পর্ব ১৬ · Register, shift register আর counterআগের পর্বState register আর counter — সবচেয়ে সরল FSM.
- পর্ব ০৯ · K-map দিয়ে সরলীকরণ — ২ থেকে ৪ চলক, don't careভিত্তিNext-state সমীকরণ সরল করার মূল হাতিয়ার।
- কম্পিউটার আর্কিটেকচার ও ডিজিটাল লজিক · কোর্স হোম৬২টি পর্বপুরো কোর্সের রোডম্যাপ — logic gate থেকে multicore.
- কম্পিউটার ফান্ডামেন্টালস · Sequential circuitসহজ পরিচয়Flip-flop, register আর counter-এর সহজ পরিচয়।
- DSA · String matchingপাশের ট্র্যাকKMP-এর failure function — sequence detector-এর software রূপ।