RISC-V असेंबलरमध्ये प्रोग्रामिंग सुरू करण्यासाठी तुम्हाला काय आवश्यक आहे

शेवटचे अद्यतनः 08/10/2025
लेखक: इसहाक
  • RV32I समाविष्ट आहे: रजिस्टर्स, ABI आणि ecall सह प्रवाह नियंत्रण.
  • बृहस्पति ग्रहाचा सराव करा आणि व्यायाम करा: ऋण, घटक, साखळी, पुनरावृत्ती.
  • मास्टर क्रॉस टूलचेन, स्क्रिप्ट objdump सह लिंकिंग आणि डीबगिंग.

RISC-V असेंबलर: आवश्यकता आणि सुरुवात करणे

जर तुम्हाला असेंबलरबद्दल उत्सुकता असेल आणि तुम्हाला वाटत असेल की RISC-V हाच योग्य मार्ग आहे, तर तुम्ही योग्य ठिकाणी आला आहात. RISC-V वर ASM सह सुरुवात करणे वाटते त्यापेक्षा अधिक परवडणारे आहे. जर तुम्हाला साधने, मॉडेल समजले तर प्रोग्रामिंग आणि वास्तुकलेचे काही प्रमुख नियम.

खालील ओळींमध्ये मी अनेक सर्वोत्तम स्रोत एकत्र केले आहेत: ज्युपिटर प्रकारच्या सिम्युलेटरसह पद्धती, RV32I बेस रिपर्टोरचे नियम, लूप आणि रिकर्सन उदाहरणे, सिस्टम कॉल्स आणि VHDL मधील RISC-V CPU डिझाइनवर एक नजर (ALU, मेमरी कंट्रोल आणि स्टेट मशीनसह), तसेच क्रॉस-टूलचेन आणि लिंकिंग स्क्रिप्ट्सचा आढावा.

RISC-V असेंबलर म्हणजे काय आणि ते मशीन लँग्वेजपेक्षा कसे वेगळे आहे?

जरी दोन्ही संलग्न आहेत हार्डवेअर, मशीन भाषा ही शुद्ध बायनरी आहे (एक आणि शून्य) ज्याचा CPU थेट अर्थ लावतो, तर असेंबलर स्मृतिशास्त्र वापरतो आणि प्रतीक असेंबलरपेक्षा जास्त वाचनीय नंतर बायनरीमध्ये भाषांतरित होते.

RISC-V हे अतिशय स्वच्छ बेस रिपर्टोअरसह ओपन ISA परिभाषित करते. RV32I (32-बिट) प्रोफाइलमध्ये 39 वापरकर्ता सूचना समाविष्ट आहेत. उल्लेखनीय ऑर्थोगोनॅलिटीसह, मेमरी अॅक्सेसला शुद्ध संगणनापासून वेगळे करणे आणि GCC/LLVM मध्ये उत्कृष्ट समर्थनासह.

नोंदी, करार आणि प्रवेश बिंदू

RV32I मध्ये तुमच्याकडे आहे ३२ सामान्य उद्देश नोंदणी (x०–x३१) ३२-बिट; x0 हे नेहमी ० असे वाचले जाते आणि ते लिहिता येत नाही. a0–a7 (वितर्क), t0–t6 (तात्पुरते), किंवा s0–s11 ​​(जतन केलेले) सारखी उपनावे देखील ABI फॉलो करण्यासाठी उपयुक्त आहेत.

वातावरण किंवा सिम्युलेटरवर अवलंबून, प्रोग्राम एका विशिष्ट लेबलपासून सुरू होऊ शकतो. ज्युपिटरमध्ये, प्रोग्राम्स ग्लोबल __स्टार्ट टॅगपासून सुरू होतात., जे तुम्हाला प्रवेश बिंदू चिन्हांकित करण्यासाठी दृश्यमान म्हणून घोषित करावे लागेल (उदाहरणार्थ, .globl सह).

