निर्णय और लूप

निर्णय और लूप

डिफ़ॉल्ट रूप से CPU आपके निर्देशों को उसी क्रम में निष्पादित करता है जिस क्रम में वे ऊपर से नीचे दिखाई देते हैं। अपने आप में, वह क्रम कभी कोई चुनाव नहीं कर सकता या काम दोहरा नहीं सकता। एक ब्रांच वह तरीका है जिससे एक प्रोग्राम उस सीधे रास्ते को छोड़ता है: यह एक शर्त की जाँच करता है और, जब शर्त सत्य होती है, तो CPU को अगली पंक्ति के बजाय किसी भिन्न स्थान पर जारी रखने का निर्देश देता है। हर निर्णय और हर लूप इसी एक तंत्र से आता है।

यहाँ कोई if या for नहीं है। आप उन्हें लेबल (नामित स्थान) और ब्रांच (शर्त सत्य होने पर किसी स्थान पर कूदना) से बनाते हैं। एक लेबल एक नाम होता है जिसके बाद : आता है।

यह समझने के लिए कि एक ब्रांच कैसे निष्पादित होती है, आपको प्रोग्राम काउंटर (PC) के बारे में जानना होगा। PC एक विशेष रजिस्टर है, जो आपके कोड से छिपा होता है, जो निष्पादित हो रहे निर्देश का मेमोरी पता रखता है। एक ब्रांच निर्देश PC में एक नया मान लिखता है, इसलिए CPU अपना अगला निर्देश कोड की अगली पंक्ति से नहीं बल्कि आपके लक्ष्य लेबल से प्राप्त करता है।

शाखा परिवार

हर ब्रांच दो रजिस्टरों की तुलना करती है और केवल तब लेबल पर कूदती है जब परीक्षण सत्य होता है। जब परीक्षण विफल होता है, तो निष्पादन अगली पंक्ति पर जारी रहता है। छह परीक्षण मूल बनाते हैं:

छह वास्तविक शाखाएँ
beq a, b, label # यदि a == b हो तो शाखा लें
bne a, b, label # यदि a != b हो तो शाखा लें
blt a, b, label # यदि a < b हो तो शाखा लें (साइन सहित)
bge a, b, label # यदि a >= b हो तो शाखा लें (साइन सहित)
bltu a, b, label # यदि a < b हो तो शाखा लें (बिना साइन)
bgeu a, b, label # यदि a >= b हो तो शाखा लें (बिना साइन)

और समानता की जाँच करते हैं और चिह्न की उपेक्षा करते हैं। और क्रम-युग्म बनाते हैं, कम-से-कम और अधिक-या-बराबर, और रजिस्टरों की तुलना साइन्ड संख्याओं के रूप में करते हैं। और वही तुलनाएँ करते हैं लेकिन मानों को अनसाइन्ड मानते हैं, जो उन पतों या गणनाओं के लिए उपयुक्त है जो कभी ऋणात्मक नहीं होते।

साइन्ड और अनसाइन्ड का क्या अर्थ है? एक रजिस्टर 32 बिट रखता है, और वही बिट दो तरह से पढ़े जा सकते हैं। अनसाइन्ड के रूप में पढ़ने पर, वे 0 से लगभग 4 अरब तक एक साधारण पूर्ण संख्या बनाते हैं। साइन्ड के रूप में पढ़ने पर, सबसे ऊपरी बिट ऋण चिह्न के रूप में गिना जाता है, इसलिए आधे बिट पैटर्न ऋणात्मक संख्याओं को दर्शाते हैं। बिट स्वयं नहीं बदलते। केवल आपके पढ़ने का तरीका बदलता है। इसीलिए तुलनाओं के दो समूह हैं: सामान्य संख्याओं के लिए जो ऋणात्मक हो सकती हैं, साइन्ड वाले (, ) उपयोग करें, और उन मानों के लिए जो कभी ऋणात्मक नहीं होते, जैसे मेमोरी पते, अनसाइन्ड वाले (, ) उपयोग करें।

कोई सीधा "ब्रांच इफ ग्रेटर" या "ब्रांच इफ लेस-ऑर-इक्वल" नहीं है। आप उन्हें दो रजिस्टरों की अदला-बदली करके प्राप्त करते हैं, और असेंबलर और को छद्म-ब्रांच के रूप में प्रदान करता है जो आपके लिए अदला-बदली करती हैं, इसलिए बन जाता है। दो और शॉर्टकट: और एक रजिस्टर की शून्य से तुलना करते हैं, और बिना किसी शर्त के कूदता है।

लूप के साथ योग 1..5
li t0, 0 # योग = 0
li t1, 1 # i = 1
li t2, 6 # सीमा = 6 (जब तक i < 6 तब तक लूप)
loop:
bge t1, t2, done # जब i >= 6 हो तो लूप छोड़ें
add t0, t0, t1 # योग += i
addi t1, t1, 1 # i++
j loop # फिर से जाँचने वापस जाएँ
done:
mv a0, t0 # योग प्रिंट करें (15 होना चाहिए)
li a7, 1
ecall
li a7, 10
ecall

इसका अनुसरण करें। t0 चालू योग रखता है (0 से शुरू), t1 काउंटर i रखता है (1 से शुरू), और t2 सीमा 6 रखता है। loop से हर गुज़र में: लूप को छोड़ देता है जब i 6 तक पहुँच जाता है। अन्यथा योग में i जोड़ता है, i को एक से बढ़ाता है, और फिर से परीक्षण के लिए वापस कूदता है। लूप 1, 2, 3, 4, और 5 जोड़ता है, और done कुल 15 प्रिंट करता है।

शाखा के साथ लूप
loop:
bge t1, t2, done
add t0, t0, t1
addi t1, t1, 1
j loop
i (t1)1
योग (t0)0
हाँनहींt1 < 6?sum += t1t1 += 1पूरा

bge t1 की तुलना t2 से करता है यह तय करने के लिए कि लूप जारी रहेगा या नहीं।

नीचे दिया गया चित्र उस निर्देश को चिह्नित करता है जो काउंटर को अद्यतन करता है और उसे जो चालू योग को अद्यतन करता है, उन्हें लूप के बाकी हिस्सों से अलग करता है। काउंटर को आगे बढ़ाता है, और उसके बाद आने वाला नए काउंटर मान को योग में जोड़ता है। अंतिम फ़्रेम वह परीक्षण दिखाता है जो लूप को समाप्त करता है। जब t1 6 हो जाता है, नियंत्रण को done पर स्थानांतरित करता है बजाय शरीर को फिर से चलने देने के। वह परीक्षण ही उस गुज़र को अलग करता है जो दोहराता है उस गुज़र से जो रुकता है।
💡
प्रोग्राम के माध्यम से Run के बजाय Step से आगे बढ़ें। जैसे-जैसे आप आगे बढ़ते हैं, t1 बढ़ता है और प्रोग्राम काउंटर (pc) वापस loop पर कूदता है। हर बार जब pc loop पर लौटता है, ब्रांच शर्त असत्य थी, इसलिए लूप फिर से चलता है।
⚠
यदि निकास शर्त गलत है, तो लूप कभी समाप्त नहीं होता। सिम्युलेटर एक भागते हुए लूप को रोक देता है, लेकिन ब्रांच तर्क आपका है जिसे सही करना है।