- AVX-512 का vpternlogd एक SIMD instruction है जो तीन inputs पर मनचाही bitwise Boolean logic को 8-bit immediate value चुनकर एक ही बार में execute करता है
- इसका मूल विचार जटिल logic expressions याद रखना नहीं, बल्कि
#imm8 को तीन inputs A/B/C के 8 possible cases के लिए एक lookup table की तरह देखना है
- 1985 के Amiga blitter में भी तीन bitmap sources और 8-bit minterm के जरिए इसी तरह logic combinations तय किए जाते थे, और masked sprite के लिए
0xE2 अक्सर इस्तेमाल होता था
- result column के 8 bits को नीचे से ऊपर पढ़ने पर immediate value बनती है, इसलिए “तीन inputs में से ठीक दो ही 1 हों” जैसी condition भी सीधे
0x68 के रूप में बनाई जा सकती है
- Intel docs में दिया गया vpternlogd example और Amiga demoscene का आम
0xE2 एक-दूसरे से जुड़ते हैं, और दिखाते हैं कि modern SIMD instructions और retro graphics hardware में एक जैसी design sense मिलती है
AVX-512 का vpternlogd
- vpternlogd AVX-512 ISA design announcement material में नज़र आने वाला एक उल्लेखनीय bitwise ternary logic instruction है
- यह तीन inputs A, B, C लेकर किसी भी Boolean logic को एक instruction में व्यक्त कर सकता है
- उदाहरण:
(NOT A) OR ((NOT B) XOR (C AND A))
- inputs 512-bit registers हो सकते हैं, इसलिए complex logic को पूरे 512 bits पर एक साथ apply किया जा सकता है
foo_and_a_or_not_b जैसे dedicated instructions बार-बार जोड़ने के बजाय, एक flexible instruction और 8-bit immediate value से कई तरह की logic संभाली जाती है
VPTERNLOGD r0, r1, r3, #imm8
#imm8 तय करता है कि कौन-सा bitwise logic function चलाया जाएगा
- कई documents सिर्फ इतना बताते हैं कि immediate value “किसी specific binary function को तय करती है”, इसलिए असली calculation method को सहज रूप से समझना कठिन हो जाता है
Amiga blitter और minterm
- 1980s के computers में graphics processing के लिए custom chips का इस्तेमाल आम था
- Commodore Amiga 500 का blitter bitmap graphics को एक जगह से दूसरी जगह ले जाते समय logic operations apply करता था
- यह अधिकतम तीन bitmap sources को संभालता था, और उनके बीच की logic operation 8-bit value minterm से तय की जाती थी
- तीन sources और 8-bit value से logic combination चुनने के लिहाज़ से इसकी संरचना vpternlogd जैसी ही है
- कई Amiga programmers minterm calculation को सीधे समझने के बजाय अक्सर इस्तेमाल होने वाली values दोबारा उपयोग करते थे
- buffer साफ़ करने के लिए
0x00
- masked sprite draw करने के लिए
0xE2
- 1989 की “Amiga Hardware Reference Manual” ने minterm calculation को उलझे हुए symbols से समझाया था, इसलिए उस समय demo बनाने वालों के लिए यह ज़्यादा मददगार नहीं थी
8-bit value को lookup table की तरह निकालना
#imm8 या minterm को logic operators के combination की तरह नहीं, बल्कि 8 entries वाली lookup table की तरह देखा जा सकता है
- तीन inputs A, B, C में से हर एक 0 या 1 हो सकता है, इसलिए कुल 8 possible combinations होते हैं
- आपको बस चौथे column में चाहा गया result सीधे भरना है
| A |
B |
C |
वांछित result |
| 0 |
0 |
0 |
? |
| 0 |
0 |
1 |
? |
| 0 |
1 |
0 |
? |
| 0 |
1 |
1 |
? |
| 1 |
0 |
0 |
? |
| 1 |
0 |
1 |
? |
| 1 |
1 |
0 |
? |
| 1 |
1 |
1 |
? |
- उदाहरण के लिए, अगर आप चाहते हैं कि तीन inputs में ठीक दो ही 1 होने पर result 1 बने, तो चौथे column में उसी condition के मुताबिक values भरें
- फिर उस result column के 8 bits को नीचे से ऊपर पढ़ने पर
01101000, यानी 0x68 मिलता है
- इसलिए
0x68 function तीन inputs में ठीक दो inputs के 1 होने पर result को 1 सेट करता है
- इसी तरीके से तीन sources के बीच किसी भी logic function के लिए ज़रूरी
#imm8 value निकाली जा सकती है
masked sprite का 0xE2
- Amiga में बहुत आम minterm values में से एक
0xE2 है
- यह value masked 2D sprite render करते समय अक्सर इस्तेमाल होती है
- A: sprite bitmap
- B: sprite mask
- C: background
- इस condition को एक सरल program logic की तरह व्यक्त किया जा सकता है
- अगर mask pixel B set है, तो result sprite A होगा
- अगर mask pixel B set नहीं है, तो result background C होगा
| A |
B |
C |
वांछित result |
| 0 |
0 |
0 |
0 |
| 0 |
0 |
1 |
1 |
| 0 |
1 |
0 |
0 |
| 0 |
1 |
1 |
0 |
| 1 |
0 |
0 |
0 |
| 1 |
0 |
1 |
1 |
| 1 |
1 |
0 |
1 |
| 1 |
1 |
1 |
1 |
- result column को नीचे से ऊपर पढ़ने पर
11100010, यानी 0xE2 मिलता है
0xE2 Amiga demoscene culture में बहुत आम minterm value है
Intel docs से एक दिलचस्प जुड़ाव
1 टिप्पणियां
Hacker News टिप्पणियाँ
जिस expression की गणना करनी है, उससे immediate value निकालने का एक आसान तरीका है। उदाहरण के लिए, अगर आप
(NOT A) OR ((NOT B) XOR (C AND A))निकालना चाहते हैं, तो इसे~_MM_TERNLOG_A | (~_MM_TERNLOG_B ^ (_MM_TERNLOG_C & _MM_TERNLOG_A))की तरह लिख सकते हैंयह शाब्दिक रूप से वही expression है जिसकी गणना करनी है, और gcc तथा clang के intrinsic headers में परिभाषित
_MM_TERNLOG_A/B/Cconstants से immediate value के रूप में evaluate हो जाता है:typedef enum { _MM_TERNLOG_A = 0xF0, _MM_TERNLOG_B = 0xCC, _MM_TERNLOG_C = 0xAA } _MM_TERNLOG_ENUM;MSVC में इसे सीधे define किया जा सकता है
A = 0b11110000,B = 0b11001100,C = 0b10101010सिर्फ शीर्षक देखकर मुझे लगा था कि इसका मतलब यह है कि यह instruction ठीक से काम नहीं करता। असली लेख तो बस इसके काम करने के तरीके को समझाता है
अपनी किशोरावस्था में मैंने hardware manual के उस पेज पर “CRAP!” तो नहीं लिखा था, लेकिन उसे समझने की कोशिश में बहुत देर तक घूरता रहा था
आख़िर में, लगभग सभी की तरह, मैंने Bobs और साधारण copy operations के लिए BLTCON0 lookup करके इस्तेमाल किया, और उस हिस्से को अनदेखा कर दिया
फिर भी कुछ साल बाद विश्वविद्यालय में computational logic में A+ मिला, तो शायद उस trauma ने कुछ मदद की होगी
शीर्षक की बात करें तो, “ternary logic” का मतलब आम तौर पर तीन truth values वाली logic होता है। लेकिन यह लेख ऐसे compiler instruction पर है जो तीन inputs लेने वाले सभी binary logic gates को संभालता है
ternlogहै और intrinsic भीternarylogicहै, इसलिए थोड़ी असहजता के बावजूद शीर्षक उचित हैऊपर से
bitwiseपहले ही कुछ हद तक इसे “three-valued logic” से अलग करता है, औरternaryका इस्तेमाल “three-input” के अर्थ में भी बहुत आम है।a ? b : cको भी अक्सर ternary operator कहा जाता है, और वास्तव मेंternlogउस ternary operation की नकल कर सकता है; लेख भी उसी पर बात करता हैternaryनहीं बल्किtrinaryथाC++, JavaScript और Python के नज़रिए से
(a < b) ? 5 : 2जैसी ternary expression ही सबसे सामान्य usage लगती है। https://www.programiz.com/cpp-programming/ternary-operatorखैर, कोई भी धारणा लें, बहुत फ़र्क नहीं पड़ता। शब्दों और वाक्यांशों के कई अर्थ होते हैं, और
ternaryका अर्थ तीन भागों से बना हुआ भी है, इसलिए यहाँ भी यह फिट बैठता हैternaryका वही मतलब नहीं हैC में
+दो inputs लेता है, इसलिए वह binary operator है, और?:तीन inputs लेता है, इसलिए वह ternary operator है। C में वह अकेला है, इसलिए आम तौर पर उसे “the ternary operator” कहा जाता है, पर अपने स्वभाव में वह कोई विशेष अपवाद नहीं हैvpternlogdतीन inputs लेने वाले सभी bitwise ternary operators को implement करता हैमुझे लगा यह शायद Windows के
BitBltfunction जैसा कुछ है। कम से कम Windows 3.1 के समय से तो था ही, औरopparameter से यह तय होता था कि source, destination, mask को कैसे combine करना हैमुझे याद है कि ऐसे code names थे जैसे input से परे काला बनाने वाला
BLACKNESS, या source को destination पर copy करने वालाCOPY।BLACKNESSऔरWHITENESSमें किसी तरह की काव्यात्मक गूँज थीPetzold में पढ़ा था कि यह software में implement था, लेकिन call के समय opcode function के अंदर custom assembly में translate हो जाता था, इसलिए Windows OS में self-modifying code का एक दुर्लभ उदाहरण था
BitBltमूल रूप से binary operations को reverse Polish notation में store करने वाले जटिल 16-bit “operation codes” इस्तेमाल करता थाबाद में Amiga की तरह उसी जानकारी को 1 byte में रखने वाला “operation index” जोड़ा गया, जो छोटा और अधिक सुघड़ है। अब हर raster operation code में operation index और operation code दोनों ही भरे होते हैं, इसलिए encoding दोहराव वाली हो गई है। https://devblogs.microsoft.com/oldnewthing/20180528-00/?p=98...
यह वैसा ही है जैसे FPGA किसी मनचाहे logic function को lookup table के रूप में implement करता है
बस FPGA या इस लेख की instruction जैसी special-purpose स्थितियों को छोड़ दें, तो आम तौर पर ऐसा नहीं किया जाता। high-speed registers और static RAM कभी-कभी logic से बनाए जाते हैं, लेकिन gates की बजाय सीधे transistors से बनाना ज़्यादा आम है
74181arithmetic logic unit भी ऐसा ही करता हैhttps://www.sandpile.org पर जाएँ और 3-byte opcode पेज https://www.sandpile.org/x86/opc_3.htm में
VPTERNLOGखोजें, तो आपको AVX512BITALG2 भी दिखेगा, जो शायद Intel द्वारा पहले कभी योजनाबद्ध byte/word masking variant थावहाँ से
Iboperand में मौजूद सभी 256 cases वाली ternary logic table के पेज https://www.sandpile.org/x86/ternlog.htm का लिंक भी मिलता हैdocumentation example में
E2function शायद इसलिए चुना गया, क्योंकि तीन-input boolean functions में यह लगभग सबसे बुनियादी और मानक mux है:Bहो तोA, नहीं तोCयह एक universal function है, इसलिए इसे चुनने के लिए Amiga fan होना ज़रूरी नहीं। हालाँकि हो सकता है वे सचमुच fan रहे हों
integer में bitwise operations भरने का एक और उदाहरण Win32 के GDI ROP codes हैं: https://learn.microsoft.com/en-us/windows/win32/gdi/ternary-...
आधिकारिक Amiga hardware manual तो नहीं था, उसकी जगह मैंने “Mapping the Amiga” किताब देखी थी। उसमें वही बात थोड़ी ज़्यादा विस्तार से समझाई गई थी
उस समय कौन-से minterms इस्तेमाल किए थे, यह याद नहीं, लेकिन लगता है इसी किताब को देखकर मैंने किसी तरह shadebobs, bobs, XOR 3D line drawing जैसी चीज़ें implement की थीं
Mapping the Amiga का संबंधित पेज: https://archive.org/details/1993-thomson-randy-rhett-anderso...