अगोदर निर्देश केलेल्या बाबीसंबंधी बोलताना टॅग्ज कोलनमध्ये संपतात, तुम्ही प्रत्येक ओळीत फक्त एकच सूचना देऊ शकता आणि टिप्पण्या # किंवा ; ने सुरू करता येतात म्हणून असेंबलर त्याकडे दुर्लक्ष करतो.

साधने आणि सिम्युलेटर: ज्युपिटर आणि मूलभूत कार्यप्रवाह

गुंतागुंतीशिवाय सराव करण्यासाठी, तुमच्याकडे आहे ज्युपिटर सिम्युलेटर/असेम्बलर, SPIM/MARS/VENUS द्वारे प्रेरित एक ग्राफिकल टूल जे एकाच वातावरणात संपादन, असेंब्ली आणि अंमलबजावणी सुलभ करते.

ज्युपिटरमध्ये तुम्ही एडिटर टॅबमध्ये फाइल्स तयार करू शकता, संपादित करू शकता आणि हटवू शकता. सेव्ह केल्यानंतर, F3 सह असेंबल करा आणि चालवा मशीनची स्थिती समजून घेण्यासाठी रजिस्टर आणि मेमरी व्ह्यूज वापरून, सूचनांनुसार फ्लो इंस्ट्रक्शन डीबग करणे.

कार्यक्रमांचा शेवट पर्यावरणाला आवाहनाने झाला पाहिजे: कोड १० वापरून कॉल सेटिंग a0 मधून बाहेर पडा. (एक्झिट). RISC-V मध्ये, ईकॉल हे सिस्टम कॉल किंवा पर्यावरण/सिस्टममधील ट्रॅप्सच्या समतुल्य असतात.

प्रोग्राम आणि सिस्टम कॉलची किमान रचना

शैक्षणिक उदाहरणांमधील विशिष्ट रचना सुरुवातीचा बिंदू परिभाषित करते, काम करते आणि एका कॉलने समाप्त होते. ecall वितर्क सहसा a0–a2 मध्ये प्रवास करतात आणि वातावरणानुसार, a7 मधील सेवा निवडकर्ता.

एक मध्ये linux उदाहरणार्थ, RISC-V मध्ये, तुम्ही write syscall वापरून प्रिंट करू शकता आणि योग्य कोड वापरून बाहेर पडू शकता. लेखनासाठी a0 (fd), a1 (बफर), a2 (लांबी) आणि a7 सेवा क्रमांकासह वापरले जातात.. शेवटी, a0 रिटर्न कोडवर आणि a7 एक्झिट नंबरवर सेट केले आहे.

# Ejemplo mínimo (Linux RISC-V) para escribir y salir
.global _start
_start:
  addi a0, x0, 1        # fd = 1 (stdout)
  la   a1, msg          # a1 = &msg
  addi a2, x0, 12       # a2 = longitud
  addi a7, x0, 64       # write
  ecall

  addi a0, x0, 0        # return code
  addi a7, x0, 93       # exit
  ecall

.data
msg: .ascii "Hola mundo\n"

जर तुम्ही लिनक्सच्या बाहेर काम करत असाल, जसे की स्वतःच्या आयओटी सेवेसह शैक्षणिक सिम्युलेटर, पर्यावरण दस्तऐवजीकरणानुसार ई-कॉल नंबर आणि नोंदणी बदला.

  Windows 8.1 ISO फायली मिळवा [USB आणि DVD सेटअप]

कंडिशन्स, लूप आणि मेमरीमध्ये आरामदायी होण्यास मदत करणारे सुरुवातीचे व्यायाम

एक सामान्य वॉर्म-अप म्हणजे पूर्णांक ऋण आहे की नाही हे शोधणे. जर ते सकारात्मक असेल तर तुम्ही 0 आणि जर ते नकारात्मक असेल तर 1 परत करू शकता.; RV32I सह, 0 आणि सेट-ऑन-लेस-दॅन शी तुलना केल्याने एकाच विचारपूर्वक केलेल्या सूचनांमध्ये समस्या सोडवली जाते.

