- Box64 का RV64 DynaRec एक साल पहले केवल साधारण native Linux गेम चलाने के स्तर पर था, लेकिन अब यह RISC-V PC पर The Witcher 3 चलाने तक पहुँच गया है
- इस प्रगति का बड़ा कारण AMD ग्राफिक्स कार्ड के उपयोग की सुविधा मिलना रहा, जिससे OpenGL की सीमाएँ घटीं और अधिक x86 प्रोग्राम टेस्ट करके बग ठीक करना संभव हुआ
- RV64 backend में ARM64 backend की तुलना में लागू किए गए x86 निर्देश कम हैं, और AVX निर्देश भी अभी RISC-V पक्ष के लिए बड़ा अधूरा काम हैं
- RISC-V में bit range extraction·insertion और 16-byte atomic instructions की कमी है, इसलिए x86 emulation में AArch64 या LoongArch64 की तुलना में translation cost अधिक है
- The Witcher 3 वास्तव में box64 पर चलता है, गेम के भीतर अधिकतम 15fps तक पहुँचता है, और main menu में full-speed हासिल करता है
RISC-V पर The Witcher 3 के चलने तक की यात्रा
- एक साल पहले RV64 DynaRec केवल Stardew Valley, World of Goo जैसे अपेक्षाकृत आसानी से चलने वाले native Linux गेम ही चला पाता था
- उस समय bottleneck मुख्य रूप से दो थे
- RISC-V backend में x86_64 निर्देशों को तेज़ी से जोड़ने की प्रक्रिया के दौरान बहुत से DynaRec bugs बाकी थे
- VisionFive 2 और LicheePi 4A के IMG integrated GPU केवल OpenGL ES को सपोर्ट करते थे और OpenGL को सपोर्ट नहीं करते थे
- gl4es के जरिए कुछ OpenGL सपोर्ट मिल जाने से Stardew Valley जैसे गेम चल सके, लेकिन भारी Linux गेम और सामान्य Windows गेम के लिए यह पर्याप्त नहीं था
- Sophgo का Milk-V Pioneer 64-core RISC-V PC है, जो ग्राफिक्स कार्ड लगाने के लिए PCIe slot देता है
- एक अन्य contributor xctan ने VisionFive 2 में M.2 interface के जरिए AMD ग्राफिक्स कार्ड को “कनेक्ट” करने का तरीका खोजा
- AMD ग्राफिक्स कार्ड का उपयोग संभव होने के बाद टेस्ट किए जा सकने वाले x86 प्रोग्रामों की सीमा बढ़ी, और RV64 DynaRec bugs को ठीक करने तथा x86 निर्देश जोड़ने का काम बड़े पैमाने पर हुआ
- नतीजतन The Witcher 3 पहली बार चलाने पर ही काम कर गया
RV64 DynaRec की मौजूदा स्थिति
- x86 instruction set बहुत बड़ा है, और backend के अनुसार implementation का पैमाना भी अलग है
- ARM64 backend में कुल मिलाकर 1,600 से अधिक x86 निर्देश लागू हैं
- RV64 backend में लगभग 1,000 x86 निर्देश लागू हैं
- इनमें 300 से अधिक नए सपोर्ट किए गए AVX निर्देश हैं, जो RISC-V में अभी बिल्कुल लागू नहीं हुए हैं
- SSE निर्देशों के implementation में भी RISC-V प्रदर्शन के लिहाज़ से कमजोर है
- RV64 backend SSE निर्देशों को scalar instructions के रूप में लागू करता है
- AArch64 Neon extension का उपयोग करता है, और LoongArch64 LSX extension का
- इस अंतर के कारण प्रदर्शन अन्य दो backends की तुलना में काफी कम है
- RISC-V में vector extension RVV मौजूद है
- Milk-V Pioneer, RVV 0.7.1 के एक variant xtheadvector extension को सपोर्ट करता है
- SpacemiT K1/M1 SoC ratified RVV 1.0 को सपोर्ट करता है
- इस SoC वाले Banana Pi F3 और Milk-V Jupiter खरीदे जा सकते हैं
- box64 में हाल ही में बुनियादी RVV सपोर्ट और कुछ सामान्य SSE निर्देशों का implementation जोड़ा गया है
- RVV पर काम अभी बहुत शुरुआती चरण में है, इसलिए फिलहाल इससे performance improvement में मदद नहीं मिलती
x86 emulation के लिए खास तौर पर कमी वाले RISC-V निर्देश
- x86 emulation के नज़रिए से RISC-V, सपोर्ट की जाने वाली तीन architectures में सबसे कम expressive है
- AArch64 और LoongArch64 की तुलना में इसमें सुविधाजनक निर्देश कम हैं, इसलिए वही काम emulate करने के लिए अधिक निर्देशों की ज़रूरत पड़ती है
- खास तौर पर दो महत्वपूर्ण सुविधाएँ नहीं हैं
- एक register से किसी खास bit range को चुनकर दूसरे register में लाने की सुविधा
- एक register के कुछ bits को दूसरे register की किसी खास range में insert करने की सुविधा
- LoongArch64 और AArch64 में इसके लिए संबंधित निर्देश मौजूद हैं
- LoongArch64
BSTRPICK.DऔरBSTRINS.Dका उपयोग करता है - ARM64
UBFXऔरBFIopcode का उपयोग करता है
- LoongArch64
- RISC-V में official extensions या vendor extensions, किसी में भी इसके अनुरूप निर्देश नहीं हैं
ADD AH, BL उदाहरण से दिखने वाली translation cost
- x86 ISA बदले बिना छोड़े गए bits को सुरक्षित रखने की प्रवृत्ति रखता है, इसलिए partial register manipulation महत्वपूर्ण है
ADD AH, BLके मामले में box64 को ये काम करने पड़ते हैंRBXका सबसे निचला byte निकालना- उसे
RAXके दूसरे सबसे निचले byte में जोड़ना - परिणाम को फिर
RAXके दूसरे सबसे निचले byte में insert करना RAXके बाकी bytes को जस का तस बनाए रखना
- LoongArch64 में
BSTRPICK.D,ADD,BSTRINS.Dकी मदद से इसे सरल और सीधा लागू किया जा सकता है - RISC-V में वही काम shifts, masks,
AND,ORआदि के संयोजन से करना पड़ता है, इसलिए 10 निर्देशों की ज़रूरत होती है - ऐसे मामले अलग-थलग नहीं हैं; x86 में इस तरह के कई निर्देश हैं, इसलिए RISC-V implementation अधिक झंझटभरा है
16-byte atomic instructions की सीमा
- x86 में lock-free atomic operations के लिए LOCK prefix instructions होते हैं
- box64 मुख्य रूप से LR/SC sequence से इनका emulation करता है
- LR/SC का मतलब Load-Reserved / Store-Conditionally है
- उदाहरण के लिए
LOCK ADD [RAX], RCXकोLR.D,ADD,SC.D, conditional branch के रूप में बनाया जाता है
- अगर
RAXaddress aligned न हो तो मामला और जटिल हो जाता है, लेकिन सामान्यतः यह तरीका अच्छी तरह काम करता है - समस्या
LOCK CMPXCHG16Bमें है- यह निर्देश
RDX:RAXकी तुलना memory के 16 bytes से करता है - शर्त के अनुसार
RCX:RBXको उस memory address पर swap करता है
- यह निर्देश
- AArch64 और LoongArch64 में implementation के लिए कुछ 16-byte atomic instructions उपलब्ध हैं
- RISC-V में इसके अनुरूप निर्देश नहीं हैं, इसलिए इसे अन्य architectures जितना पूर्ण रूप से लागू नहीं किया जा सकता
- Unity गेम्स सहित कई प्रोग्राम
LOCK CMPXCHG16Bका उपयोग करते हैं
वास्तविक रनिंग परिणाम
- सीमाएँ बाकी होने के बावजूद The Witcher 3, box64 के जरिए RISC-V पर चलता है
- प्रदर्शन गेम के भीतर अधिकतम 15fps तक पहुँचता है
- main menu में यह full-speed पर चलता है
- ऐसी मशीन के लिए, जिसे AAA गेम चलाने के उद्देश्य से डिज़ाइन नहीं किया गया था, यह परिणाम बुरा नहीं है
1 टिप्पणियां
Hacker News की राय
चिप वाली तरफ काम न करने वाले व्यक्ति के तौर पर जिज्ञासा है कि RISC-V के लिए software बनाते समय software engineer को अलग क्या करना पड़ता है
लगता है executable file का size बढ़ जाता होगा, इसलिए cache locality को aggressively optimize करना पड़ता होगा; और यह भी जानना है कि games या web servers जैसी software categories में कुछ CISC/RISC में से किसी एक के लिए ज्यादा फिट होती हैं या नहीं
software approach में मूल रूप से बदलने लायक बहुत कुछ नहीं है, और x86-64 की तुलना में सबसे बड़ा फर्क यह है कि registers 32 हैं, इसलिए stack में spill होने से पहले ज्यादा intermediate values रखी जा सकती हैं; ARM में भी 32 हैं, इसलिए वह भी मिलता-जुलता है। आम तौर पर जब तक micro-optimization नहीं कर रहे हों, इस पर ज्यादा ध्यान देने की जरूरत नहीं होती
और detail में जाएँ तो vector extension (V/RVV) default rv64gc ISA में नहीं है, इसलिए target के हिसाब से SIMD optimization नहीं मिल सकता; और popcount तथा leading/trailing zero count भी default rv64gc में नहीं हैं, इनके लिए Zbb चाहिए। साथ ही
a ? b : cजैसी branchless selection भी default rv64gc में 4–5 instructions, Zicond के साथ 3 instructions मांगती है, जबकि x86-64 और aarch64 में यह 1 instruction में हो जाता हैRISC-V profiles पहले दो issues को कुछ हद तक solve करते हैं। जैसे Android RVV, Zbb, Zicond आदि की मांग करने वाला rva23 require करता है। लेकिन अगर Linux distribution rva20/rv64gc को target करे, तो dynamically dispatch न करने वाले precompiled code में ऐसे extensions को practical तौर पर लंबे समय तक इस्तेमाल नहीं किया जा सकेगा। x86-64 में भी ऐसा ही issue है, लेकिन ARM में extensions काफी कम हैं, इसलिए समस्या कम है; SVE सबसे बड़ा exception है, पर अभी widely supported नहीं है
सबसे बड़ा फर्क weak memory model है, लेकिन यह ARM जैसी ज्यादातर non-x86 architectures में भी होता है, और code को शुरू से ही strong memory model पर depend नहीं करना चाहिए
executable code density में historical कारणों से x86 बहुत अच्छा नहीं है, इसलिए executable file size उतना नहीं बढ़ता जितना लगता है। compressed instruction extension वाला RISC-V और Thumb extension वाला 32-bit ARM काफी dense हैं
अहम बात CISC बनाम RISC नहीं, बल्कि vector instructions और cryptography extensions की मौजूदगी और quality है। video encoding/decoding अच्छी performance के लिए vector instructions पर बहुत depend करता है, और full disk encryption या hashing को AES, SHA256 जैसे specific algorithms accelerate करने वाले dedicated instructions से मदद मिल सकती है
असल बात ARM patents से मुक्त होना और सीखे गए lessons के आधार पर नई शुरुआत करना ज्यादा है
याद आता है कि एक मशहूर रूसी व्यक्ति ने Elbrus 8S पर Atomic Heart चलाया था
Elbrus में native translator है और मेरी जानकारी में वह काफी ठीक है। Atomic Heart करीब 15–25fps पर कुछ हद तक playable था
लेख में “basic” explanation थोड़ी कम है। मुझे लगा था कि इसे Wine port जैसी किसी चीज से चलाया गया होगा, लेकिन असल में ऐसा लगता है कि RISC-V chip के ऊपर किसी तरह से x86_64 ISA implement किया गया है
अच्छा होगा अगर कोई समझा सके कि वह हिस्सा कैसे काम करता है
यह emulator तो है, लेकिन libc, libm, SDL, OpenGL जैसी कुछ “system” libraries के native versions इस्तेमाल करता है, इसलिए ज्यादातर applications के साथ integrate करना आसान है, और कुछ मामलों में performance भी हैरान करने लायक high हो सकती है। Wine को भी native compile करके चलाया जा सकता है
कमाल का result है। बहुत बड़ा काम है, और कुछ मामलों में लगता है कि यह RISC-V की limits को छू रहा है
bit gather/scatter instructions को extension में जाना चाहिए लगता है
x86 emulation के संदर्भ में जिन 3 architectures को support किया जाता है, उनमें RISC-V का सबसे कम expressive होना दिलचस्प है
Computer science history की क्लास में हमने RISC को reduced instruction set computer के रूप में पढ़ा था, लेकिन आजकल RISC-V profiles के प्रस्तावों या लेखों को देखें तो अक्सर बात ऐसी होती है कि “feature parity के लिए बस कुछ और instructions चाहिए।” मैं समझता हूं कि RISC-V कई लोगों के लिए दूसरे platforms का सुविधाजनक विकल्प है, लेकिन यह भी सोचता हूं कि क्या इसका मतलब है कि RISC का सपना मर गया है
RISC-V specification पढ़ने की मेरी याद के मुताबिक, वह “combo” instructions जोड़ने को लेकर काफ़ी strict था, क्योंकि आम instruction sequences को front-end में fuse किया जा सकता है
x86/ARM की तुलना में RISC-V की कमी शायद RISC fundamentalism की वजह से नहीं, बल्कि इसलिए है कि specification ने बहुत basic embedded chips से शुरुआत की और समय के साथ application CPUs के लिए extensions जोड़े। basic RV32I में integer multiplication तक नहीं है। दुर्भाग्य से bit manipulation और SIMD/vector extensions की बहस खत्म करने में बहुत ज़्यादा समय लगा, और नतीजतन आज जिन feature gaps की बात हो रही है वे पैदा हुए
हालांकि इसी वजह से high performance के लिए सुविधाजनक कुछ instructions बाहर रह जाते हैं
simple pipeline का एक फायदा यह भी है कि high-performance design करने वाली team के engineering resources कम लगते हैं, जिससे optimization पर ज़्यादा समय लगाया जा सकता है
RISC मोटे तौर पर simplification philosophy है, लेकिन उसका स्तर अलग-अलग होता है। MIPS, RISC-V जितना simplified है, लेकिन ARM और POWER ज़्यादा pragmatic compromise करते हैं, और high-performance क्षेत्र में x86 से मुकाबला करने में उन्हें कोई बड़ी दिक्कत नहीं दिखती
processor के market में application execution के अलावा embedded, accelerators जैसी कई niches भी हैं। application core नाम की खास niche में मैं RISC-V को लेकर थोड़ा pessimistic हूं, लेकिन व्यापक रूप से देखें तो इसकी potential बड़ी है, कुछ commercial niches पर dominate करने की संभावना भी है, और education व research tools के रूप में यह शानदार है
classical RISC की खासियत यह है कि ज़्यादातर data manipulation instructions सिर्फ registers पर काम करते हैं, memory instructions आम तौर पर registers में load/store तक सीमित होते हैं, और इसलिए बहुत सारे registers चाहिए होते हैं। parameters pass करने के लिए stack को सीधे manipulate करना पड़ता है, इसलिए stack भी खुद बनता है, और CALL/JSR instructions के बिना instruction pointer register पर सीधे load/store करने वाली basic instructions से इसे implement किया जाता है। instruction encoding predictable होती है और सभी instructions का size समान होता है। कई RISC architectures में ऐसा register भी था जिसे हमेशा 0 पढ़ा जाता था और लिखा नहीं जा सकता था, और values को 0 पर set करने में इस्तेमाल होता था
यह तरीका काम आया, लेकिन बाद में out-of-order execution और SIMD ने इसकी अहमियत घटा दी। raw instruction stream desired result तक पहुंचने के रास्ते की declaration जैसा है; इसका मतलब यह नहीं कि CPU सचमुच उसे वैसा ही execute करता है। उसके पीछे speculative execution, branch prediction और register renaming होते हैं। SIMD wide register space और उसके भीतर सभी values पर काम करने वाली instructions के करीब है। आखिरकार out-of-order execution और SIMD ने lead ले ली
theory में original source code को RISC के लिए compile करें तो पूरी तरह अलग binary बनेगी, और उन specific instructions की जरूरत नहीं पड़ सकती
practical तौर पर, शायद कोई इन games को सचमुच RISC-V के लिए compile नहीं करेगा
screenshot में RAM 31GB दिख रही है, जो बताए गए development board की maximum spec से साफ़ तौर पर ज़्यादा है। क्या यहां कुछ और इस्तेमाल हो रहा है?
आज के समय में RVA22 और RVV 1.0 implement करने वाले कई तेज cores वाले नए options में से कोई एक इस्तेमाल करना बेहतर होगा
क्या यह 86Box है? Amstrad PC1512 खरीदने वाले दिनों को याद करना मज़ेदार था
500MB hard card के 2 units और 128KB memory expansion जोड़कर 640KB कर दिया था, तो यह कहीं ज़्यादा मज़ेदार हो गया। शुरुआत में सिर्फ दो 360KB floppies थीं, और कुछ साल बाद 32MB hard card जोड़ा था। Borland TurboPascal और Zortech C भी थे। अच्छे दिन थे
फिर भी Amstrad PC1512 इस्तेमाल करने वाले दिन याद हैं
सोचता हूं कि क्या कभी ऐसा system आएगा जिसमें कुछ बड़े RISC-V CPUs के साथ, छोटे RISC-V CPUs के झुंड से implement किया गया “GPU” भी होगा
शायद यह उचित vector features के साथ होगा, लेकिन side question के तौर पर यह भी जानना चाहता हूं कि packed SIMD के बजाय classical vector approach GPU में उपयोगी हो सकती है या नहीं
technically impressive Witcher 3 achievements में Switch port भी था, और वह सचमुच अच्छी तरह चलता था
यह दिखाता है कि optimization से कितना कुछ किया जा सकता है, और PC पर bad optimization की वजह से कितने resources waste होते हैं
यह apples-to-apples comparison नहीं है, और screen पर दिखने वाली range काफ़ी अलग है, इसलिए PC की bad optimization को तय मानना मुश्किल है
अच्छा होगा अगर इस तरह का ISA-स्तर का feedback RVI के लोगों तक पहुँचे
कल चेक किया तो [1], लेख का example पहले ही 4 RISC-V instructions से किया जा सकता है। हालांकि इसे सोच पाना थोड़ा मुश्किल है
# a0 = rax, a1 = rbxslli t0, a1, 64-8rori a0, a0, 16add a0, a0, t0rori a0, a0, 64-16[1] https://www.reddit.com/r/RISCV/comments/1f1mnxf/box64_and_ri...
सच में, bitfield extract का छूट जाना इतनी साफ़ गलती है कि RISC-V ISA कितना बेतुका है, यह दिखाने वाला मेरा पसंदीदा example यही है। दूसरा है ढंग के addressing modes का न होना
कुछ बेहतर RISC-V designs ने इसके लिए सचमुच custom instructions implement किए हैं। उदाहरण के लिए Hazard3 का BEXTM है: https://github.com/Wren6991/Hazard3/blob/stable/doc/hazard3....