पृष्ठभूमि
मुझे अपनी पुरानी 8-बिट 6502 चिप पसंद है। 6502 मशीन कोड में PPCG पर यहाँ की कुछ चुनौतियों को हल करना और भी मज़ेदार है। लेकिन कुछ चीजें जो सरल होनी चाहिए (जैसे, डेटा या स्टडआउट में पढ़ा जाता है) मशीन कोड में करने के लिए अनावश्यक रूप से बोझिल हैं। तो मेरे दिमाग में एक मोटा विचार है: अपनी खुद की 8-बिट वर्चुअल मशीन का आविष्कार करें जो 6502 से प्रेरित है, लेकिन डिजाइन के साथ चुनौतियों के लिए अधिक उपयोगी होने के लिए संशोधित किया गया है। कुछ को लागू करने के लिए शुरू, मुझे एहसास हुआ कि यह एक अच्छी चुनौती हो सकती है यदि VM का डिज़ाइन एक न्यूनतम न्यूनतम तक कम हो :)
कार्य
निम्नलिखित विनिर्देश के अनुरूप 8-बिट वर्चुअल मशीन को लागू करें। यह कोड-गोल्फ है , इसलिए सबसे कम बाइट्स जीत के साथ कार्यान्वयन।
इनपुट
आपके कार्यान्वयन को निम्नलिखित इनपुट लेने चाहिए:
एक एकल अहस्ताक्षरित बाइट
pc
, यह प्रारंभिक प्रोग्राम काउंटर है (मेमोरी में पता जहां वीएम निष्पादन शुरू करता है,0
-based)256
प्रविष्टियों की अधिकतम लंबाई के साथ बाइट्स की एक सूची , यह वर्चुअल मशीन के लिए रैम है (इसकी प्रारंभिक सामग्री के साथ)
आप इस इनपुट को किसी भी समझदार प्रारूप में ले सकते हैं।
उत्पादन
वीएम समाप्त होने के बाद बाइट्स की एक सूची जो रैम की अंतिम सामग्री है (नीचे देखें)। आप मान सकते हैं कि आपको केवल इनपुट मिल सकता है जो अंततः समाप्त होता है। किसी भी समझदार प्रारूप की अनुमति है।
वर्चुअल सीपीयू
वर्चुअल CPU है
- 8-बिट प्रोग्राम काउंटर,
- 8-बिट संचायक रजिस्टर कहा जाता है
A
और - 8-बिट इंडेक्स रजिस्टर कहा जाता है
X
।
तीन स्थिति ध्वज हैं:
Z
- शून्य ध्वज को कुछ ऑपरेशन के परिणाम के बाद सेट किया गया है0
N
- एक नकारात्मक संख्या में कुछ ऑपरेशन के परिणाम के बाद नकारात्मक ध्वज सेट किया गया है (परिणाम का iow बिट 7 सेट किया गया है)C
- कैरी फ़्लैग को परिणाम के "लापता" बिट के लिए परिवर्धन और बदलाव द्वारा निर्धारित किया जाता है
शुरू करने पर, झंडे सब साफ़ हो जाते हैं, प्रोग्राम काउंटर किसी दिए गए मूल्य और की सामग्री के लिए सेट है A
और X
अनिश्चित है।
8-बिट मान या तो प्रतिनिधित्व करते हैं
- रेंज में एक अहस्ताक्षरित पूर्णांक
[0..255]
- एक हस्ताक्षरित पूर्णांक, 2 का पूरक, सीमा में
[-128..127]
संदर्भ के आधार पर। यदि कोई ऑपरेशन ओवरफ्लो करता है या कम होता है, तो मान चारों ओर घूमता है (और इसके अलावा, कैरी फ्लैग प्रभावित होता है)।
समाप्ति
वर्चुअल मशीन कब समाप्त होती है
- एक
HLT
निर्देश पहुँच जाता है - एक गैर-मौजूदा मेमोरी एड्रेस एक्सेस किया जाता है
- प्रोग्राम काउंटर मेमोरी के बाहर चलता है (ध्यान दें कि यह चारों ओर लपेटता नहीं है, भले ही वीएम को मेमोरी के पूर्ण 256 बाइट्स दिए गए हों)
अनुकूल करने की विधा
- निहित - निर्देश का कोई तर्क नहीं है, ऑपरेंड निहित है
- तत्काल - ऑपरेंड निर्देश के बाद सीधे बाइट है
- सापेक्ष - (केवल शाखा के लिए) निर्देश पर हस्ताक्षर होने के बाद बाइट (2 का पूरक) और शाखा निर्धारित होने पर प्रोग्राम काउंटर में जोड़ने के लिए ऑफसेट निर्धारित करता है।
0
निम्नलिखित निर्देश का स्थान है - निरपेक्ष - निर्देश के बाद बाइट ऑपरेंड का पता है
- अनुक्रमित - निर्देश प्लस
X
(रजिस्टर) के बाद बाइट ऑपरेंड का पता है
अनुदेश
प्रत्येक निर्देश में एक ओपोड (एक बाइट) होता है और, संबोधन मोड में तत्काल , सापेक्ष , निरपेक्ष और एक दूसरे तर्क बाइट को अनुक्रमित किया जाता है। जब वर्चुअल सीपीयू एक निर्देश निष्पादित करता है, तो यह प्रोग्राम काउंटर को तदनुसार ( 1
या 2
) बढ़ाता है ।
यहाँ दिखाए गए सभी ऑपकोड हेक्स में हैं।
LDA
- लोड ऑपरेंड मेंA
- Opcodes: तत्काल:,
00
पूर्ण:,02
अनुक्रमित:04
- झंडे:
Z
,N
- Opcodes: तत्काल:,
STA
-A
ओपेरा में स्टोर करें- Opcodes: तत्काल:,
08
पूर्ण:,0a
अनुक्रमित:0c
- Opcodes: तत्काल:,
LDX
- लोड ऑपरेंड मेंX
- Opcodes: तत्काल:,
10
पूर्ण:,12
अनुक्रमित:14
- झंडे:
Z
,N
- Opcodes: तत्काल:,
STX
-X
ओपेरा में स्टोर करें- Opcodes: तत्काल:,
18
पूर्ण:,1a
अनुक्रमित:1c
- Opcodes: तत्काल:,
AND
- बिटवाइज़ और कीA
और संकार्य मेंA
- Opcodes: तत्काल:,
30
पूर्ण:,32
अनुक्रमित:34
- झंडे:
Z
,N
- Opcodes: तत्काल:,
ORA
- बिटवाइज़ या कीA
और संकार्य मेंA
- Opcodes: तत्काल:,
38
पूर्ण:,3a
अनुक्रमित:3c
- झंडे:
Z
,N
- Opcodes: तत्काल:,
EOR
- का बिटवाइस xor (एक्सक्लूसिव या)A
और ऑपरेंडA
- Opcodes: तत्काल:,
40
पूर्ण:,42
अनुक्रमित:44
- झंडे:
Z
,N
- Opcodes: तत्काल:,
LSR
- लॉजिकल शिफ्ट राइट, ऑपरेंड के सभी बिट्स को एक स्थान पर दाईं ओर शिफ्ट करें, बिट 0 ले जाने के लिए जाता है- Opcodes: तत्काल:,
48
पूर्ण:,4a
अनुक्रमित:4c
- झंडे:
Z
,N
,C
- Opcodes: तत्काल:,
ASL
- अंकगणित पारी छोड़ दिया, ऑपरेंड के सभी बिट्स को बाईं ओर एक स्थान पर स्थानांतरित करें, बिट 7 ले जाने के लिए जाता है- Opcodes: तत्काल:,
50
पूर्ण:,52
अनुक्रमित:54
- झंडे:
Z
,N
,C
- Opcodes: तत्काल:,
ROR
- दाईं ओर घुमाएं, ऑपरेंड के सभी बिट्स को एक स्थान पर दाईं ओर शिफ्ट करें, कैरी 7 पर जाता है, बिट 0 ले जाने के लिए जाता है- Opcodes: तत्काल:,
58
पूर्ण:,5a
अनुक्रमित:5c
- झंडे:
Z
,N
,C
- Opcodes: तत्काल:,
ROL
- बाईं ओर घुमाएं, ऑपरेंड के सभी बिट्स को बाईं ओर एक स्थान पर शिफ्ट करें, कैरी 0 पर जाता है, बिट 7 ले जाने के लिए जाता है- Opcodes: तत्काल:,
60
पूर्ण:,62
अनुक्रमित:64
- झंडे:
Z
,N
,C
- Opcodes: तत्काल:,
ADC
- कैरी के साथ जोड़ें, ऑपरेंड प्लस कैरी को जोड़ा जाता हैA
, कैरी को ओवरफ्लो पर सेट किया जाता है- Opcodes: तत्काल:,
68
पूर्ण:,6a
अनुक्रमित:6c
- झंडे:
Z
,N
,C
- Opcodes: तत्काल:,
INC
- वेतन वृद्धि एक-एक करके- Opcodes: तत्काल:,
78
पूर्ण:,7a
अनुक्रमित:7c
- झंडे:
Z
,N
- Opcodes: तत्काल:,
DEC
- एक के बाद वेतन वृद्धि- Opcodes: तत्काल:,
80
पूर्ण:,82
अनुक्रमित:84
- झंडे:
Z
,N
- Opcodes: तत्काल:,
CMP
-A
से ऑपरेंड घटाकर ऑपरेंड के साथ तुलना करेंA
, परिणाम भूल जाएं। अंडरफ्लो पर कैरी साफ किया जाता है, अन्यथा सेट करें- Opcodes: तत्काल:,
88
पूर्ण:,8a
अनुक्रमित:8c
- झंडे:
Z
,N
,C
- Opcodes: तत्काल:,
CPX
- तुलनाX
- रूप में एक हीCMP
के लिएX
- Opcodes: तत्काल:,
90
पूर्ण:,92
अनुक्रमित:94
- झंडे:
Z
,N
,C
- Opcodes: तत्काल:,
HLT
- समाप्त करें- Opcodes: निहित:
c0
- Opcodes: निहित:
INX
-X
एक से वृद्धि- Opcodes: निहित:
c8
- झंडे:
Z
,N
- Opcodes: निहित:
DEX
-X
एक से घटाव- Opcodes: निहित:
c9
- झंडे:
Z
,N
- Opcodes: निहित:
SEC
- सेट कैरी फ्लैग- Opcodes: निहित:
d0
- झंडे:
C
- Opcodes: निहित:
CLC
- स्पष्ट कैरी फ्लैग- Opcodes: निहित:
d1
- झंडे:
C
- Opcodes: निहित:
BRA
- शाखा हमेशा- Opcodes: रिश्तेदार:
f2
- Opcodes: रिश्तेदार:
BNE
- शाखा अगरZ
झंडा साफ हो गया- Opcodes: रिश्तेदार:
f4
- Opcodes: रिश्तेदार:
BEQ
- शाखा अगरZ
झंडा सेट- Opcodes: रिश्तेदार:
f6
- Opcodes: रिश्तेदार:
BPL
- शाखा अगरN
झंडा साफ हो गया- Opcodes: रिश्तेदार:
f8
- Opcodes: रिश्तेदार:
BMI
- शाखा अगरN
झंडा सेट- Opcodes: रिश्तेदार:
fa
- Opcodes: रिश्तेदार:
BCC
- शाखा अगरC
झंडा साफ हो गया- Opcodes: रिश्तेदार:
fc
- Opcodes: रिश्तेदार:
BCS
- शाखा अगरC
झंडा सेट- Opcodes: रिश्तेदार:
fe
- Opcodes: रिश्तेदार:
opcodes
VM का व्यवहार अपरिभाषित है, यदि कोई भी ओपकोड पाया जाता है जो उपरोक्त सूची से मान्य निर्देश के लिए मैप नहीं करता है।
के अनुसार जोनाथन एलन के अनुरोध , आप कर सकते हैं में दिखाया गया opcodes के बजाय opcodes के अपने स्वयं के सेट का चयन निर्देश अनुभाग। यदि आप ऐसा करते हैं, तो आपको अपने उत्तर में उपयोग किए गए ऑपकोड में एक पूर्ण मानचित्रण जोड़ना होगा ।
मैपिंग जोड़े के साथ एक हेक्स फ़ाइल होनी चाहिए <official opcode> <your opcode>
, जैसे कि यदि आपने दो ओपकोड्स को बदल दिया है:
f4 f5
10 11
Newlines यहाँ कोई फर्क नहीं पड़ता।
परीक्षण के मामले (आधिकारिक ऑपकोड)
// some increments and decrements
pc: 0
ram: 10 10 7a 01 c9 f4 fb
output: 10 20 7a 01 c9 f4 fb
// a 16bit addition
pc: 4
ram: e0 08 2a 02 02 00 6a 02 0a 00 02 01 6a 03 0a 01
output: 0a 0b 2a 02 02 00 6a 02 0a 00 02 01 6a 03 0a 01
// a 16bit multiplication
pc: 4
ram: 5e 01 28 00 10 10 4a 01 5a 00 fc 0d 02 02 d1 6a 21 0a 21 02 03 6a 22 0a 22 52
02 62 03 c9 f8 e6 c0 00 00
output: 00 00 00 00 10 10 4a 01 5a 00 fc 0d 02 02 d1 6a 21 0a 21 02 03 6a 22 0a 22 52
02 62 03 c9 f8 e6 c0 b0 36
मैं बाद में और अधिक टेस्टेसिस जोड़ सकता हूं।
संदर्भ और परीक्षण
स्वयं के प्रयोगों के साथ मदद करने के लिए, यहाँ कुछ (पूरी तरह से गोल्फ नहीं) संदर्भ कार्यान्वयन है - यह ट्रेसिंग जानकारी ( डिसएम्ड किए गए निर्देशों सहित) को आउटपुट कर सकता है stderr
और रनिंग के दौरान ऑपकोड को परिवर्तित कर सकता है।
स्रोत प्राप्त करने के लिए अनुशंसित तरीका:
git clone https://github.com/zirias/gvm --branch challenge --single-branch --recurse-submodules
या चेकआउट शाखा challenge
और git submodule update --init --recursive
मेरे कस्टम बिल्ड सिस्टम को प्राप्त करने के लिए, क्लोनिंग के बाद करें।
GNU मेक के साथ टूल का निर्माण करें (बस टाइप करें make
, या gmake
यदि आपके सिस्टम पर, डिफ़ॉल्ट मेक अप GNU मेक नहीं है)।
उपयोग :gvm [-s startpc] [-h] [-t] [-c convfile] [-d] [-x] <initial_ram
-s startpc
- प्रारंभिक कार्यक्रम काउंटर, के लिए चूक0
-h
- इनपुट हेक्स में है (अन्यथा बाइनरी)-t
- का पता लगाने के लिए निष्पादनstderr
-c convfile
- इसमें दिए गए मैपिंग के अनुसार ऑपकोड को कन्वर्ट करेंconvfile
-d
- डंप परिणामी मेमोरी को बाइनरी डेटा के रूप में-x
- डंप परिणामस्वरूप स्मृति हेक्स के रूप मेंinitial_ram
- प्रारंभिक रैम सामग्री, या तो हेक्स या बाइनरी
ध्यान दें कि रूपांतरण सुविधा उन कार्यक्रमों पर विफल हो जाएगी जो रन करते समय opcodes को संशोधित करते हैं।
अस्वीकरण: ऊपर दिए गए नियम और चश्मा चुनौती के लिए आधिकारिक हैं, इस उपकरण के लिए नहीं। यह विशेष रूप से opcode रूपांतरण सुविधा पर लागू होता है। यदि आपको लगता है कि यहां प्रस्तुत टूल में बग बग ऐनक है, तो कृपया टिप्पणी में रिपोर्ट करें :)
BRA
("शाखा हमेशा") नियंत्रण प्रवाह में एक शाखा का परिचय नहीं देता है, तो क्या इसे नहीं बुलाया जाना चाहिए JMP
?
BRA
बाद में चिप डिजाइन (6502 में ऐसा कोई निर्देश नहीं है) 65C02 और MC 68000 की JMP
तरह मौजूद है। साथ ही मौजूद है। अंतर यह है कि BRA
सापेक्ष पते का JMP
उपयोग करता है और निरपेक्ष पते का उपयोग करता है। इसलिए, मैंने सिर्फ इन डिजाइनों का पालन किया - वास्तव में, यह सब तर्कसंगत नहीं लगता है;)