आणखी एक अतिशय उपयुक्त व्यायाम म्हणजे संख्येचे घटक सूचीबद्ध करणे: १ पासून n पर्यंत प्रवास करते, विभाजक प्रिंट करते आणि किती होते ते परत करतेतुम्ही सशर्त शाखा, भागाकार (किंवा पुनरावृत्ती वजाबाकी) आणि बेरीज आणि तुलनेसह लूपचा सराव कराल.

स्ट्रिंग्ससह काम केल्याने तुम्हाला मेमरी व्यवस्थापित करावी लागते: मेमरीमधील स्ट्रिंगमधील प्रत्येक कॅरेक्टर पहा आणि त्या जागी लोअरकेस अक्षरे अपरकेसमध्ये रूपांतरित करा. जर ते ASCII श्रेणीमध्ये बसत असतील तर. पूर्ण झाल्यावर, ते स्ट्रिंगचा मूळ पत्ता परत करते.

लूप्स, फंक्शन्स आणि रिकर्सन: फॅक्टोरियल, फिबोनाची आणि टॉवर ऑफ हनोई

लूप डिझाइन करताना, तीन ब्लॉक्सचा विचार करा: कंडिशन, बॉडी आणि स्टेप. beq/bne/bge आणि बिनशर्त जंपसह jal/j while/for बांधले जातात गूढतेशिवाय, अ‍ॅडी आणि तुलनांवर अवलंबून राहून.

.text
.globl __start
__start:
  li t0, 0        # i
  li t1, 10       # max
cond:
  bge t0, t1, end # si i >= max, salta
  # cuerpo: usar a0/a1 segun servicio IO del entorno
  addi t0, t0, 1  # i++
  j cond
end:
  li a0, 10
  ecall

फंक्शन कॉलमध्ये, ABI चा आदर करा: जर तुम्हाला अधिक कॉल्स चेन करायचे असतील तर बचत करा., जर तुम्ही त्यांना सुधारित केले तर s0–s11 ​​जतन करते आणि शब्दाच्या पटीत sp हलवून स्टॅक वापरते.

फॅक्टोरियल हे क्लासिक रिकर्सन आहे: बेस केस n==0 १ मिळवते.; अन्यथा, फॅक्टोरियल(n-1) कॉल करा आणि n ने गुणा. कॉल करण्यापूर्वी स्टॅकवर सेव्ह केलेले ra आणि रजिस्टर्स संरक्षित करा आणि परत आल्यावर ते रिस्टोअर करा.

factorial:
  beq a0, x0, base
  addi sp, sp, -8
  sw   ra, 4(sp)
  sw   s0, 0(sp)
  mv   s0, a0
  addi a0, a0, -1
  jal  factorial
  mul  a0, a0, s0
  lw   s0, 0(sp)
  lw   ra, 4(sp)
  addi sp, sp, 8
  jr   ra
base:
  li a0, 1
  jr ra

फिबोनाची दोन्ही सराव करण्यासाठी उपयुक्त आहे दोन कॉलसह पुनरावृत्ती एक्युम्युलेटर व्हेरिअबल्ससह एक कार्यक्षम पुनरावृत्ती आवृत्ती म्हणून. आणि जर तुम्हाला फ्लो आणि पॅरामीटर कंट्रोल चॅलेंज हवे असेल, तर सोल्यूशनचे असेंबलरमध्ये भाषांतर करा. हनोईचे टॉवर्स चार वितर्कांसह: डिस्क, स्रोत, गंतव्यस्थान आणि सहाय्यक टॉवर; ते कॉल ऑर्डरचा आदर करते आणि प्रत्येक हालचाल प्रदर्शित करते.

