(हे भगवान, किसने .iris को ऐसा प्रोग्राम किया कि उसे कमिट नहीं किया जा सके?)
RISC-V 32-बिट असेंबली में लिखा गया एक टेक्स्ट-आधारित आरपीजी, जिसे QEMU के माध्यम से सिम्युलेट किया गया है।
"ब्रह्मांड ने फैसला किया कि वह मुझसे कुछ बेहतर करने नहीं चाहता, जैसे कि शायद कोई ज़िंदगी जी ले।"
निर्भरताएँ
riscv32-elf-as— RISC-V असेंबलरriscv32-elf-ld— RISC-V लिंकरqemu-riscv32— RISC-V यूज़र-मोड एमुलेटर
आर्च लिनक्स पर:
sudo pacman -S riscv64-elf-binutils qemu-user
बिल्ड और रन करें
make build # main.bin में असेंबल और लिंक करें
make run # qemu-riscv32 के माध्यम से बिल्ड + रन करें
make debug # syscalls की जाँच करने के लिए -strace के साथ रन करें
प्रोजेक्ट संरचना
Extremis/
├── main.s # एंट्री पॉइंट (_start), run_chapter_1 को कॉल करता है
├── src/
│ ├── include/
│ │ └── function.s # startF / endF स्टैक फ्रेम मैक्रोज़
│ ├── engine/
│ │ ├── print.s # print — एक सिंगल नल-टर्मिनेटेड स्ट्रिंग (a0) प्रिंट करें
│ │ └── utils.s # printl — स्ट्रिंग्स की एक सूची प्रिंट करें (a0=पता तालिका, a1=गिनती)
│ ├── chapters/
│ │ └── chapter_1.s # अध्याय 1 का लॉजिक; परिचय स्ट्रिंग्स लोड करता है और printl को कॉल करता है
│ └── dialogue/
│ └── intro.s # परिचय अनुक्रम के लिए स्ट्रिंग डेटा
└── build/ # संकलित .o फ़ाइलें (src/ लेआउट का प्रतिबिंब)
आर्किटेक्चर
इंजन पूरी तरह से RISC-V 32-बिट असेंबली है जो QEMU यूज़र-मोड इम्यूलेशन के माध्यम से लिनक्स ABI को लक्षित करता है।
स्टैक फ्रेम कन्वेंशन
हर फ़ंक्शन स्टैक पर ra, s0, s1, s2 को सेव और रिस्टोर करने के लिए src/include/function.s से startF / endF मैक्रोज़ का उपयोग करता है:
startF # पुश: 16 बाइट आवंटित करें, ra/s0/s1/s2 सहेजें...
endF # पॉप: ra/s0/s1/s2 पुनर्स्थापित करें, 16 बाइट डी-आवंटित करें
ret
सिस्टकॉल्स
चेतावनी: RARS/MARS एनवायरनमेंट कॉल नंबर
qemu-riscv32पर काम नहीं करते हैं। यह प्रोजेक्ट लिनक्स RISC-V ABI सिस्टकॉल नंबरों का उपयोग करता है।
सिस्कॉल नंबर a7 में जाता है, ecall से कॉल करें। रिटर्न वैल्यू a0 में वापस आता है।
आउटपुट
| इरादा | RARS a7 |
लिनक्स a7 |
a0 |
a1 |
a2 |
नोट्स |
|---|---|---|---|---|---|---|
| स्ट्रिंग प्रिंट | 4 |
64 |
1 (स्टैंडर्ड आउटपुट एफडी) |
buf addr | length | लिनक्स null पर नहीं रुकता — byte len पास करें |
| Print char | 11 |
64 |
1 |
char buf | 1 |
मेमोरी में char स्टोर करें, उसका पता पास करें |
| पूर्णांक प्रिंट करें | 1 |
— | पूर्णांक | — | — | कोई लिनक्स समकक्ष नहीं; पहले स्ट्रिंग में बदलें |
| हेक्स पूर्णांक प्रिंट करें | 34 |
— | पूर्णांक | — | — | लिनक्स समकक्ष नहीं है; मैन्युअल रूप से परिवर्तित करें |
| अनसाइन्ड पूर्णांक प्रिंट करें | 36 |
— | पूर्णांक | — | — | लिनक्स समकक्ष नहीं है; मैन्युअल रूप से परिवर्तित करें |
इनपुट
| इरादा | RARS a7 |
लिनक्स a7 |
a0 |
a1 |
a2 |
नोट्स |
|---|---|---|---|---|---|---|
| स्ट्रिंग पढ़ें | 8 |
63 |
0 (stdin fd) |
buf addr | अधिकतम बाइट्स | लिनक्स न्यूलाइन सहित कच्चे बाइट्स लौटाता है |
| कैरेक्टर पढ़ें | 12 |
63 |
0 |
बफ़र पता | 1 |
a0 लौटाता है = पढ़े गए बाइट्स; कैरेक्टर बफ़र में होता है |
| पूर्णांक पढ़ें | 5 |
— | — | — | — | कोई लिनक्स समकक्ष नहीं; स्ट्रिंग पढ़ें, उसे पार्स करें |
प्रक्रिया
| इरादा | RARS a7 |
लिनक्स a7 |
a0 |
टिप्पणियाँ |
|---|---|---|---|---|
| एग्जिट | 10 |
93 |
— | RARS a0 को अनदेखा करता है; लिनक्स इसे एग्जिट स्टेटस के रूप में पढ़ता है |
| एग्जिट(कोड) | 17 |
93 |
एग्जिट कोड | लिनक्स exit_group |
मेमोरी
| इरादा | RARS a7 |
लिनक्स a7 |
a0 |
रिटर्न | नोट्स |
|---|---|---|---|---|---|
| आवंटित (sbrk) | 9 |
214 |
बाइट्स (RARS) / नया brk पता (Linux) | a0 = आवंटित ब्लॉक की शुरुआत |
Linux brk अलग तरह से काम करता है — आप आकार नहीं, बल्कि नया टॉप सेट करते हैं |
फ़ाइल I/O
| इरादा | RARS a7 |
लिनक्स a7 |
a0 |
a1 |
a2 |
a3 |
नोट्स |
|---|---|---|---|---|---|---|---|
| फ़ाइल खोलें | 13 |
56 |
dirfd (-100=CWD) |
फ़ाइलनाम पता | फ़्लैग | मोड | लिनक्स openat का उपयोग करता है |
| फ़ाइल पढ़ें | 14 |
63 |
fd | buf addr | अधिकतम बाइट्स | — | पढ़े गए बाइट्स लौटाता है |
| फ़ाइल लिखें | 15 |
64 |
fd | buf addr | बाइट काउंट | — | लिखे गए बाइट्स लौटाता है |
| फ़ाइल बंद करें | 16 |
57 |
fd | — | — | — | सफलता पर 0 लौटाता है |
समय
| इरादा | RARS a7 |
लिनक्स a7 |
a0 |
a1 |
नोट्स |
|---|---|---|---|---|---|
| समय | 30 |
113 |
क्लॉक आईडी (1=REALTIME) |
timespec* बफ़ |
RARS a0/a1 में विभाजित लो/हाई लौटाता है; Linux बफ़ में स्ट्रक्चर लिखता है |
| स्लीप | 32 |
115 |
क्लॉक आईडी | timespec* |
RARS a0 में मिलीसेकंड लेता है; Linux एक struct के साथ clock_nanosleep का उपयोग करता है |
सामग्री जोड़ना
- नई डायलॉग स्ट्रिंग्स
src/dialogue/में जाती हैं। - नए अध्याय
src/chapters/में जाते हैं और जिन अध्याय फ़ाइलों को उनकी आवश्यकता होती है, उनमें.includeकिए जाते हैं। - मेकफ़ाइल
src/के अंतर्गत सभी.sफ़ाइलों को स्वचालित रूप से खोज लेती है (src/include/को छोड़कर)।