मेमरी अ‍ॅक्सेस, अ‍ॅरे आणि स्ट्रिंग मॅनिपुलेशन

RISC-V मध्ये, मेमरी अॅक्सेस लोड/स्टोअर वापरून केला जातो: शब्दांसाठी lw/sw, अर्धशब्दांसाठी lh/sh आणि बाइट्ससाठी lb/sb, शुल्कांमध्ये स्वाक्षरीकृत किंवा स्वाक्षरी नसलेले प्रकार (lb विरुद्ध lbu, lh विरुद्ध lhu).

  अँड्रॉइडवर प्रोजेक्ट झोम्बॉइड: तुम्ही ते मोबाईलवर प्ले करू शकता का?

पूर्णांक अ‍ॅरे ओलांडण्यासाठी, प्रत्येक इंडेक्समध्ये ४-बाइट ऑफसेट वापरा; टेक्स्ट स्ट्रिंगसाठी, टर्मिनेटर सापडेपर्यंत बाइट बाय बाइट पुढे जाते जर कन्व्हेन्शनला त्याची आवश्यकता असेल (उदा., \0). बेस अॅड्रेस सेव्ह करायला विसरू नका आणि योग्य असल्यास addi/auipc/la वापरून पॉइंटर्स हाताळा.

आरव्ही३२आय सीपीयू सुरवातीपासून डिझाइन करणे: एक उच्च-स्तरीय आढावा

जर तुम्हाला सिलिकॉनवर जायचं असेल, तर एक शैक्षणिक प्रकल्प तयार करतो VHDL मध्ये RV32I CPU, FPGA मध्ये संश्लेषित करण्यायोग्य कमी-मध्यम श्रेणी. प्रोग्राम रॉम, डेटा रॅम आणि एलईडी लावण्यासाठी एक साधा जीपीआयओ समाविष्ट आहे.

कर्नल बेस रिपर्टायर (M/A/C एक्सटेंशन किंवा CSR शिवाय) लागू करतो, ३२-बिट अॅड्रेस बस वापरते आणि योग्य ठिकाणी ८-/१६-/३२-बिट साइन-एक्सटेंडेड मेमरी अॅक्सेसची परवानगी देते. डिझाइनमध्ये रजिस्टर्स, एएलयू, मेमरी कंट्रोलर आणि स्टेट मशीन स्पष्टपणे वेगळे केले आहेत.

ALU, शिफ्ट्स आणि "विलंबित लोडिंग" ची कल्पना

ALU चे वर्णन अशा ऑपरेशन्ससह एकत्रितपणे केले आहे जसे की बेरीज, वजाबाकी, XOR, OR, AND, तुलना (स्वाक्षरीकृत आणि अस्वाक्षरीकृत) आणि तार्किक/अंकगणितीय बदल.

FPGA मध्ये LUTs वाचवण्यासाठी, मल्टी-बिट शिफ्ट्स लागू केल्या जातात. स्टेट मशीनद्वारे नियंत्रित केलेल्या १-बिट शिफ्टची पुनरावृत्ती करणे: तुम्ही अनेक चक्रे वापरता, परंतु तुम्ही तार्किक संसाधने कमी करता.

सिंक्रोनस सर्किट्समध्ये, घड्याळाच्या कडांवर बदल दिसून येतात. "विलंबित भार" ही संकल्पना आठवते की मल्टीप्लेक्सरने निवडलेल्या गोष्टीचा पुढील चक्रात रजिस्टरवर परिणाम होतो., फेच-डीकोड-एक्झिक्युट स्टेट मशीन डिझाइन करताना एक महत्त्वाचा पैलू.

मेमरी कंट्रोलर आणि नकाशा: रॉम, रॅम आणि जीपीआयओ

मेमरी ब्लॉक रॉम आणि रॅमला एका जवळच्या जागेत एकत्रित करतो, प्रोसेसर इंटरफेस सोपे करणेनियंत्रकाला व्यवहार सुरू करण्यासाठी AddressIn (३२ बिट्स), DataIn, रुंदी (बाइट/अर्धा/शब्द), चिन्ह विस्तार सिग्नल, WE (वाचणे/लेखन) आणि प्रारंभ प्राप्त होतात.

ऑपरेशन संपल्यावर, रेडीआउट १ वर सेट केले आहे आणि जर ते वाचले असेल तर, DataOut मध्ये डेटा असतो (विनंती केल्यावर साइन-एक्सटेंड केला जातो). जर तो लिहिला गेला असेल, तर डेटा RAM मध्ये राहतो.

व्यावहारिक नकाशाचे उदाहरण: 0x0000 ते 0x0FFF पर्यंत रॉम, ०x१००० वर एक GPIO बाइट (एका पिनला बिट ०) आणि ०x१००१ ते ०x१FFF पर्यंत रॅमयाच्या मदतीने तुम्ही आउटपुट बिट लिहून आणि टॉगल करून ब्लिंकर बनवू शकता.

रजिस्टर्स, मल्टीप्लेक्सर्स आणि स्टेट मशीन्स

CPU व्हीएचडीएलमध्ये अ‍ॅरेसह इन्स्टंटिएटेड 32 सामान्य उद्देश रजिस्टर्स परिभाषित करते, ज्यामध्ये डीकोडर ALU मधून लिहिण्याचे ठिकाण निवडण्यासाठी आणि उर्वरित ठेवण्यासाठी.

मल्टीप्लेक्सर्स ALU इनपुट (ऑपरेंड आणि ऑपरेशन) नियंत्रित करतात, मेमरी कंट्रोलरला सिग्नल (रुंदी, पत्ता, प्रारंभ नियंत्रण आणि वाचन/लेखन) आणि विशेष रजिस्टर: पीसी, आयआर आणि पुनरावृत्ती शिफ्टसाठी एक सहाय्यक काउंटर.

राज्य यंत्राची सुरुवात होते रीसेट करा, पीसीने निर्देशित केलेल्या सूचना मिळवते (४-बाइट रीडिंग), ते तयार झाल्यावर IR मध्ये लोड केले जाते आणि एक्झिक्युशन नोड्समध्ये जाते: ALU (शिफ्ट वगळता १ सायकलमध्ये एक सूचना), लोड/स्टोअर, ब्रँच आणि जंप, तसेच ईब्रेक सारख्या विशेष सूचना.

  विंडोज 10 मध्ये ब्लूटूथ कसे सेट करावे

क्रॉस-टूलचेन, लिंकिंग आणि डीबगिंग

RV32I बायनरी तयार करण्यासाठी, a वापरा क्रॉस GCC (लक्ष्य riscv32-none-elf). तुम्ही C/C++/ASM सोर्सेस कंपाइल करता, मेमरी मॅप परिभाषित करणाऱ्या स्क्रिप्टशी लिंक करता आणि आउटपुटला तुमच्या ROM/FPGA च्या अपेक्षेनुसार रूपांतरित करता.

एक साधी हुक स्क्रिप्ट ठेवू शकते 0x0000 पासून ROM मध्ये .text आणि 0x1004 पासून RAM मध्ये .data (जर 0x1000–0x1003 GPIO रजिस्टर्सनी व्यापलेले असेल तर). स्टार्टअप रूटीन "नॅक" असू शकते आणि RAM च्या शेवटी स्टॅक पॉइंटर (उदा. 0x1FFC) मुख्य कॉल करण्यापूर्वी.

/* Mapa simple
 * ROM: 0x00000000 - 0x00000FFF
 * GPIO: 0x00001000 - 0x00001003
 * RAM: 0x00001004 - 0x00001FFF
 */
SECTIONS {
  . = 0x00000000;
  .text : { *(.startup) *(.text) *(.text.*) *(.rodata*) }
  . = 0x00001004;
  .data : { *(.data) *(.data.*) }
}

riscv32-none-elf-objdump सह तुम्ही हे करू शकता ELF वेगळे करा आणि पत्ते तपासा.; उदाहरणार्थ, तुम्हाला दिसेल की बूट 0x00000000 वर lui/addi/jal सारख्या सूचनांसह आणि तुमच्या मुख्य आवृत्तीवर संक्रमणासह. VHDL सिम्युलेशनसाठी, GHDL असे ट्रेस तयार करते जे तुम्ही GtkWave सह उघडू शकता.

सिम्युलेशनमध्ये पडताळणी केल्यानंतर, डिझाइनला FPGA (क्वार्टस किंवा इतर टूलचेन) वर न्या. जर RAM ला अंतर्गत ब्लॉक्स म्हणून अनुमान लावले असेल आणि कोड स्पष्ट असेल तर RTL, तुम्ही अनुभवी उपकरणांवरही आश्चर्यचकित न होता संश्लेषित केले पाहिजे.

सुरुवात करताना व्यावहारिक आठवणी आणि सामान्य चुका

ते विसरू नका x0 नेहमीच शून्य असते.; त्यावर लिहिल्याने कोणताही परिणाम होत नाही आणि ते वाचल्याने 0 मिळते. जोडण्या, तुलना आणि नोंदणी साफसफाईमध्ये याचा तुमच्या फायद्यासाठी वापर करा.

जेव्हा तुम्ही वैशिष्ट्ये अंमलात आणता, तुम्ही सुधारित केलेले ra आणि sN रेकॉर्ड सेव्ह करा., आणि sp मध्ये शब्द-संरेखित बेरीज/वजाबाकीसह स्टॅक व्यवस्थापित करते. परत आल्यावर, ते उलट क्रमाने पुनर्संचयित होते आणि jr ra सह उडी मारते.

ज्युपिटर सारख्या सिम्युलेटरमध्ये, हे तपासा की __start हे ग्लोबल आहे आणि तुम्ही ते ecall ने संपवता. बरोबर (बाहेर पडण्यासाठी a0=10). जर काहीतरी सुरू झाले नाही, तर लेबल, जागतिकता तपासा आणि पुन्हा कंपाइल करा (F3).

IO सह व्यायामांमध्ये, पर्यावरणाच्या नियमांचे पालन करा: ज्या रजिस्टरमध्ये पॅरामीटर्स, सेवा क्रमांक आणि पत्ता किंवा तात्काळ मूल्य अपेक्षित आहे की नाही हे असते. सिम्युलेटर किंवा ऑपरेटिंग सिस्टम दस्तऐवजीकरण वापरा.

स्पष्ट ISA बेस (RV32I, रजिस्टर्स आणि ABI), ज्युपिटरसारखे आरामदायी सिम्युलेटर आणि वाढत्या उदाहरणांसह (ऋण, घटक, अपरकेस, लूप, फॅक्टोरियल, फिबोनाची आणि हनोई), RISC-V असेंबलर भिंतीसारखे राहणे थांबवतो आणि CPU कसे विचार करतो हे समजून घेण्यासाठी एक रसाळ भूभाग बनतो. आणि जर तुम्ही VHDL वर जाण्याचे धाडस केले तर तुम्हाला दिसेल की ALU, मेमरी आणि कंट्रोल कसे एकत्र बसतात.: सूचना आणणे आणि आळशी लोडिंगपासून ते मेमरी इंटरफेस आणि ROM, RAM आणि GPIO सह नकाशापर्यंत जे तुम्हाला तुमच्या स्वतःच्या प्रोसेसरने LED ब्लिंक करू देते.

कार्यक्रमासाठी सर्वोत्तम कार्यक्रम
संबंधित लेख:
कार्यक्रमासाठी 7 सर्वोत्तम कार्यक्रम